diff --git a/gui_qt/formwater.cpp b/gui_qt/formwater.cpp index a33acd3..6650379 100644 --- a/gui_qt/formwater.cpp +++ b/gui_qt/formwater.cpp @@ -3,16 +3,15 @@ #include #include -#include #include "../lib_paysages/tools/euclid.h" #include "../lib_paysages/tools/lighting.h" #include "../lib_paysages/renderer.h" #include "../lib_paysages/scenery.h" -#include "../lib_paysages/water.h" +#include "../lib_paysages/water/public.h" #include "tools.h" -static WaterDefinition _definition; +static WaterDefinition* _definition; /**************** Previews ****************/ class PreviewWaterCoverage:public BasePreview @@ -20,8 +19,7 @@ class PreviewWaterCoverage:public BasePreview public: PreviewWaterCoverage(QWidget* parent):BasePreview(parent) { - _renderer = terrainCreatePreviewRenderer(); - _water = waterCreateDefinition(); + _renderer = waterCreatePreviewCoverageRenderer(); _highlight_enabled = true; addOsd(QString("geolocation")); @@ -33,40 +31,11 @@ public: protected: Color getColor(double x, double y) { - double height; - - height = _renderer->terrain->getHeight(_renderer, x, y, 1); - if (height > _definition.height) - { - return terrainGetPreviewColor(_renderer, x, y, scaling); - } - else - { - Vector3 location, look; - Color base; - - location.x = x; - location.y = _water.height; - location.z = y; - - look.x = 0.0; - look.y = -1.0; - look.z = 0.0; - - base = waterGetColor(&_water, _renderer, location, look); - - if (_highlight_enabled) - { - Color mask = {0.5, 0.5, 1.0, 0.5}; - colorMask(&base, &mask); - } - - return base; - } + return waterGetPreviewCoverage(_renderer, x, y, scaling, _highlight_enabled ? 1 : 0); } void updateData() { - waterCopyDefinition(&_definition, &_water); + WaterRendererClass.bind(_renderer, _definition); // TODO Do this only on full refresh TerrainDefinition* terrain = (TerrainDefinition*)TerrainDefinitionClass.create(); @@ -84,7 +53,6 @@ protected: } private: Renderer* _renderer; - WaterDefinition _water; bool _highlight_enabled; }; diff --git a/lib_paysages/Makefile b/lib_paysages/Makefile index 4df0092..0b38be3 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 clouds/*.c terrain/*.c tools/*.c) +SOURCES = $(wildcard *.c atmosphere/*.c clouds/*.c terrain/*.c water/*.c tools/*.c) OBJECTS = ${SOURCES:%.c=${OBJPATH}/%.o} -HEADERS = $(wildcard *.h atmosphere/*.h clouds/*.h terrain/*.h tools/*.h shared/*.h) +HEADERS = $(wildcard *.h atmosphere/*.h clouds/*.h terrain/*.h water/*.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 1d614ed..4c2caac 100644 --- a/lib_paysages/atmosphere/bruneton.c +++ b/lib_paysages/atmosphere/bruneton.c @@ -1169,7 +1169,7 @@ Color brunetonApplyAerialPerspective(Renderer* renderer, Vector3 location, Color Vector3 eye = renderer->getCameraLocation(renderer, location); Vector3 sun_position = v3Scale(renderer->atmosphere->getSunDirection(renderer), SUN_DISTANCE); - double yoffset = GROUND_OFFSET - renderer->getWaterHeightInfo(renderer).base_height; + double yoffset = GROUND_OFFSET - renderer->water->getHeightInfo(renderer).base_height; eye.y += yoffset; location.y += yoffset; if (eye.y < 0.0) @@ -1212,7 +1212,7 @@ void brunetonGetLightingStatus(Renderer* renderer, LightStatus* status, Vector3 double altitude = lightingGetStatusLocation(status).y; - double yoffset = GROUND_OFFSET - renderer->getWaterHeightInfo(renderer).base_height; + double yoffset = GROUND_OFFSET - renderer->water->getHeightInfo(renderer).base_height; altitude += yoffset; if (altitude < 0.0) { diff --git a/lib_paysages/auto.c b/lib_paysages/auto.c index ebaa91b..9eade6e 100644 --- a/lib_paysages/auto.c +++ b/lib_paysages/auto.c @@ -8,7 +8,6 @@ #include "textures.h" #include "scenery.h" #include "system.h" -#include "water.h" #include "zone.h" void autoGenRealisticLandscape(int seed) @@ -26,12 +25,6 @@ void autoGenRealisticLandscape(int seed) sceneryAutoPreset(); - /* Water */ - water = waterCreateDefinition(); - waterAutoPreset(&water, WATER_PRESET_LAKE); - scenerySetWater(&water); - waterDeleteDefinition(&water); - /* Textures */ textures = texturesCreateDefinition(); layer = layersAddLayer(textures.layers, NULL); @@ -87,13 +80,4 @@ void autoGenRealisticLandscape(int seed) texture->thickness_transparency = 0.015;*/ scenerySetTextures(&textures); texturesDeleteDefinition(&textures); - - /* Atmosphere */ - /*atmosphere = atmosphereCreateDefinition(); - atmosphere.distance_near = 20.0; - atmosphere.distance_far = 100.0; - atmosphere.full_mask = 0.6; - atmosphere.auto_lock_on_haze = 1; - scenerySetAtmosphere(&atmosphere); - atmosphereDeleteDefinition(&atmosphere);*/ } diff --git a/lib_paysages/camera.c b/lib_paysages/camera.c index a515577..6d6406c 100644 --- a/lib_paysages/camera.c +++ b/lib_paysages/camera.c @@ -69,13 +69,9 @@ void cameraValidateDefinition(CameraDefinition* definition, int check_above) if (check_above) { - water = waterCreateDefinition(); - sceneryGetWater(&water); - water_height = water.height + 0.5; - waterDeleteDefinition(&water); - renderer = sceneryCreateStandardRenderer(); terrain_height = renderer->terrain->getHeight(renderer, definition->location.x, definition->location.z, 1) + 0.5; + water_height = renderer->water->getHeightInfo(renderer).max_height + 0.5; rendererDelete(renderer); if (definition->location.y < water_height || definition->location.y < terrain_height) diff --git a/lib_paysages/renderer.c b/lib_paysages/renderer.c index c3ea4d2..2079c9b 100644 --- a/lib_paysages/renderer.c +++ b/lib_paysages/renderer.c @@ -7,7 +7,6 @@ #include "tools.h" static RayCastingResult _RAYCASTING_NULL = {0}; -static HeightInfo _WATER_HEIGHT_INFO = {0.0, 0.0, 0.0}; static void* _renderFirstPass(void* data) { @@ -79,11 +78,6 @@ static RayCastingResult _rayWalking(Renderer* renderer, Vector3 location, Vector return _RAYCASTING_NULL; } -static HeightInfo _getWaterHeightInfo(Renderer* renderer) -{ - return _WATER_HEIGHT_INFO; -} - static Color _applyTextures(Renderer* renderer, Vector3 location, double precision) { return COLOR_TRANSPARENT; @@ -131,7 +125,6 @@ Renderer* rendererCreate() result->pushQuad = _pushQuad; result->rayWalking = _rayWalking; - result->getWaterHeightInfo = _getWaterHeightInfo; result->applyTextures = _applyTextures; result->applyLightingToSurface = _applyLightingToSurface; @@ -142,6 +135,7 @@ Renderer* rendererCreate() result->atmosphere = AtmosphereRendererClass.create(); result->clouds = CloudsRendererClass.create(); result->terrain = TerrainRendererClass.create(); + result->water = WaterRendererClass.create(); return result; } @@ -153,6 +147,7 @@ void rendererDelete(Renderer* renderer) AtmosphereRendererClass.destroy(renderer->atmosphere); CloudsRendererClass.destroy(renderer->clouds); TerrainRendererClass.destroy(renderer->terrain); + WaterRendererClass.destroy(renderer->water); renderDeleteArea(renderer->render_area); diff --git a/lib_paysages/renderer.h b/lib_paysages/renderer.h index b523b57..1b05343 100644 --- a/lib_paysages/renderer.h +++ b/lib_paysages/renderer.h @@ -5,6 +5,7 @@ #include "atmosphere/public.h" #include "clouds/public.h" #include "terrain/public.h" +#include "water/public.h" #include "render.h" #ifdef __cplusplus @@ -39,7 +40,6 @@ struct Renderer /* Scenery related */ 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); /* Autonomous tools */ @@ -49,6 +49,7 @@ struct Renderer AtmosphereRenderer* atmosphere; TerrainRenderer* terrain; CloudsRenderer* clouds; + WaterRenderer* water; /* Custom data */ void* customData[10]; diff --git a/lib_paysages/scenery.c b/lib_paysages/scenery.c index 98b965f..68691c7 100644 --- a/lib_paysages/scenery.c +++ b/lib_paysages/scenery.c @@ -10,7 +10,7 @@ static CameraDefinition _camera; static CloudsDefinition* _clouds; static TerrainDefinition* _terrain; static TexturesDefinition _textures; -static WaterDefinition _water; +static WaterDefinition* _water; static SceneryCustomDataCallback _custom_save = NULL; static SceneryCustomDataCallback _custom_load = NULL; @@ -25,7 +25,7 @@ void sceneryInit() _clouds = CloudsDefinitionClass.create(); _terrain = TerrainDefinitionClass.create(); _textures = texturesCreateDefinition(); - _water = waterCreateDefinition(); + _water = WaterDefinitionClass.create(); _custom_save = NULL; _custom_load = NULL; @@ -38,7 +38,7 @@ void sceneryQuit() CloudsDefinitionClass.destroy(_clouds); TerrainDefinitionClass.destroy(_terrain); texturesDeleteDefinition(&_textures); - waterDeleteDefinition(&_water); + AtmosphereDefinitionClass.destroy(_water); noiseQuit(); } @@ -47,6 +47,7 @@ void sceneryAutoPreset() { terrainAutoPreset(_terrain, TERRAIN_PRESET_STANDARD); atmosphereAutoPreset(_atmosphere, ATMOSPHERE_PRESET_CLEAR_DAY); + waterAutoPreset(_water, WATER_PRESET_LAKE); cloudsAutoPreset(_clouds, CLOUDS_PRESET_PARTLY_CLOUDY); } @@ -65,7 +66,7 @@ void scenerySave(PackStream* stream) CloudsDefinitionClass.save(stream, _clouds); TerrainDefinitionClass.save(stream, _terrain); texturesSave(stream, &_textures); - waterSave(stream, &_water); + WaterDefinitionClass.save(stream, _water); if (_custom_save) { @@ -83,11 +84,10 @@ void sceneryLoad(PackStream* stream) CloudsDefinitionClass.load(stream, _clouds); TerrainDefinitionClass.load(stream, _terrain); texturesLoad(stream, &_textures); - waterLoad(stream, &_water); + WaterDefinitionClass.load(stream, _water); cameraValidateDefinition(&_camera, 0); texturesValidateDefinition(&_textures); - waterValidateDefinition(&_water); if (_custom_load) { @@ -151,21 +151,20 @@ void sceneryGetTextures(TexturesDefinition* textures) void scenerySetWater(WaterDefinition* water) { - waterCopyDefinition(water, &_water); - waterValidateDefinition(&_water); + WaterDefinitionClass.copy(water, _water); cameraValidateDefinition(&_camera, 1); } void sceneryGetWater(WaterDefinition* water) { - waterCopyDefinition(&_water, water); + WaterDefinitionClass.copy(_water, water); } void sceneryRenderFirstPass(Renderer* renderer) { terrainRenderSurface(renderer); - waterRender(&_water, renderer); + waterRenderSurface(renderer); atmosphereRenderSkydome(renderer); } @@ -193,11 +192,6 @@ static RayCastingResult _rayWalking(Renderer* renderer, Vector3 location, Vector return result; } -static HeightInfo _getWaterHeightInfo(Renderer* renderer) -{ - return waterGetHeightInfo(&_water); -} - static Color _applyTextures(Renderer* renderer, Vector3 location, double precision) { return texturesGetColor(&_textures, renderer, location.x, location.z, precision); @@ -233,7 +227,6 @@ Renderer* sceneryCreateStandardRenderer() cameraCopyDefinition(&_camera, &result->render_camera); result->rayWalking = _rayWalking; - result->getWaterHeightInfo = _getWaterHeightInfo; result->applyTextures = _applyTextures; result->projectPoint = _projectPoint; result->unprojectPoint = _unprojectPoint; @@ -242,6 +235,7 @@ Renderer* sceneryCreateStandardRenderer() AtmosphereRendererClass.bind(result, _atmosphere); TerrainRendererClass.bind(result, _terrain); CloudsRendererClass.bind(result, _clouds); + WaterRendererClass.bind(result, _water); return result; } diff --git a/lib_paysages/scenery.h b/lib_paysages/scenery.h index e8611bc..71ccc90 100644 --- a/lib_paysages/scenery.h +++ b/lib_paysages/scenery.h @@ -12,9 +12,9 @@ #include "atmosphere/public.h" #include "clouds/public.h" #include "terrain/public.h" +#include "water/public.h" #include "camera.h" #include "textures.h" -#include "water.h" #include "renderer.h" #ifdef __cplusplus diff --git a/lib_paysages/terrain/raster.c b/lib_paysages/terrain/raster.c index f91b103..9ce2972 100644 --- a/lib_paysages/terrain/raster.c +++ b/lib_paysages/terrain/raster.c @@ -69,7 +69,7 @@ void terrainRenderSurface(Renderer* renderer) radius_ext = min_chunk_size; chunk_size = min_chunk_size; - water_height = renderer->getWaterHeightInfo(renderer).max_height; + water_height = renderer->water->getHeightInfo(renderer).max_height; while (radius_int < 5000.0) { diff --git a/lib_paysages/water.c b/lib_paysages/water.c deleted file mode 100644 index 788ae54..0000000 --- a/lib_paysages/water.c +++ /dev/null @@ -1,446 +0,0 @@ -#include "water.h" - -#include "shared/types.h" -#include "render.h" -#include "tools.h" - -#include - -void waterSave(PackStream* stream, WaterDefinition* definition) -{ - packWriteDouble(stream, &definition->height); - materialSave(stream, &definition->material); - colorSave(stream, &definition->depth_color); - packWriteDouble(stream, &definition->transparency_depth); - packWriteDouble(stream, &definition->transparency); - packWriteDouble(stream, &definition->reflection); - packWriteDouble(stream, &definition->lighting_depth); - - packWriteDouble(stream, &definition->scaling); - packWriteDouble(stream, &definition->waves_height); - packWriteDouble(stream, &definition->detail_height); - packWriteDouble(stream, &definition->turbulence); - - packWriteDouble(stream, &definition->foam_coverage); - materialSave(stream, &definition->foam_material); - - noiseSaveGenerator(stream, definition->_waves_noise); -} - -void waterLoad(PackStream* stream, WaterDefinition* definition) -{ - packReadDouble(stream, &definition->height); - materialLoad(stream, &definition->material); - colorLoad(stream, &definition->depth_color); - packReadDouble(stream, &definition->transparency_depth); - packReadDouble(stream, &definition->transparency); - packReadDouble(stream, &definition->reflection); - packReadDouble(stream, &definition->lighting_depth); - - packReadDouble(stream, &definition->scaling); - packReadDouble(stream, &definition->waves_height); - packReadDouble(stream, &definition->detail_height); - packReadDouble(stream, &definition->turbulence); - - packReadDouble(stream, &definition->foam_coverage); - materialLoad(stream, &definition->foam_material); - - noiseLoadGenerator(stream, definition->_waves_noise); - - waterValidateDefinition(definition); -} - -WaterDefinition waterCreateDefinition() -{ - WaterDefinition result; - - result.height = -4.0; - result._waves_noise = noiseCreateGenerator(); - - waterAutoPreset(&result, WATER_PRESET_LAKE); - - return result; -} - -void waterDeleteDefinition(WaterDefinition* definition) -{ - noiseDeleteGenerator(definition->_waves_noise); -} - -void waterAutoPreset(WaterDefinition* definition, WaterPreset preset) -{ - noiseRandomizeOffsets(definition->_waves_noise); - - if (preset == WATER_PRESET_LAKE) - { - definition->transparency = 0.5; - definition->reflection = 0.4; - definition->transparency_depth = 4.0; - definition->material.base.r = 0.08; - definition->material.base.g = 0.15; - definition->material.base.b = 0.2; - definition->depth_color.r = 0.0; - definition->depth_color.g = 0.1; - definition->depth_color.b = 0.1; - definition->lighting_depth = 6.0; - definition->scaling = 1.0; - definition->waves_height = 0.8; - definition->detail_height = 0.05; - definition->turbulence = 0.1; - definition->foam_coverage = 0.15; - } - else if (preset == WATER_PRESET_SEA) - { - definition->transparency = 0.4; - definition->reflection = 0.35; - definition->transparency_depth = 3.0; - definition->material.base.r = 0.05; - definition->material.base.g = 0.18; - definition->material.base.b = 0.2; - definition->depth_color.r = 0.0; - definition->depth_color.g = 0.18; - definition->depth_color.b = 0.15; - definition->lighting_depth = 4.0; - definition->scaling = 1.5; - definition->waves_height = 1.0; - definition->detail_height = 0.06; - definition->turbulence = 0.3; - definition->foam_coverage = 0.4; - } - - definition->depth_color.a = 1.0; - definition->material.base.a = 1.0; - definition->material.reflection = 1.0; - definition->material.shininess = 16.0; - definition->foam_material.base.r = 0.8; - definition->foam_material.base.g = 0.8; - definition->foam_material.base.b = 0.8; - definition->foam_material.base.a = 1.0; - definition->foam_material.reflection = 0.4; - definition->foam_material.shininess = 1.5; - - waterValidateDefinition(definition); -} - -void waterCopyDefinition(WaterDefinition* source, WaterDefinition* destination) -{ - NoiseGenerator* noise; - - noise = destination->_waves_noise; - *destination = *source; - destination->_waves_noise = noise; - noiseCopy(source->_waves_noise, destination->_waves_noise); -} - -void waterValidateDefinition(WaterDefinition* definition) -{ - double scaling = definition->scaling * 0.3; - noiseClearLevels(definition->_waves_noise); - if (definition->waves_height > 0.0) - { - noiseAddLevelsSimple(definition->_waves_noise, 2, scaling, -definition->waves_height * scaling * 0.015, definition->waves_height * scaling * 0.015, 0.5); - } - if (definition->detail_height > 0.0) - { - noiseAddLevelsSimple(definition->_waves_noise, 3, scaling * 0.1, -definition->detail_height * scaling * 0.015, definition->detail_height * scaling * 0.015, 0.5); - } - noiseSetFunctionParams(definition->_waves_noise, NOISE_FUNCTION_SIMPLEX, -definition->turbulence, 0.0); - noiseValidate(definition->_waves_noise); -} - -static inline double _getHeight(WaterDefinition* definition, double x, double z) -{ - return definition->height + noiseGet2DTotal(definition->_waves_noise, x, z); -} - -static inline Vector3 _getNormal(WaterDefinition* definition, Vector3 base, double detail) -{ - Vector3 back, right; - double x, z; - - x = base.x; - z = base.z; - - back.x = x; - back.y = _getHeight(definition, x, z + detail); - back.z = z + detail; - back = v3Sub(back, base); - - right.x = x + detail; - right.y = _getHeight(definition, x + detail, z); - right.z = z; - right = v3Sub(right, base); - - return v3Normalize(v3Cross(back, right)); -} - -static inline Vector3 _reflectRay(Vector3 incoming, Vector3 normal) -{ - double c; - - c = v3Dot(normal, v3Scale(incoming, -1.0)); - return v3Add(incoming, v3Scale(normal, 2.0 * c)); -} - -static inline Vector3 _refractRay(Vector3 incoming, Vector3 normal) -{ - double c1, c2, f; - - f = 1.0 / 1.33; - c1 = v3Dot(normal, v3Scale(incoming, -1.0)); - c2 = sqrt(1.0 - pow(f, 2.0) * (1.0 - pow(c1, 2.0))); - if (c1 >= 0.0) - { - return v3Add(v3Scale(incoming, f), v3Scale(normal, f * c1 - c2)); - } - else - { - return v3Add(v3Scale(incoming, f), v3Scale(normal, c2 - f * c1)); - } -} - -HeightInfo waterGetHeightInfo(WaterDefinition* definition) -{ - HeightInfo info; - double noise_minvalue, noise_maxvalue; - - info.base_height = definition->height; - noiseGetRange(definition->_waves_noise, &noise_minvalue, &noise_maxvalue); - info.min_height = definition->height + noise_minvalue; - info.max_height = definition->height + noise_maxvalue; - - return info; -} - -Color waterLightFilter(WaterDefinition* definition, Renderer* renderer, Color light, Vector3 location, Vector3 light_location, Vector3 direction_to_light) -{ - double factor; - - UNUSED(renderer); - UNUSED(light_location); - - if (location.y < definition->height) - { - if (direction_to_light.y > 0.00001) - { - factor = (definition->height - location.y) / (direction_to_light.y * definition->lighting_depth); - if (factor > 1.0) - { - factor = 1.0; - } - factor = 1.0 - 0.8 * factor; - - light.r *= factor; - light.g *= factor; - light.b *= factor; - - return light; - } - else - { - return COLOR_BLACK; - } - } - else - { - return light; - } -} - -static inline void _applyFoam(WaterDefinition* definition, Vector3 location, Vector3 normal, double detail, SurfaceMaterial* material) -{ - Color result = definition->foam_material.base; - double foam_factor, normal_diff, location_offset; - - location_offset = 2.0 * detail; - - foam_factor = 0.0; - location.x += location_offset; - normal_diff = 1.0 - v3Dot(normal, _getNormal(definition, location, detail)); - if (normal_diff > foam_factor) - { - foam_factor = normal_diff; - } - location.x -= location_offset * 2.0; - normal_diff = 1.0 - v3Dot(normal, _getNormal(definition, location, detail)); - if (normal_diff > foam_factor) - { - foam_factor = normal_diff; - } - location.x += location_offset; - location.z -= location_offset; - normal_diff = 1.0 - v3Dot(normal, _getNormal(definition, location, detail)); - if (normal_diff > foam_factor) - { - foam_factor = normal_diff; - } - location.z += location_offset * 2.0; - normal_diff = 1.0 - v3Dot(normal, _getNormal(definition, location, detail)); - if (normal_diff > foam_factor) - { - foam_factor = normal_diff; - } - - foam_factor *= 10.0; - if (foam_factor > 1.0) - { - foam_factor = 1.0; - } - - if (foam_factor <= 1.0 - definition->foam_coverage) - { - return; - } - foam_factor = (foam_factor - (1.0 - definition->foam_coverage)) * definition->foam_coverage; - - material->reflection = foam_factor * definition->foam_material.reflection + (1.0 - foam_factor) * material->reflection; - material->shininess = foam_factor * definition->foam_material.shininess + (1.0 - foam_factor) * material->shininess; - - /* TODO This should be configurable */ - if (foam_factor > 0.2) - { - result.a = 0.8; - } - else - { - result.a = 0.8 * (foam_factor / 0.2); - } - colorMask(&material->base, &result); -} - -WaterResult waterGetColorDetail(WaterDefinition* definition, Renderer* renderer, Vector3 location, Vector3 look) -{ - WaterResult result; - RayCastingResult refracted; - Vector3 normal; - Color color; - SurfaceMaterial material; - double detail, depth; - - detail = renderer->getPrecision(renderer, location) * 0.1; - if (detail < 0.00001) - { - detail = 0.00001; - } - - location.y = _getHeight(definition, location.x, location.z); - result.location = location; - - normal = _getNormal(definition, location, detail); - look = v3Normalize(look); - result.reflected = renderer->rayWalking(renderer, location, _reflectRay(look, normal), 1, 0, 1, 1).hit_color; - refracted = renderer->rayWalking(renderer, location, _refractRay(look, normal), 1, 0, 1, 1); - depth = v3Norm(v3Sub(location, refracted.hit_location)); - if (depth > definition->transparency_depth) - { - result.refracted = definition->depth_color; - } - else - { - depth /= definition->transparency_depth; - result.refracted.r = refracted.hit_color.r * (1.0 - depth) + definition->depth_color.r * depth; - result.refracted.g = refracted.hit_color.g * (1.0 - depth) + definition->depth_color.g * depth; - result.refracted.b = refracted.hit_color.b * (1.0 - depth) + definition->depth_color.b * depth; - result.refracted.a = 1.0; - } - - color.r = definition->material.base.r * (1.0 - definition->transparency) + result.reflected.r * definition->reflection + result.refracted.r * definition->transparency; - color.g = definition->material.base.g * (1.0 - definition->transparency) + result.reflected.g * definition->reflection + result.refracted.g * definition->transparency; - color.b = definition->material.base.b * (1.0 - definition->transparency) + result.reflected.b * definition->reflection + result.refracted.b * definition->transparency; - color.a = 1.0; - - material = definition->material; - material.base = color; - - _applyFoam(definition, location, normal, detail, &material); - - color = renderer->applyLightingToSurface(renderer, location, normal, &material); - color = renderer->applyMediumTraversal(renderer, location, color); - - result.base = definition->material.base; - result.final = color; - - return result; -} - -Color waterGetColor(WaterDefinition* definition, Renderer* renderer, Vector3 location, Vector3 look) -{ - return waterGetColorDetail(definition, renderer, location, look).final; -} - -static Color _postProcessFragment(Renderer* renderer, Vector3 location, void* data) -{ - return waterGetColor((WaterDefinition*)data, renderer, location, v3Sub(location, renderer->getCameraLocation(renderer, location))); -} - -static Vector3 _getFirstPassVertex(WaterDefinition* definition, double x, double z, double precision) -{ - Vector3 result; - - UNUSED(precision); - result.x = x; - result.y = _getHeight(definition, x, z); - result.z = z; - - return result; -} - -static void _renderQuad(WaterDefinition* definition, Renderer* renderer, double x, double z, double size) -{ - Vector3 v1, v2, v3, v4; - - v1 = _getFirstPassVertex(definition, x, z, size); - v2 = _getFirstPassVertex(definition, x, z + size, size); - v3 = _getFirstPassVertex(definition, x + size, z + size, size); - v4 = _getFirstPassVertex(definition, x + size, z, size); - - renderer->pushQuad(renderer, v1, v2, v3, v4, _postProcessFragment, definition); -} - -void waterRender(WaterDefinition* definition, Renderer* renderer) -{ - int chunk_factor, chunk_count, i; - Vector3 cam = renderer->getCameraLocation(renderer, VECTOR_ZERO); - double cx = cam.x; - double cz = cam.z; - double radius_int, radius_ext, base_chunk_size, chunk_size; - - base_chunk_size = 2.0 / (double)renderer->render_quality; - if (renderer->render_quality > 7) - { - base_chunk_size *= 0.5; - } - - chunk_factor = 1; - chunk_count = 2; - radius_int = 0.0; - radius_ext = base_chunk_size; - chunk_size = base_chunk_size; - - while (radius_int < 5000.0) - { - if (!renderer->addRenderProgress(renderer, 0.0)) - { - return; - } - - for (i = 0; i < chunk_count - 1; i++) - { - _renderQuad(definition, renderer, cx - radius_ext + chunk_size * i, cz - radius_ext, chunk_size); - _renderQuad(definition, renderer, cx + radius_int, cz - radius_ext + chunk_size * i, chunk_size); - _renderQuad(definition, renderer, cx + radius_int - chunk_size * i, cz + radius_int, chunk_size); - _renderQuad(definition, renderer, cx - radius_ext, cz + radius_int - chunk_size * i, chunk_size); - } - - if (radius_int > 20.0 && chunk_count % 64 == 0 && (double)chunk_factor < radius_int / 20.0) - { - chunk_count /= 2; - chunk_factor *= 2; - } - chunk_count += 2; - chunk_size = base_chunk_size * chunk_factor; - radius_int = radius_ext; - radius_ext += chunk_size; - } -} - diff --git a/lib_paysages/water.h b/lib_paysages/water.h deleted file mode 100644 index 45d2d8b..0000000 --- a/lib_paysages/water.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef _PAYSAGES_WATER_H_ -#define _PAYSAGES_WATER_H_ - -#include "tools/color.h" -#include "tools/euclid.h" -#include "tools/lighting.h" -#include "tools/pack.h" -#include "renderer.h" -#include "noise.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum -{ - WATER_PRESET_LAKE, - WATER_PRESET_SEA -} WaterPreset; - -typedef struct -{ - double height; - double transparency; - double reflection; - SurfaceMaterial material; - Color depth_color; - double transparency_depth; - double lighting_depth; - - double scaling; - double turbulence; - double waves_height; - double detail_height; - - double foam_coverage; - SurfaceMaterial foam_material; - - NoiseGenerator* _waves_noise; -} WaterDefinition; - -typedef struct -{ - Vector3 location; - Color base; - Color reflected; - Color refracted; - Color foam; - Color final; -} WaterResult; - -void waterSave(PackStream* stream, WaterDefinition* definition); -void waterLoad(PackStream* stream, WaterDefinition* definition); - -WaterDefinition waterCreateDefinition(); -void waterDeleteDefinition(WaterDefinition* definition); -void waterAutoPreset(WaterDefinition* definition, WaterPreset preset); -void waterCopyDefinition(WaterDefinition* source, WaterDefinition* destination); -void waterValidateDefinition(WaterDefinition* definition); - -HeightInfo waterGetHeightInfo(WaterDefinition* definition); -Color waterLightFilter(WaterDefinition* definition, Renderer* renderer, Color light, Vector3 location, Vector3 light_location, Vector3 direction_to_light); -WaterResult waterGetColorDetail(WaterDefinition* definition, Renderer* renderer, Vector3 location, Vector3 look); -Color waterGetColor(WaterDefinition* definition, Renderer* renderer, Vector3 location, Vector3 look); -void waterRender(WaterDefinition* definition, Renderer* renderer); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib_paysages/water/definition.c b/lib_paysages/water/definition.c new file mode 100644 index 0000000..b93e3fd --- /dev/null +++ b/lib_paysages/water/definition.c @@ -0,0 +1,100 @@ +#include "private.h" + +#include + +static void _validateDefinition(WaterDefinition* definition) +{ + double scaling = definition->scaling * 0.3; + noiseClearLevels(definition->_waves_noise); + if (definition->waves_height > 0.0) + { + noiseAddLevelsSimple(definition->_waves_noise, 2, scaling, -definition->waves_height * scaling * 0.015, definition->waves_height * scaling * 0.015, 0.5); + } + if (definition->detail_height > 0.0) + { + noiseAddLevelsSimple(definition->_waves_noise, 3, scaling * 0.1, -definition->detail_height * scaling * 0.015, definition->detail_height * scaling * 0.015, 0.5); + } + noiseSetFunctionParams(definition->_waves_noise, NOISE_FUNCTION_SIMPLEX, -definition->turbulence, 0.0); + noiseValidate(definition->_waves_noise); +} + +static WaterDefinition* _createDefinition() +{ + WaterDefinition* definition = malloc(sizeof(WaterDefinition)); + + definition->height = -4.0; + definition->_waves_noise = noiseCreateGenerator(); + + waterAutoPreset(definition, WATER_PRESET_LAKE); + + return definition; +} + +static void _deleteDefinition(WaterDefinition* definition) +{ + noiseDeleteGenerator(definition->_waves_noise); + free(definition); +} + +static void _copyDefinition(WaterDefinition* source, WaterDefinition* destination) +{ + NoiseGenerator* noise; + + noise = destination->_waves_noise; + *destination = *source; + destination->_waves_noise = noise; + noiseCopy(source->_waves_noise, destination->_waves_noise); +} + +static void _saveDefinition(PackStream* stream, WaterDefinition* definition) +{ + packWriteDouble(stream, &definition->height); + materialSave(stream, &definition->material); + colorSave(stream, &definition->depth_color); + packWriteDouble(stream, &definition->transparency_depth); + packWriteDouble(stream, &definition->transparency); + packWriteDouble(stream, &definition->reflection); + packWriteDouble(stream, &definition->lighting_depth); + + packWriteDouble(stream, &definition->scaling); + packWriteDouble(stream, &definition->waves_height); + packWriteDouble(stream, &definition->detail_height); + packWriteDouble(stream, &definition->turbulence); + + packWriteDouble(stream, &definition->foam_coverage); + materialSave(stream, &definition->foam_material); + + noiseSaveGenerator(stream, definition->_waves_noise); +} + +static void _loadDefinition(PackStream* stream, WaterDefinition* definition) +{ + packReadDouble(stream, &definition->height); + materialLoad(stream, &definition->material); + colorLoad(stream, &definition->depth_color); + packReadDouble(stream, &definition->transparency_depth); + packReadDouble(stream, &definition->transparency); + packReadDouble(stream, &definition->reflection); + packReadDouble(stream, &definition->lighting_depth); + + packReadDouble(stream, &definition->scaling); + packReadDouble(stream, &definition->waves_height); + packReadDouble(stream, &definition->detail_height); + packReadDouble(stream, &definition->turbulence); + + packReadDouble(stream, &definition->foam_coverage); + materialLoad(stream, &definition->foam_material); + + noiseLoadGenerator(stream, definition->_waves_noise); + + _validateDefinition(definition); +} + +StandardDefinition WaterDefinitionClass = { + (FuncObjectCreate)_createDefinition, + (FuncObjectDelete)_deleteDefinition, + (FuncObjectCopy)_copyDefinition, + (FuncObjectValidate)_validateDefinition, + (FuncObjectSave)_saveDefinition, + (FuncObjectLoad)_loadDefinition +}; diff --git a/lib_paysages/water/presets.c b/lib_paysages/water/presets.c new file mode 100644 index 0000000..0f2445b --- /dev/null +++ b/lib_paysages/water/presets.c @@ -0,0 +1,56 @@ +#include "private.h" + +void waterAutoPreset(WaterDefinition* definition, WaterPreset preset) +{ + noiseRandomizeOffsets(definition->_waves_noise); + + if (preset == WATER_PRESET_LAKE) + { + definition->transparency = 0.5; + definition->reflection = 0.4; + definition->transparency_depth = 4.0; + definition->material.base.r = 0.08; + definition->material.base.g = 0.15; + definition->material.base.b = 0.2; + definition->depth_color.r = 0.0; + definition->depth_color.g = 0.1; + definition->depth_color.b = 0.1; + definition->lighting_depth = 6.0; + definition->scaling = 1.0; + definition->waves_height = 0.8; + definition->detail_height = 0.05; + definition->turbulence = 0.1; + definition->foam_coverage = 0.15; + } + else if (preset == WATER_PRESET_SEA) + { + definition->transparency = 0.4; + definition->reflection = 0.35; + definition->transparency_depth = 3.0; + definition->material.base.r = 0.05; + definition->material.base.g = 0.18; + definition->material.base.b = 0.2; + definition->depth_color.r = 0.0; + definition->depth_color.g = 0.18; + definition->depth_color.b = 0.15; + definition->lighting_depth = 4.0; + definition->scaling = 1.5; + definition->waves_height = 1.0; + definition->detail_height = 0.06; + definition->turbulence = 0.3; + definition->foam_coverage = 0.4; + } + + definition->depth_color.a = 1.0; + definition->material.base.a = 1.0; + definition->material.reflection = 1.0; + definition->material.shininess = 16.0; + definition->foam_material.base.r = 0.8; + definition->foam_material.base.g = 0.8; + definition->foam_material.base.b = 0.8; + definition->foam_material.base.a = 1.0; + definition->foam_material.reflection = 0.4; + definition->foam_material.shininess = 1.5; + + WaterDefinitionClass.validate(definition); +} diff --git a/lib_paysages/water/preview.c b/lib_paysages/water/preview.c new file mode 100644 index 0000000..af7a160 --- /dev/null +++ b/lib_paysages/water/preview.c @@ -0,0 +1,44 @@ +#include "private.h" + +#include "../terrain/public.h" +#include "../renderer.h" +#include "../tools.h" + +Renderer* waterCreatePreviewCoverageRenderer() +{ + return terrainCreatePreviewRenderer(); +} + +Color waterGetPreviewCoverage(Renderer* renderer, double x, double y, double scaling, int highlight_enabled) +{ + double height; + + height = renderer->terrain->getHeight(renderer, x, y, 1); + if (height > renderer->water->definition.height) + { + return terrainGetPreviewColor(renderer, x, y, scaling); + } + else + { + Color base; + + base = renderer->water->getResult(renderer, x, y).final; + + if (highlight_enabled) + { + Color mask = {0.5, 0.5, 1.0, 0.5}; + colorMask(&base, &mask); + } + + return base; + } +} + +Renderer* waterCreatePreviewColorRenderer() +{ +} + +Color waterGetPreviewColor(Renderer* renderer, double x, double y, double scaling) +{ + +} diff --git a/lib_paysages/water/private.h b/lib_paysages/water/private.h new file mode 100644 index 0000000..624f459 --- /dev/null +++ b/lib_paysages/water/private.h @@ -0,0 +1,7 @@ +#ifndef _PAYSAGES_WATER_PRIVATE_H_ +#define _PAYSAGES_WATER_PRIVATE_H_ + +#include "public.h" + + +#endif diff --git a/lib_paysages/water/public.h b/lib_paysages/water/public.h new file mode 100644 index 0000000..87a6642 --- /dev/null +++ b/lib_paysages/water/public.h @@ -0,0 +1,82 @@ +#ifndef _PAYSAGES_WATER_PUBLIC_H_ +#define _PAYSAGES_WATER_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 +{ + WATER_PRESET_LAKE, + WATER_PRESET_SEA +} WaterPreset; + +typedef struct +{ + double height; + double transparency; + double reflection; + SurfaceMaterial material; + Color depth_color; + double transparency_depth; + double lighting_depth; + + double scaling; + double turbulence; + double waves_height; + double detail_height; + + double foam_coverage; + SurfaceMaterial foam_material; + + NoiseGenerator* _waves_noise; +} WaterDefinition; + +typedef struct +{ + Vector3 location; + Color base; + Color reflected; + Color refracted; + Color foam; + Color final; +} WaterResult; + +typedef HeightInfo (*FuncWaterGetHeightInfo)(Renderer* renderer); +typedef double (*FuncWaterGetHeight)(Renderer* renderer, double x, double z); +typedef WaterResult (*FuncWaterGetResult)(Renderer* renderer, double x, double z); + +typedef struct +{ + WaterDefinition* definition; + + FuncWaterGetHeightInfo getHeightInfo; + FuncWaterGetHeight getHeight; + FuncWaterGetResult getResult; +} WaterRenderer; + + +extern StandardDefinition WaterDefinitionClass; +extern StandardRenderer WaterRendererClass; + +void waterRenderSurface(Renderer* renderer); +void waterAutoPreset(WaterDefinition* definition, WaterPreset preset); + +Renderer* waterCreatePreviewCoverageRenderer(); +Color waterGetPreviewCoverage(Renderer* renderer, double x, double y, double scaling, int highlight_enabled); + +Renderer* waterCreatePreviewColorRenderer(); +Color waterGetPreviewColor(Renderer* renderer, double x, double y, double scaling); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_paysages/water/raster.c b/lib_paysages/water/raster.c new file mode 100644 index 0000000..15c9d37 --- /dev/null +++ b/lib_paysages/water/raster.c @@ -0,0 +1,82 @@ +#include "public.h" +#include "private.h" + +#include +#include "../renderer.h" +#include "../tools.h" + +static Color _postProcessFragment(Renderer* renderer, Vector3 location, void* data) +{ + UNUSED(data); + return renderer->water->getResult(renderer, location.x, location.z).final; +} + +static Vector3 _getFirstPassVertex(Renderer* renderer, double x, double z) +{ + Vector3 result; + + result.x = x; + result.y = renderer->water->getHeight(renderer, x, z); + result.z = z; + + return result; +} + +static void _renderQuad(Renderer* renderer, double x, double z, double size) +{ + Vector3 v1, v2, v3, v4; + + v1 = _getFirstPassVertex(renderer, x, z); + v2 = _getFirstPassVertex(renderer, x, z + size); + v3 = _getFirstPassVertex(renderer, x + size, z + size); + v4 = _getFirstPassVertex(renderer, x + size, z); + + renderer->pushQuad(renderer, v1, v2, v3, v4, _postProcessFragment, NULL); +} + +void waterRenderSurface(Renderer* renderer) +{ + int chunk_factor, chunk_count, i; + Vector3 cam = renderer->getCameraLocation(renderer, VECTOR_ZERO); + double cx = cam.x; + double cz = cam.z; + double radius_int, radius_ext, base_chunk_size, chunk_size; + + base_chunk_size = 2.0 / (double)renderer->render_quality; + if (renderer->render_quality > 7) + { + base_chunk_size *= 0.5; + } + + chunk_factor = 1; + chunk_count = 2; + radius_int = 0.0; + radius_ext = base_chunk_size; + chunk_size = base_chunk_size; + + while (radius_int < 5000.0) + { + if (!renderer->addRenderProgress(renderer, 0.0)) + { + return; + } + + for (i = 0; i < chunk_count - 1; i++) + { + _renderQuad(renderer, cx - radius_ext + chunk_size * i, cz - radius_ext, chunk_size); + _renderQuad(renderer, cx + radius_int, cz - radius_ext + chunk_size * i, chunk_size); + _renderQuad(renderer, cx + radius_int - chunk_size * i, cz + radius_int, chunk_size); + _renderQuad(renderer, cx - radius_ext, cz + radius_int - chunk_size * i, chunk_size); + } + + if (radius_int > 20.0 && chunk_count % 64 == 0 && (double)chunk_factor < radius_int / 20.0) + { + chunk_count /= 2; + chunk_factor *= 2; + } + chunk_count += 2; + chunk_size = base_chunk_size * chunk_factor; + radius_int = radius_ext; + radius_ext += chunk_size; + } +} diff --git a/lib_paysages/water/render.c b/lib_paysages/water/render.c new file mode 100644 index 0000000..54f4e49 --- /dev/null +++ b/lib_paysages/water/render.c @@ -0,0 +1,304 @@ +#include "private.h" + +#include +#include +#include "../tools.h" +#include "../renderer.h" + +static HeightInfo _FAKE_HEIGHT_INFO = {0.0, 0.0, 0.0}; +static WaterResult _FAKE_RESULT = {}; + +/******************** Fake ********************/ +static HeightInfo _fakeGetHeightInfo(Renderer* renderer) +{ + UNUSED(renderer); + return _FAKE_HEIGHT_INFO; +} + +static double _fakeGetHeight(Renderer* renderer, double x, double z) +{ + UNUSED(renderer); + UNUSED(x); + UNUSED(z); + return 0.0; +} + +static WaterResult _fakeGetResult(Renderer* renderer, double x, double z) +{ + WaterResult result; + + result.location.x = x; + result.location.y = 0.0; + result.location.z = z; + + result.base = COLOR_BLUE; + result.reflected = COLOR_BLACK; + result.refracted = COLOR_BLACK; + result.foam = COLOR_BLACK; + result.final = COLOR_BLUE; + + return result; +} + +/******************** Helpers ********************/ +static inline double _getHeight(WaterDefinition* definition, double x, double z) +{ + return definition->height + noiseGet2DTotal(definition->_waves_noise, x, z); +} + +static inline Vector3 _getNormal(WaterDefinition* definition, Vector3 base, double detail) +{ + Vector3 back, right; + double x, z; + + x = base.x; + z = base.z; + + back.x = x; + back.y = _getHeight(definition, x, z + detail); + back.z = z + detail; + back = v3Sub(back, base); + + right.x = x + detail; + right.y = _getHeight(definition, x + detail, z); + right.z = z; + right = v3Sub(right, base); + + return v3Normalize(v3Cross(back, right)); +} + +static inline Vector3 _reflectRay(Vector3 incoming, Vector3 normal) +{ + double c; + + c = v3Dot(normal, v3Scale(incoming, -1.0)); + return v3Add(incoming, v3Scale(normal, 2.0 * c)); +} + +static inline Vector3 _refractRay(Vector3 incoming, Vector3 normal) +{ + double c1, c2, f; + + f = 1.0 / 1.33; + c1 = v3Dot(normal, v3Scale(incoming, -1.0)); + c2 = sqrt(1.0 - pow(f, 2.0) * (1.0 - pow(c1, 2.0))); + if (c1 >= 0.0) + { + return v3Add(v3Scale(incoming, f), v3Scale(normal, f * c1 - c2)); + } + else + { + return v3Add(v3Scale(incoming, f), v3Scale(normal, c2 - f * c1)); + } +} + +static inline void _applyFoam(WaterDefinition* definition, Vector3 location, Vector3 normal, double detail, SurfaceMaterial* material) +{ + Color result = definition->foam_material.base; + double foam_factor, normal_diff, location_offset; + + location_offset = 2.0 * detail; + + foam_factor = 0.0; + location.x += location_offset; + normal_diff = 1.0 - v3Dot(normal, _getNormal(definition, location, detail)); + if (normal_diff > foam_factor) + { + foam_factor = normal_diff; + } + location.x -= location_offset * 2.0; + normal_diff = 1.0 - v3Dot(normal, _getNormal(definition, location, detail)); + if (normal_diff > foam_factor) + { + foam_factor = normal_diff; + } + location.x += location_offset; + location.z -= location_offset; + normal_diff = 1.0 - v3Dot(normal, _getNormal(definition, location, detail)); + if (normal_diff > foam_factor) + { + foam_factor = normal_diff; + } + location.z += location_offset * 2.0; + normal_diff = 1.0 - v3Dot(normal, _getNormal(definition, location, detail)); + if (normal_diff > foam_factor) + { + foam_factor = normal_diff; + } + + foam_factor *= 10.0; + if (foam_factor > 1.0) + { + foam_factor = 1.0; + } + + if (foam_factor <= 1.0 - definition->foam_coverage) + { + return; + } + foam_factor = (foam_factor - (1.0 - definition->foam_coverage)) * definition->foam_coverage; + + material->reflection = foam_factor * definition->foam_material.reflection + (1.0 - foam_factor) * material->reflection; + material->shininess = foam_factor * definition->foam_material.shininess + (1.0 - foam_factor) * material->shininess; + + /* TODO This should be configurable */ + if (foam_factor > 0.2) + { + result.a = 0.8; + } + else + { + result.a = 0.8 * (foam_factor / 0.2); + } + colorMask(&material->base, &result); +} + +static int _alterLight(Renderer* renderer, LightDefinition* light, Vector3 at) +{ + WaterDefinition* definition = renderer->water->definition; + double factor; + + if (at.y < definition->height) + { + if (light->direction.y < 0.00001) + { + factor = (definition->height - at.y) / (-light->direction.y * definition->lighting_depth); + if (factor > 1.0) + { + factor = 1.0; + } + factor = 1.0 - 0.8 * factor; + + light->color.r *= factor; + light->color.g *= factor; + light->color.b *= factor; + + return 1; + } + else + { + light->color = COLOR_BLACK; + return 1; + } + } + else + { + return 0; + } +} + +/******************** Real ********************/ +static HeightInfo _realGetHeightInfo(Renderer* renderer) +{ + WaterDefinition* definition = renderer->water->definition; + HeightInfo info; + double noise_minvalue, noise_maxvalue; + + info.base_height = definition->height; + noiseGetRange(definition->_waves_noise, &noise_minvalue, &noise_maxvalue); + info.min_height = definition->height + noise_minvalue; + info.max_height = definition->height + noise_maxvalue; + + return info; +} + +static double _realGetHeight(Renderer* renderer, double x, double z) +{ + return _getHeight(renderer->water->definition, x, z); +} + +static WaterResult _realGetResult(Renderer* renderer, double x, double z) +{ + WaterDefinition* definition = renderer->water->definition; + WaterResult result; + RayCastingResult refracted; + Vector3 location, normal, look; + Color color; + SurfaceMaterial material; + double detail, depth; + + location.x = x; + location.y = _getHeight(definition, x, z); + location.z = z; + result.location = location; + + detail = renderer->getPrecision(renderer, location) * 0.1; + if (detail < 0.00001) + { + detail = 0.00001; + } + + normal = _getNormal(definition, location, detail); + look = v3Normalize(renderer->getCameraDirection(renderer, location)); + result.reflected = renderer->rayWalking(renderer, location, _reflectRay(look, normal), 1, 0, 1, 1).hit_color; + refracted = renderer->rayWalking(renderer, location, _refractRay(look, normal), 1, 0, 1, 1); + depth = v3Norm(v3Sub(location, refracted.hit_location)); + if (depth > definition->transparency_depth) + { + result.refracted = definition->depth_color; + } + else + { + depth /= definition->transparency_depth; + result.refracted.r = refracted.hit_color.r * (1.0 - depth) + definition->depth_color.r * depth; + result.refracted.g = refracted.hit_color.g * (1.0 - depth) + definition->depth_color.g * depth; + result.refracted.b = refracted.hit_color.b * (1.0 - depth) + definition->depth_color.b * depth; + result.refracted.a = 1.0; + } + + color.r = definition->material.base.r * (1.0 - definition->transparency) + result.reflected.r * definition->reflection + result.refracted.r * definition->transparency; + color.g = definition->material.base.g * (1.0 - definition->transparency) + result.reflected.g * definition->reflection + result.refracted.g * definition->transparency; + color.b = definition->material.base.b * (1.0 - definition->transparency) + result.reflected.b * definition->reflection + result.refracted.b * definition->transparency; + color.a = 1.0; + + material = definition->material; + material.base = color; + + _applyFoam(definition, location, normal, detail, &material); + + color = renderer->applyLightingToSurface(renderer, location, normal, &material); + color = renderer->applyMediumTraversal(renderer, location, color); + + result.base = definition->material.base; + result.final = color; + + return result; +} + +/******************** Renderer ********************/ +static WaterRenderer* _createRenderer() +{ + WaterRenderer* result; + + result = malloc(sizeof(WaterRenderer)); + result->definition = WaterDefinitionClass.create(); + + result->getHeightInfo = _fakeGetHeightInfo; + result->getHeight = _fakeGetHeight; + result->getResult = _fakeGetResult; + + return result; +} + +static void _deleteRenderer(WaterRenderer* renderer) +{ + WaterDefinitionClass.destroy(renderer->definition); + free(renderer); +} + +static void _bindRenderer(Renderer* renderer, WaterDefinition* definition) +{ + WaterDefinitionClass.copy(definition, renderer->water->definition); + + renderer->water->getHeightInfo = _realGetHeightInfo; + renderer->water->getHeight = _realGetHeight; + renderer->water->getResult = _realGetResult; + + lightingManagerRegisterFilter(renderer->lighting, (FuncLightingAlterLight)_alterLight, renderer); +} + +StandardRenderer CloudsRendererClass = { + (FuncObjectCreate)_createRenderer, + (FuncObjectDelete)_deleteRenderer, + (FuncObjectBind)_bindRenderer +};