paysages : Water refactoring (WIP).
git-svn-id: https://subversion.assembla.com/svn/thunderk/paysages@527 b1fd45b6-86a6-48da-8261-f70d1f35bdcc
This commit is contained in:
parent
9a7bc290dc
commit
e8b3468038
19 changed files with 701 additions and 605 deletions
|
@ -3,16 +3,15 @@
|
|||
|
||||
#include <QColor>
|
||||
#include <QSlider>
|
||||
#include <math.h>
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);*/
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -1,446 +0,0 @@
|
|||
#include "water.h"
|
||||
|
||||
#include "shared/types.h"
|
||||
#include "render.h"
|
||||
#include "tools.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
100
lib_paysages/water/definition.c
Normal file
100
lib_paysages/water/definition.c
Normal file
|
@ -0,0 +1,100 @@
|
|||
#include "private.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
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
|
||||
};
|
56
lib_paysages/water/presets.c
Normal file
56
lib_paysages/water/presets.c
Normal file
|
@ -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);
|
||||
}
|
44
lib_paysages/water/preview.c
Normal file
44
lib_paysages/water/preview.c
Normal file
|
@ -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)
|
||||
{
|
||||
|
||||
}
|
7
lib_paysages/water/private.h
Normal file
7
lib_paysages/water/private.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
#ifndef _PAYSAGES_WATER_PRIVATE_H_
|
||||
#define _PAYSAGES_WATER_PRIVATE_H_
|
||||
|
||||
#include "public.h"
|
||||
|
||||
|
||||
#endif
|
82
lib_paysages/water/public.h
Normal file
82
lib_paysages/water/public.h
Normal file
|
@ -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
|
82
lib_paysages/water/raster.c
Normal file
82
lib_paysages/water/raster.c
Normal file
|
@ -0,0 +1,82 @@
|
|||
#include "public.h"
|
||||
#include "private.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#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;
|
||||
}
|
||||
}
|
304
lib_paysages/water/render.c
Normal file
304
lib_paysages/water/render.c
Normal file
|
@ -0,0 +1,304 @@
|
|||
#include "private.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#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
|
||||
};
|
Loading…
Reference in a new issue