diff --git a/src/editing/formwater.cpp b/src/editing/formwater.cpp index c684861..d362036 100644 --- a/src/editing/formwater.cpp +++ b/src/editing/formwater.cpp @@ -121,10 +121,15 @@ protected: cameraSetLocation(_renderer->render_camera, camera_location); } + static double _getWaterHeight(Renderer* renderer) + { + return 0.0; + } + void updateData() { WaterRendererClass.bind(_renderer, _definition); - _renderer->water->definition->height = 0.0; + _renderer->terrain->getWaterHeight = _getWaterHeight; } void choiceChangeEvent(const QString& key, int position) @@ -234,7 +239,7 @@ BaseForm(parent) addPreview(previewCoverage, tr("Coverage preview")); addPreview(previewColor, tr("Rendered preview")); - addInputDouble(tr("Height"), &_definition->height, -15.0, 15.0, 0.1, 1.0); + //addInputDouble(tr("Height"), &_definition->height, -15.0, 15.0, 0.1, 1.0); addInputMaterial(tr("Surface material"), &_definition->material); addInputColor(tr("Depth color"), &_definition->depth_color); addInputDouble(tr("Transparency"), &_definition->transparency, 0.0, 1.0, 0.001, 0.1); diff --git a/src/editing/terrain/mainterrainform.cpp b/src/editing/terrain/mainterrainform.cpp index 6b91d7b..5061b89 100644 --- a/src/editing/terrain/mainterrainform.cpp +++ b/src/editing/terrain/mainterrainform.cpp @@ -20,8 +20,9 @@ MainTerrainForm::MainTerrainForm(QWidget *parent) : _form_helper->addPreview("preview_shape", _renderer_shape); _form_helper->addDoubleInputSlider("input_scaling", &_terrain->scaling, 0.1, 3.0, 0.03, 0.3); - _form_helper->addDoubleInputSlider("input_height", &_terrain->height, 0.0, 3.0, 0.01, 0.1); + _form_helper->addDoubleInputSlider("input_height", &_terrain->height, 1.0, 45.0, 0.3, 3.0); _form_helper->addDoubleInputSlider("input_shadow_smoothing", &_terrain->shadow_smoothing, 0.0, 0.3, 0.003, 0.03); + _form_helper->addDoubleInputSlider("input_water_height", &_terrain->water_height, -2.0, 2.0, 0.01, 0.1); _form_helper->setApplyButton("button_apply"); _form_helper->setRevertButton("button_revert"); diff --git a/src/editing/terrain/mainterrainform.ui b/src/editing/terrain/mainterrainform.ui index 96abd77..ceb7822 100644 --- a/src/editing/terrain/mainterrainform.ui +++ b/src/editing/terrain/mainterrainform.ui @@ -250,7 +250,7 @@ - + 400 diff --git a/src/editing/widgetexplorer.cpp b/src/editing/widgetexplorer.cpp index d61c7f7..41c8320 100644 --- a/src/editing/widgetexplorer.cpp +++ b/src/editing/widgetexplorer.cpp @@ -399,13 +399,14 @@ void WidgetExplorer::paintGL() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Render water + double water_height = _renderer->terrain->getWaterHeight(_renderer); glDisable(GL_TEXTURE_2D); glColor3f(water->material.base.r, water->material.base.g, water->material.base.b); glBegin(GL_QUADS); - glVertex3f(camera_location.x - 500.0, water->height, camera_location.z - 500.0); - glVertex3f(camera_location.x - 500.0, water->height, camera_location.z + 500.0); - glVertex3f(camera_location.x + 500.0, water->height, camera_location.z + 500.0); - glVertex3f(camera_location.x + 500.0, water->height, camera_location.z - 500.0); + glVertex3f(camera_location.x - 500.0, water_height, camera_location.z - 500.0); + glVertex3f(camera_location.x - 500.0, water_height, camera_location.z + 500.0); + glVertex3f(camera_location.x + 500.0, water_height, camera_location.z + 500.0); + glVertex3f(camera_location.x + 500.0, water_height, camera_location.z - 500.0); glEnd(); // Render chunks diff --git a/src/editing/widgetheightmap.cpp b/src/editing/widgetheightmap.cpp index fc8fa8c..cd13d71 100644 --- a/src/editing/widgetheightmap.cpp +++ b/src/editing/widgetheightmap.cpp @@ -27,9 +27,9 @@ QGLWidget(parent) _water = true; _wireframe = true; - WaterDefinition* water_definition = (WaterDefinition*) WaterDefinitionClass.create(); + WaterDefinition* water_definition = (WaterDefinition*)WaterDefinitionClass.create(); sceneryGetWater(water_definition); - _water_height = water_definition->height; + _water_height = _renderer->terrain->getWaterHeight(_renderer); WaterDefinitionClass.destroy(water_definition); _average_frame_time = 0.0; @@ -74,6 +74,7 @@ void WidgetHeightMap::setTerrain(TerrainDefinition* terrain) { _terrain = terrain; TerrainRendererClass.bind(_renderer, _terrain); + _water_height = _renderer->terrain->getWaterHeight(_renderer); revert(); } diff --git a/src/rendering/terrain/public.h b/src/rendering/terrain/public.h index 1670870..ca83821 100644 --- a/src/rendering/terrain/public.h +++ b/src/rendering/terrain/public.h @@ -26,6 +26,8 @@ typedef struct TerrainHeightMap* height_map; + double water_height; + double _detail; NoiseGenerator* _height_noise; double _min_height; @@ -40,7 +42,8 @@ typedef struct typedef double (*FuncTerrainGetHeight)(Renderer* renderer, double x, double z, int with_painting); typedef TerrainResult (*FuncTerrainGetResult)(Renderer* renderer, double x, double z, int with_painting, int with_textures); -typedef Color (*FuncTerrainGetFinalColor)(Renderer* renderer, Vector3 location, double precision); +typedef Color(*FuncTerrainGetFinalColor)(Renderer* renderer, Vector3 location, double precision); +typedef double (*FuncGetWaterHeight)(Renderer* renderer); typedef struct { @@ -50,6 +53,7 @@ typedef struct FuncTerrainGetHeight getHeight; FuncTerrainGetResult getResult; FuncTerrainGetFinalColor getFinalColor; + FuncGetWaterHeight getWaterHeight; void* _internal_data; } TerrainRenderer; diff --git a/src/rendering/terrain/ter_definition.c b/src/rendering/terrain/ter_definition.c index 62d8407..b61c74a 100644 --- a/src/rendering/terrain/ter_definition.c +++ b/src/rendering/terrain/ter_definition.c @@ -10,10 +10,17 @@ static void _validateDefinition(TerrainDefinition* definition) { noiseValidate(definition->_height_noise); + if (definition->height < 1.0) + { + definition->height = 1.0; + } + /* Get minimal and maximal height */ noiseGetRange(definition->_height_noise, &definition->_min_height, &definition->_max_height); - definition->_min_height *= definition->height; - definition->_max_height *= definition->height; + definition->_min_height *= definition->height * definition->scaling; + definition->_max_height *= definition->height * definition->scaling; + + /* TODO Alter with heightmap min/max */ } static TerrainDefinition* _createDefinition() @@ -26,6 +33,8 @@ static TerrainDefinition* _createDefinition() definition->height_map = terrainHeightMapCreate(definition); + definition->water_height = -0.8; + definition->_height_noise = noiseCreateGenerator(); terrainAutoPreset(definition, TERRAIN_PRESET_STANDARD); @@ -48,6 +57,8 @@ static void _copyDefinition(TerrainDefinition* source, TerrainDefinition* destin terrainHeightmapCopy(source->height_map, destination->height_map); + destination->water_height = source->water_height; + noiseCopy(source->_height_noise, destination->_height_noise); _validateDefinition(destination); @@ -59,6 +70,7 @@ static void _saveDefinition(PackStream* stream, TerrainDefinition* definition) packWriteDouble(stream, &definition->scaling); packWriteDouble(stream, &definition->shadow_smoothing); terrainHeightmapSave(stream, definition->height_map); + packWriteDouble(stream, &definition->water_height); noiseSaveGenerator(stream, definition->_height_noise); } @@ -68,6 +80,7 @@ static void _loadDefinition(PackStream* stream, TerrainDefinition* definition) packReadDouble(stream, &definition->scaling); packReadDouble(stream, &definition->shadow_smoothing); terrainHeightmapLoad(stream, definition->height_map); + packReadDouble(stream, &definition->water_height); noiseLoadGenerator(stream, definition->_height_noise); _validateDefinition(definition); @@ -82,294 +95,6 @@ StandardDefinition TerrainDefinitionClass = { (FuncObjectLoad)_loadDefinition }; -/******************** Binding ********************/ -static double _fakeGetHeight(Renderer* renderer, double x, double z, int with_painting) -{ - UNUSED(renderer); - UNUSED(x); - UNUSED(z); - UNUSED(with_painting); - - return 0.0; -} - -static double _realGetHeight(Renderer* renderer, double x, double z, int with_painting) -{ - return terrainGetInterpolatedHeight(renderer->terrain->definition, x, z, with_painting); -} - -static TerrainResult _fakeGetResult(Renderer* renderer, double x, double z, int with_painting, int with_textures) -{ - TerrainResult result; - - UNUSED(renderer); - UNUSED(x); - UNUSED(z); - UNUSED(with_painting); - UNUSED(with_textures); - - result.location.x = x; - result.location.y = 0.0; - result.location.z = z; - result.normal = VECTOR_UP; - - return result; -} - -static inline Vector3 _getNormal4(Vector3 center, Vector3 north, Vector3 east, Vector3 south, Vector3 west) -{ - Vector3 dnorth, deast, dsouth, dwest, normal; - - dnorth = v3Sub(north, center); - deast = v3Sub(east, center); - dsouth = v3Sub(south, center); - dwest = v3Sub(west, center); - - normal = v3Cross(deast, dnorth); - normal = v3Add(normal, v3Cross(dsouth, deast)); - normal = v3Add(normal, v3Cross(dwest, dsouth)); - normal = v3Add(normal, v3Cross(dnorth, dwest)); - - return v3Normalize(normal); -} - -static inline Vector3 _getNormal2(Vector3 center, Vector3 east, Vector3 south) -{ - return v3Normalize(v3Cross(v3Sub(south, center), v3Sub(east, center))); -} - -static TerrainResult _realGetResult(Renderer* renderer, double x, double z, int with_painting, int with_textures) -{ - TerrainResult result; - double detail = 0.001; /* TODO */ - - /* Normal */ - Vector3 center, north, east, south, west; - - center.x = x; - center.z = z; - center.y = renderer->terrain->getHeight(renderer, center.x, center.z, with_painting); - - east.x = x + detail; - east.z = z; - east.y = renderer->terrain->getHeight(renderer, east.x, east.z, with_painting); - - south.x = x; - south.z = z + detail; - south.y = renderer->terrain->getHeight(renderer, south.x, south.z, with_painting); - - if (renderer->render_quality > 6) - { - west.x = x - detail; - west.z = z; - west.y = renderer->terrain->getHeight(renderer, west.x, west.z, with_painting); - - north.x = x; - north.z = z - detail; - north.y = renderer->terrain->getHeight(renderer, north.x, north.z, with_painting); - - result.normal = _getNormal4(center, north, east, south, west); - } - else - { - result.normal = _getNormal2(center, east, south); - } - - /* Location */ - result.location = center; - - /* Texture displacement */ - if (with_textures) - { - center = renderer->textures->displaceTerrain(renderer, result); - result.location = center; - - /* Recompute normal */ - if (renderer->render_quality > 6) - { - /* Use 5 points on displaced terrain */ - east = renderer->textures->displaceTerrain(renderer, _realGetResult(renderer, east.x, east.z, with_painting, 0)); - south = renderer->textures->displaceTerrain(renderer, _realGetResult(renderer, south.x, south.z, with_painting, 0)); - west = renderer->textures->displaceTerrain(renderer, _realGetResult(renderer, west.x, west.z, with_painting, 0)); - north = renderer->textures->displaceTerrain(renderer, _realGetResult(renderer, north.x, north.z, with_painting, 0)); - - result.normal = _getNormal4(center, north, east, south, west); - } - else if (renderer->render_quality > 2) - { - /* Use 3 points on displaced terrain */ - east = renderer->textures->displaceTerrain(renderer, _realGetResult(renderer, east.x, east.z, with_painting, 0)); - south = renderer->textures->displaceTerrain(renderer, _realGetResult(renderer, south.x, south.z, with_painting, 0)); - - result.normal = _getNormal2(center, east, south); - } - else - { - /* TODO Use texture noise directly, as if terrain was a plane */ - } - } - - return result; -} - -static Color _fakeGetFinalColor(Renderer* renderer, Vector3 location, double precision) -{ - UNUSED(renderer); - UNUSED(location); - UNUSED(precision); - return COLOR_GREEN; -} - -static Color _realGetFinalColor(Renderer* renderer, Vector3 location, double precision) -{ - /* TODO Restore precision control */ - TexturesResult textures = renderer->textures->applyToTerrain(renderer, location.x, location.z); - return renderer->applyMediumTraversal(renderer, textures.final_location, textures.final_color); -} - -static RayCastingResult _fakeCastRay(Renderer* renderer, Vector3 start, Vector3 direction) -{ - UNUSED(renderer); - UNUSED(start); - UNUSED(direction); - - RayCastingResult result; - result.hit = 0; - return result; -} - -static RayCastingResult _realCastRay(Renderer* renderer, Vector3 start, Vector3 direction) -{ - RayCastingResult result; - TerrainDefinition* definition = renderer->terrain->definition; - Vector3 inc_vector; - double inc_value, inc_base, inc_factor, height, diff, lastdiff, length; - - direction = v3Normalize(direction); - inc_factor = (double)renderer->render_quality; - inc_base = 1.0; - inc_value = inc_base / inc_factor; - lastdiff = start.y - _realGetHeight(renderer, start.x, start.z, 1); - - length = 0.0; - do - { - inc_vector = v3Scale(direction, inc_value); - length += v3Norm(inc_vector); - start = v3Add(start, inc_vector); - height = _realGetHeight(renderer, start.x, start.z, 1); - diff = start.y - height; - if (diff < 0.0) - { - if (fabs(diff - lastdiff) > 0.00001) - { - start = v3Add(start, v3Scale(inc_vector, -diff / (diff - lastdiff))); - start.y = _realGetHeight(renderer, start.x, start.z, 1); - } - else - { - start.y = height; - } - result.hit = 1; - result.hit_location = start; - result.hit_color = _realGetFinalColor(renderer, start, renderer->getPrecision(renderer, result.hit_location)); - return result; - } - - if (diff < inc_base / inc_factor) - { - inc_value = inc_base / inc_factor; - } - else if (diff > inc_base) - { - inc_value = inc_base; - } - else - { - inc_value = diff; - } - lastdiff = diff; - } while (length < 50.0 && start.y <= definition->_max_height); - - result.hit = 0; - return result; -} - -static int _alterLight(Renderer* renderer, LightDefinition* light, Vector3 location) -{ - TerrainDefinition* definition = renderer->terrain->definition; - Vector3 inc_vector, direction_to_light; - double inc_value, inc_base, inc_factor, height, diff, light_factor, smoothing, length; - - direction_to_light = v3Scale(light->direction, -1.0); - if (direction_to_light.y < -0.05) - { - light->color = COLOR_BLACK; - return 1; - } - else if (direction_to_light.y < 0.0000) - { - light->color.r *= (0.05 + direction_to_light.y) / 0.05; - light->color.g *= (0.05 + direction_to_light.y) / 0.05; - light->color.b *= (0.05 + direction_to_light.y) / 0.05; - } - - inc_factor = (double)renderer->render_quality; - inc_base = definition->height / definition->scaling; - inc_value = inc_base / inc_factor; - smoothing = definition->shadow_smoothing; - - light_factor = 1.0; - length = 0.0; - diff = 0.0; - do - { - inc_vector = v3Scale(direction_to_light, inc_value); - length += v3Norm(inc_vector); - location = v3Add(location, inc_vector); - height = renderer->terrain->getResult(renderer, location.x, location.z, 1, 1).location.y; - diff = location.y - height; - if (diff < 0.0) - { - if (length * smoothing > 0.000001) - { - light_factor += diff * v3Norm(inc_vector) / (length * smoothing); - } - else - { - light_factor = 0.0; - } - } - - if (diff < inc_base / inc_factor) - { - inc_value = inc_base / inc_factor; - } - else if (diff > inc_base) - { - inc_value = inc_base; - } - else - { - inc_value = diff; - } - } while (light_factor > 0.0 && length < (10.0 * inc_factor) && location.y <= definition->_max_height); - - if (light_factor <= 0.0) - { - light->color = COLOR_BLACK; - return 1; - } - else - { - light->color.r *= light_factor; - light->color.g *= light_factor; - light->color.b *= light_factor; - - return 1; - } -} - /******************** Public tools ********************/ double terrainGetGridHeight(TerrainDefinition* definition, int x, int z, int with_painting) { @@ -380,7 +105,7 @@ double terrainGetGridHeight(TerrainDefinition* definition, int x, int z, int wit height = noiseGet2DTotal(definition->_height_noise, (double)x, (double)z); } - return height; + return height * definition->height * definition->scaling; } double terrainGetInterpolatedHeight(TerrainDefinition* definition, double x, double z, int with_painting) @@ -396,43 +121,3 @@ double terrainGetInterpolatedHeight(TerrainDefinition* definition, double x, dou return height * definition->height * definition->scaling; } - -/******************** Renderer ********************/ -static TerrainRenderer* _createRenderer() -{ - TerrainRenderer* result; - - result = malloc(sizeof(TerrainRenderer)); - result->definition = TerrainDefinitionClass.create(); - - result->castRay = _fakeCastRay; - result->getHeight = _fakeGetHeight; - result->getResult = _fakeGetResult; - result->getFinalColor = _fakeGetFinalColor; - - return result; -} - -static void _deleteRenderer(TerrainRenderer* renderer) -{ - TerrainDefinitionClass.destroy(renderer->definition); - free(renderer); -} - -static void _bindRenderer(Renderer* renderer, TerrainDefinition* definition) -{ - TerrainDefinitionClass.copy(definition, renderer->terrain->definition); - - renderer->terrain->castRay = _realCastRay; - renderer->terrain->getHeight = _realGetHeight; - renderer->terrain->getResult = _realGetResult; - renderer->terrain->getFinalColor = _realGetFinalColor; - - lightingManagerRegisterFilter(renderer->lighting, (FuncLightingAlterLight)_alterLight, renderer); -} - -StandardRenderer TerrainRendererClass = { - (FuncObjectCreate)_createRenderer, - (FuncObjectDelete)_deleteRenderer, - (FuncObjectBind)_bindRenderer -}; diff --git a/src/rendering/terrain/ter_painting.c b/src/rendering/terrain/ter_painting.c index 95878ac..3d60890 100644 --- a/src/rendering/terrain/ter_painting.c +++ b/src/rendering/terrain/ter_painting.c @@ -307,12 +307,12 @@ static double* _getDataPointer(HeightMapData* data, int x, int z, HeightMapData* } else if (terrain) { - *pixel = terrainGetGridHeight(terrain, x, z, 0); + *pixel = terrainGetGridHeight(terrain, x, z, 0) / (terrain->height * terrain->scaling); } } else if (terrain) { - *pixel = terrainGetGridHeight(terrain, x, z, 0); + *pixel = terrainGetGridHeight(terrain, x, z, 0) / (terrain->height * terrain->scaling); } } return pixel; @@ -411,7 +411,7 @@ int terrainHeightmapGetInterpolatedHeight(TerrainHeightMap* heightmap, double x, { if (!terrainHeightmapGetGridHeight(heightmap, ix, iz, &value)) { - value = terrainGetGridHeight(heightmap->terrain, ix, iz, 0); + value = terrainGetGridHeight(heightmap->terrain, ix, iz, 0) / (heightmap->terrain->scaling * heightmap->terrain->height); } stencil[(iz - (zlow - 1)) * 4 + ix - (xlow - 1)] = value; } @@ -462,6 +462,8 @@ static inline void _applyBrush(TerrainHeightMap* heightmap, TerrainBrush* brush, int x, z; double dx, dz, distance, influence; + force /= (heightmap->terrain->height * heightmap->terrain->scaling); + for (x = brush_rect.xstart; x <= brush_rect.xend; x++) { dx = (double)x; diff --git a/src/rendering/terrain/ter_presets.c b/src/rendering/terrain/ter_presets.c index 54f8ed5..e7236c0 100644 --- a/src/rendering/terrain/ter_presets.c +++ b/src/rendering/terrain/ter_presets.c @@ -11,19 +11,19 @@ void terrainAutoPreset(TerrainDefinition* definition, TerrainPreset preset) int resolution = 8; switch (preset) { - case TERRAIN_PRESET_STANDARD: - noiseRandomizeOffsets(definition->_height_noise); - noiseClearLevels(definition->_height_noise); - noiseAddLevelSimple(definition->_height_noise, pow(2.0, resolution + 1), -15.0, 15.0); - noiseAddLevelsSimple(definition->_height_noise, resolution - 2, pow(2.0, resolution - 1), -10.0, 10.0, 0.5); - noiseNormalizeAmplitude(definition->_height_noise, -15.0, 15.0, 0); - noiseSetFunctionParams(definition->_height_noise, NOISE_FUNCTION_SIMPLEX, 0.0, 0.0); - definition->scaling = 1.0; - definition->height = 1.0; - definition->shadow_smoothing = 0.03; - break; - default: - ; + case TERRAIN_PRESET_STANDARD: + noiseRandomizeOffsets(definition->_height_noise); + noiseClearLevels(definition->_height_noise); + noiseAddLevelSimple(definition->_height_noise, pow(2.0, resolution + 1), -1.0, 1.0); + noiseAddLevelsSimple(definition->_height_noise, resolution - 2, pow(2.0, resolution - 1), -0.7, 0.7, 0.5); + noiseNormalizeAmplitude(definition->_height_noise, -1.0, 1.0, 0); + noiseSetFunctionParams(definition->_height_noise, NOISE_FUNCTION_SIMPLEX, 0.0, 0.0); + definition->scaling = 1.0; + definition->height = 15.0; + definition->shadow_smoothing = 0.03; + break; + default: + ; } TerrainDefinitionClass.validate(definition); diff --git a/src/rendering/terrain/ter_render.c b/src/rendering/terrain/ter_render.c new file mode 100644 index 0000000..c6d15a0 --- /dev/null +++ b/src/rendering/terrain/ter_render.c @@ -0,0 +1,350 @@ +#include "private.h" + +#include +#include +#include "../tools.h" +#include "../renderer.h" + +/******************** Binding ********************/ +static double _fakeGetHeight(Renderer* renderer, double x, double z, int with_painting) +{ + UNUSED(renderer); + UNUSED(x); + UNUSED(z); + UNUSED(with_painting); + + return 0.0; +} + +static double _realGetHeight(Renderer* renderer, double x, double z, int with_painting) +{ + return terrainGetInterpolatedHeight(renderer->terrain->definition, x, z, with_painting); +} + +static TerrainResult _fakeGetResult(Renderer* renderer, double x, double z, int with_painting, int with_textures) +{ + TerrainResult result; + + UNUSED(renderer); + UNUSED(x); + UNUSED(z); + UNUSED(with_painting); + UNUSED(with_textures); + + result.location.x = x; + result.location.y = 0.0; + result.location.z = z; + result.normal = VECTOR_UP; + + return result; +} + +static inline Vector3 _getNormal4(Vector3 center, Vector3 north, Vector3 east, Vector3 south, Vector3 west) +{ + Vector3 dnorth, deast, dsouth, dwest, normal; + + dnorth = v3Sub(north, center); + deast = v3Sub(east, center); + dsouth = v3Sub(south, center); + dwest = v3Sub(west, center); + + normal = v3Cross(deast, dnorth); + normal = v3Add(normal, v3Cross(dsouth, deast)); + normal = v3Add(normal, v3Cross(dwest, dsouth)); + normal = v3Add(normal, v3Cross(dnorth, dwest)); + + return v3Normalize(normal); +} + +static inline Vector3 _getNormal2(Vector3 center, Vector3 east, Vector3 south) +{ + return v3Normalize(v3Cross(v3Sub(south, center), v3Sub(east, center))); +} + +static TerrainResult _realGetResult(Renderer* renderer, double x, double z, int with_painting, int with_textures) +{ + TerrainResult result; + double detail = 0.001; /* TODO */ + + /* Normal */ + Vector3 center, north, east, south, west; + + center.x = x; + center.z = z; + center.y = renderer->terrain->getHeight(renderer, center.x, center.z, with_painting); + + east.x = x + detail; + east.z = z; + east.y = renderer->terrain->getHeight(renderer, east.x, east.z, with_painting); + + south.x = x; + south.z = z + detail; + south.y = renderer->terrain->getHeight(renderer, south.x, south.z, with_painting); + + if (renderer->render_quality > 6) + { + west.x = x - detail; + west.z = z; + west.y = renderer->terrain->getHeight(renderer, west.x, west.z, with_painting); + + north.x = x; + north.z = z - detail; + north.y = renderer->terrain->getHeight(renderer, north.x, north.z, with_painting); + + result.normal = _getNormal4(center, north, east, south, west); + } + else + { + result.normal = _getNormal2(center, east, south); + } + + /* Location */ + result.location = center; + + /* Texture displacement */ + if (with_textures) + { + center = renderer->textures->displaceTerrain(renderer, result); + result.location = center; + + /* Recompute normal */ + if (renderer->render_quality > 6) + { + /* Use 5 points on displaced terrain */ + east = renderer->textures->displaceTerrain(renderer, _realGetResult(renderer, east.x, east.z, with_painting, 0)); + south = renderer->textures->displaceTerrain(renderer, _realGetResult(renderer, south.x, south.z, with_painting, 0)); + west = renderer->textures->displaceTerrain(renderer, _realGetResult(renderer, west.x, west.z, with_painting, 0)); + north = renderer->textures->displaceTerrain(renderer, _realGetResult(renderer, north.x, north.z, with_painting, 0)); + + result.normal = _getNormal4(center, north, east, south, west); + } + else if (renderer->render_quality > 2) + { + /* Use 3 points on displaced terrain */ + east = renderer->textures->displaceTerrain(renderer, _realGetResult(renderer, east.x, east.z, with_painting, 0)); + south = renderer->textures->displaceTerrain(renderer, _realGetResult(renderer, south.x, south.z, with_painting, 0)); + + result.normal = _getNormal2(center, east, south); + } + else + { + /* TODO Use texture noise directly, as if terrain was a plane */ + } + } + + return result; +} + +static Color _fakeGetFinalColor(Renderer* renderer, Vector3 location, double precision) +{ + UNUSED(renderer); + UNUSED(location); + UNUSED(precision); + return COLOR_GREEN; +} + +static Color _realGetFinalColor(Renderer* renderer, Vector3 location, double precision) +{ + /* TODO Restore precision control */ + TexturesResult textures = renderer->textures->applyToTerrain(renderer, location.x, location.z); + return renderer->applyMediumTraversal(renderer, textures.final_location, textures.final_color); +} + +static RayCastingResult _fakeCastRay(Renderer* renderer, Vector3 start, Vector3 direction) +{ + UNUSED(renderer); + UNUSED(start); + UNUSED(direction); + + RayCastingResult result; + result.hit = 0; + return result; +} + +static RayCastingResult _realCastRay(Renderer* renderer, Vector3 start, Vector3 direction) +{ + RayCastingResult result; + TerrainDefinition* definition = renderer->terrain->definition; + Vector3 inc_vector; + double inc_value, inc_base, inc_factor, height, diff, lastdiff, length; + + direction = v3Normalize(direction); + inc_factor = (double)renderer->render_quality; + inc_base = 1.0; + inc_value = inc_base / inc_factor; + lastdiff = start.y - _realGetHeight(renderer, start.x, start.z, 1); + + length = 0.0; + do + { + inc_vector = v3Scale(direction, inc_value); + length += v3Norm(inc_vector); + start = v3Add(start, inc_vector); + height = _realGetHeight(renderer, start.x, start.z, 1); + diff = start.y - height; + if (diff < 0.0) + { + if (fabs(diff - lastdiff) > 0.00001) + { + start = v3Add(start, v3Scale(inc_vector, -diff / (diff - lastdiff))); + start.y = _realGetHeight(renderer, start.x, start.z, 1); + } + else + { + start.y = height; + } + result.hit = 1; + result.hit_location = start; + result.hit_color = _realGetFinalColor(renderer, start, renderer->getPrecision(renderer, result.hit_location)); + return result; + } + + if (diff < inc_base / inc_factor) + { + inc_value = inc_base / inc_factor; + } + else if (diff > inc_base) + { + inc_value = inc_base; + } + else + { + inc_value = diff; + } + lastdiff = diff; + } + while (length < 50.0 && start.y <= definition->_max_height); + + result.hit = 0; + return result; +} + +static int _alterLight(Renderer* renderer, LightDefinition* light, Vector3 location) +{ + TerrainDefinition* definition = renderer->terrain->definition; + Vector3 inc_vector, direction_to_light; + double inc_value, inc_base, inc_factor, height, diff, light_factor, smoothing, length; + + direction_to_light = v3Scale(light->direction, -1.0); + if (direction_to_light.y < -0.05) + { + light->color = COLOR_BLACK; + return 1; + } + else if (direction_to_light.y < 0.0000) + { + light->color.r *= (0.05 + direction_to_light.y) / 0.05; + light->color.g *= (0.05 + direction_to_light.y) / 0.05; + light->color.b *= (0.05 + direction_to_light.y) / 0.05; + } + + inc_factor = (double)renderer->render_quality; + inc_base = definition->height / definition->scaling; + inc_value = inc_base / inc_factor; + smoothing = definition->shadow_smoothing; + + light_factor = 1.0; + length = 0.0; + diff = 0.0; + do + { + inc_vector = v3Scale(direction_to_light, inc_value); + length += v3Norm(inc_vector); + location = v3Add(location, inc_vector); + height = renderer->terrain->getResult(renderer, location.x, location.z, 1, 1).location.y; + diff = location.y - height; + if (diff < 0.0) + { + if (length * smoothing > 0.000001) + { + light_factor += diff * v3Norm(inc_vector) / (length * smoothing); + } + else + { + light_factor = 0.0; + } + } + + if (diff < inc_base / inc_factor) + { + inc_value = inc_base / inc_factor; + } + else if (diff > inc_base) + { + inc_value = inc_base; + } + else + { + inc_value = diff; + } + } + while (light_factor > 0.0 && length < (10.0 * inc_factor) && location.y <= definition->_max_height); + + if (light_factor <= 0.0) + { + light->color = COLOR_BLACK; + return 1; + } + else + { + light->color.r *= light_factor; + light->color.g *= light_factor; + light->color.b *= light_factor; + + return 1; + } +} + +static double _fakeGetWaterHeight(Renderer* renderer) +{ + UNUSED(renderer); + return -1000.0; +} + +static double _realGetWaterHeight(Renderer* renderer) +{ + return renderer->terrain->definition->water_height * renderer->terrain->definition->height * renderer->terrain->definition->scaling; +} + +/******************** Renderer ********************/ +static TerrainRenderer* _createRenderer() +{ + TerrainRenderer* result; + + result = malloc(sizeof (TerrainRenderer)); + result->definition = TerrainDefinitionClass.create(); + + result->castRay = _fakeCastRay; + result->getHeight = _fakeGetHeight; + result->getResult = _fakeGetResult; + result->getFinalColor = _fakeGetFinalColor; + result->getWaterHeight = _fakeGetWaterHeight; + + return result; +} + +static void _deleteRenderer(TerrainRenderer* renderer) +{ + TerrainDefinitionClass.destroy(renderer->definition); + free(renderer); +} + +static void _bindRenderer(Renderer* renderer, TerrainDefinition* definition) +{ + TerrainDefinitionClass.copy(definition, renderer->terrain->definition); + + renderer->terrain->castRay = _realCastRay; + renderer->terrain->getHeight = _realGetHeight; + renderer->terrain->getResult = _realGetResult; + renderer->terrain->getFinalColor = _realGetFinalColor; + renderer->terrain->getWaterHeight = _realGetWaterHeight; + + lightingManagerRegisterFilter(renderer->lighting, (FuncLightingAlterLight)_alterLight, renderer); +} + +StandardRenderer TerrainRendererClass = { + (FuncObjectCreate)_createRenderer, + (FuncObjectDelete)_deleteRenderer, + (FuncObjectBind)_bindRenderer +}; + diff --git a/src/rendering/water/public.h b/src/rendering/water/public.h index 87a6642..381486e 100644 --- a/src/rendering/water/public.h +++ b/src/rendering/water/public.h @@ -20,7 +20,6 @@ typedef enum typedef struct { - double height; double transparency; double reflection; SurfaceMaterial material; diff --git a/src/rendering/water/wat_definition.c b/src/rendering/water/wat_definition.c index b93e3fd..b798759 100644 --- a/src/rendering/water/wat_definition.c +++ b/src/rendering/water/wat_definition.c @@ -22,7 +22,6 @@ static WaterDefinition* _createDefinition() { WaterDefinition* definition = malloc(sizeof(WaterDefinition)); - definition->height = -4.0; definition->_waves_noise = noiseCreateGenerator(); waterAutoPreset(definition, WATER_PRESET_LAKE); @@ -48,7 +47,6 @@ static void _copyDefinition(WaterDefinition* source, WaterDefinition* destinatio 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); @@ -69,7 +67,6 @@ static void _saveDefinition(PackStream* stream, WaterDefinition* definition) 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); diff --git a/src/rendering/water/wat_preview.c b/src/rendering/water/wat_preview.c index dff0644..c739976 100644 --- a/src/rendering/water/wat_preview.c +++ b/src/rendering/water/wat_preview.c @@ -14,7 +14,7 @@ Color waterGetPreviewCoverage(Renderer* renderer, double x, double y, double sca double height; height = renderer->terrain->getHeight(renderer, x, y, 1); - if (height > renderer->water->definition->height) + if (height > renderer->terrain->getWaterHeight(renderer)) { return terrainGetPreviewColor(renderer, x, y, scaling); } diff --git a/src/rendering/water/wat_render.c b/src/rendering/water/wat_render.c index 4aa733f..e6eeba1 100644 --- a/src/rendering/water/wat_render.c +++ b/src/rendering/water/wat_render.c @@ -42,12 +42,12 @@ static WaterResult _fakeGetResult(Renderer* renderer, double x, double z) } /******************** Helpers ********************/ -static inline double _getHeight(WaterDefinition* definition, double x, double z) +static inline double _getHeight(WaterDefinition* definition, double base_height, double x, double z) { - return definition->height + noiseGet2DTotal(definition->_waves_noise, x, z); + return base_height + noiseGet2DTotal(definition->_waves_noise, x, z); } -static inline Vector3 _getNormal(WaterDefinition* definition, Vector3 base, double detail) +static inline Vector3 _getNormal(WaterDefinition* definition, double base_height, Vector3 base, double detail) { Vector3 back, right; double x, z; @@ -56,12 +56,12 @@ static inline Vector3 _getNormal(WaterDefinition* definition, Vector3 base, doub z = base.z; back.x = x; - back.y = _getHeight(definition, x, z + detail); + back.y = _getHeight(definition, base_height, x, z + detail); back.z = z + detail; back = v3Sub(back, base); right.x = x + detail; - right.y = _getHeight(definition, x + detail, z); + right.y = _getHeight(definition, base_height, x + detail, z); right.z = z; right = v3Sub(right, base); @@ -97,31 +97,33 @@ static inline Color _getFoamMask(Renderer* renderer, WaterDefinition* definition { Color result; double foam_factor, normal_diff, location_offset; + double base_height; + base_height = renderer->terrain->getWaterHeight(renderer); location_offset = 2.0 * detail; foam_factor = 0.0; location.x += location_offset; - normal_diff = 1.0 - v3Dot(normal, _getNormal(definition, location, detail)); + normal_diff = 1.0 - v3Dot(normal, _getNormal(definition, base_height, 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)); + normal_diff = 1.0 - v3Dot(normal, _getNormal(definition, base_height, 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)); + normal_diff = 1.0 - v3Dot(normal, _getNormal(definition, base_height, 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)); + normal_diff = 1.0 - v3Dot(normal, _getNormal(definition, base_height, location, detail)); if (normal_diff > foam_factor) { foam_factor = normal_diff; @@ -162,12 +164,14 @@ static int _alterLight(Renderer* renderer, LightDefinition* light, Vector3 at) { WaterDefinition* definition = renderer->water->definition; double factor; + double base_height; - if (at.y < definition->height) + base_height = renderer->terrain->getWaterHeight(renderer); + if (at.y < base_height) { if (light->direction.y <= -0.00001) { - factor = (definition->height - at.y) / (-light->direction.y * definition->lighting_depth); + factor = (base_height - at.y) / (-light->direction.y * definition->lighting_depth); if (factor > 1.0) { factor = 1.0; @@ -200,17 +204,17 @@ static HeightInfo _realGetHeightInfo(Renderer* renderer) HeightInfo info; double noise_minvalue, noise_maxvalue; - info.base_height = definition->height; + info.base_height = renderer->terrain->getWaterHeight(renderer); noiseGetRange(definition->_waves_noise, &noise_minvalue, &noise_maxvalue); - info.min_height = definition->height + noise_minvalue; - info.max_height = definition->height + noise_maxvalue; + info.min_height = info.base_height + noise_minvalue; + info.max_height = info.base_height + noise_maxvalue; return info; } static double _realGetHeight(Renderer* renderer, double x, double z) { - return _getHeight(renderer->water->definition, x, z); + return _getHeight(renderer->water->definition, renderer->terrain->getWaterHeight(renderer), x, z); } static WaterResult _realGetResult(Renderer* renderer, double x, double z) @@ -220,10 +224,12 @@ static WaterResult _realGetResult(Renderer* renderer, double x, double z) RayCastingResult refracted; Vector3 location, normal, look_direction; Color color, foam; - double detail, depth; + double base_height, detail, depth; + + base_height = renderer->terrain->getWaterHeight(renderer); location.x = x; - location.y = _getHeight(definition, x, z); + location.y = _getHeight(definition, base_height, x, z); location.z = z; result.location = location; @@ -233,7 +239,7 @@ static WaterResult _realGetResult(Renderer* renderer, double x, double z) detail = 0.00001; } - normal = _getNormal(definition, location, detail); + normal = _getNormal(definition, base_height, location, detail); look_direction = v3Normalize(v3Sub(location, renderer->getCameraLocation(renderer, location))); /* Reflection */