diff --git a/gui_qt/explorerchunkterrain.cpp b/gui_qt/explorerchunkterrain.cpp index 80c3bfc..683566e 100644 --- a/gui_qt/explorerchunkterrain.cpp +++ b/gui_qt/explorerchunkterrain.cpp @@ -49,7 +49,7 @@ bool ExplorerChunkTerrain::onMaintainEvent() { if (_tessellation_current_size == 0 || i % old_tessellation_inc != 0 || j % old_tessellation_inc != 0) { - double height = renderer->terrain->getHeight(renderer, _startx + _tessellation_step * (double)i, _startz + _tessellation_step * (double)j); + double height = renderer->terrain->getHeight(renderer, _startx + _tessellation_step * (double)i, _startz + _tessellation_step * (double)j, 1); _tessellation[j * (_tessellation_max_size + 1) + i] = height; } } diff --git a/gui_qt/formrender.cpp b/gui_qt/formrender.cpp index f792ea4..756d3d9 100644 --- a/gui_qt/formrender.cpp +++ b/gui_qt/formrender.cpp @@ -43,7 +43,7 @@ protected: { Vector3 down = {0.0, -1.0, 0.0}; Vector3 location; - double height = _renderer.terrain->getHeight(&_renderer, x, y); + double height = _renderer.terrain->getHeight(&_renderer, x, y, 1); if (height < _water.height) { diff --git a/gui_qt/formterrain.cpp b/gui_qt/formterrain.cpp index 9d004b0..493536b 100644 --- a/gui_qt/formterrain.cpp +++ b/gui_qt/formterrain.cpp @@ -49,8 +49,8 @@ FormTerrain::FormTerrain(QWidget *parent): addPreview(previewColor, tr("Lighted preview (no texture)")); //addInputNoise(tr("Noise"), _definition.height_noise); - addInputDouble(tr("Height"), &_definition->height, 0.0, 20.0, 0.1, 1.0); - addInputDouble(tr("Scaling"), &_definition->scaling, 20.0, 200.0, 1.0, 10.0); + addInputDouble(tr("Scaling"), &_definition->scaling, 0.1, 3.0, 0.03, 0.3); + addInputDouble(tr("Height modifier"), &_definition->height, 0.0, 3.0, 0.01, 0.1); addInputDouble(tr("Shadow smoothing"), &_definition->shadow_smoothing, 0.0, 0.3, 0.003, 0.03); revertConfig(); diff --git a/gui_qt/formtextures.cpp b/gui_qt/formtextures.cpp index 4f4e207..8b511a7 100644 --- a/gui_qt/formtextures.cpp +++ b/gui_qt/formtextures.cpp @@ -40,7 +40,7 @@ protected: Vector3 location; double coverage; location.x = x; - location.y = _renderer.terrain->getHeight(&_renderer, x, y); + location.y = _renderer.terrain->getHeight(&_renderer, x, y, 1); location.z = y; coverage = texturesGetLayerCoverage(_preview_layer, &_renderer, location, this->scaling); return QColor::fromRgbF(coverage, coverage, coverage, 1.0); diff --git a/gui_qt/formwater.cpp b/gui_qt/formwater.cpp index bec674d..d4fbf8d 100644 --- a/gui_qt/formwater.cpp +++ b/gui_qt/formwater.cpp @@ -35,7 +35,7 @@ protected: { double height; - height = _renderer.terrain->getHeight(&_renderer, x, -y); + height = _renderer.terrain->getHeight(&_renderer, x, -y, 1); if (height > _definition.height) { return colorToQColor(terrainGetPreviewColor(&_renderer, x, -y, scaling)); diff --git a/gui_qt/widgetheightmap.cpp b/gui_qt/widgetheightmap.cpp index 50f1e17..3cfc518 100644 --- a/gui_qt/widgetheightmap.cpp +++ b/gui_qt/widgetheightmap.cpp @@ -151,10 +151,10 @@ void WidgetHeightMap::timerEvent(QTimerEvent*) double brush_strength; TerrainBrush brush; - brush.relative_x = (_brush_x + 40.0) / 80.0; - brush.relative_z = (_brush_z + 40.0) / 80.0; - brush.hard_radius = _brush_size * (1.0 - _brush_smoothing) / 80.0; - brush.smoothed_size = _brush_size * _brush_smoothing / 80.0; + brush.relative_x = _brush_x; + brush.relative_z = _brush_z; + brush.hard_radius = _brush_size * (1.0 - _brush_smoothing); + brush.smoothed_size = _brush_size * _brush_smoothing; brush.total_radius = brush.hard_radius + brush.smoothed_size; brush_strength = _brush_strength * duration / 0.1; @@ -363,10 +363,10 @@ void WidgetHeightMap::updateVertexInfo() { _VertexInfo* vertex = _vertices + z * rx + x; - vertex->point.x = 80.0 * (double)x / (double)(rx - 1) - 40.0; - vertex->point.z = 80.0 * (double)z / (double)(rz - 1) - 40.0; + vertex->point.x = (double)x; + vertex->point.z = (double)z; - vertex->point.y = _renderer.terrain->getHeight(&_renderer, vertex->point.x, vertex->point.z); + vertex->point.y = terrainGetGridHeight(_terrain, x, z, 1); } } diff --git a/lib_paysages/camera.c b/lib_paysages/camera.c index 826e95b..859c889 100644 --- a/lib_paysages/camera.c +++ b/lib_paysages/camera.c @@ -76,7 +76,7 @@ void cameraValidateDefinition(CameraDefinition* definition, int check_above) waterDeleteDefinition(&water); renderer = sceneryCreateStandardRenderer(); - terrain_height = renderer.terrain->getHeight(&renderer, definition->location.x, definition->location.z) + 0.5; + terrain_height = renderer.terrain->getHeight(&renderer, definition->location.x, definition->location.z, 1) + 0.5; rendererDelete(&renderer); if (definition->location.y < water_height || definition->location.y < terrain_height) diff --git a/lib_paysages/terrain/main.c b/lib_paysages/terrain/main.c index 5d10859..3fa833c 100644 --- a/lib_paysages/terrain/main.c +++ b/lib_paysages/terrain/main.c @@ -84,25 +84,29 @@ StandardDefinition TerrainDefinitionClass = { }; /******************** Binding ********************/ -static double _fakeGetHeight(Renderer* renderer, double x, double z) +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 _getHeight(Renderer* renderer, double x, double z) +static double _getHeight(Renderer* renderer, double x, double z, int with_painting) { + double height; TerrainDefinition* definition = renderer->terrain->definition; x /= definition->scaling; z /= definition->scaling; - double height = noiseGet2DTotal(definition->_height_noise, x, z); - /* TODO Apply paintings */ + if (!with_painting || !terrainHeightmapGetHeight(definition->height_map, x, z, &height)) + { + height = noiseGet2DTotal(definition->_height_noise, x, z); + } - return height * definition->height; + return height * definition->height * definition->scaling; } static Color _fakeGetFinalColor(Renderer* renderer, Vector3 location, double precision) @@ -123,7 +127,7 @@ static Color _getFinalColor(Renderer* renderer, Vector3 location, double precisi return color; } -RayCastingResult _fakeCastRay(Renderer* renderer, Vector3 start, Vector3 direction) +static RayCastingResult _fakeCastRay(Renderer* renderer, Vector3 start, Vector3 direction) { UNUSED(renderer); UNUSED(start); @@ -134,7 +138,7 @@ RayCastingResult _fakeCastRay(Renderer* renderer, Vector3 start, Vector3 directi return result; } -RayCastingResult _castRay(Renderer* renderer, Vector3 start, Vector3 direction) +static RayCastingResult _castRay(Renderer* renderer, Vector3 start, Vector3 direction) { RayCastingResult result; TerrainDefinition* definition = renderer->terrain->definition; @@ -145,7 +149,7 @@ RayCastingResult _castRay(Renderer* renderer, Vector3 start, Vector3 direction) inc_factor = (double)renderer->render_quality; inc_base = 1.0; inc_value = inc_base / inc_factor; - lastdiff = start.y - _getHeight(renderer, start.x, start.z); + lastdiff = start.y - _getHeight(renderer, start.x, start.z, 1); length = 0.0; do @@ -153,14 +157,14 @@ RayCastingResult _castRay(Renderer* renderer, Vector3 start, Vector3 direction) inc_vector = v3Scale(direction, inc_value); length += v3Norm(inc_vector); start = v3Add(start, inc_vector); - height = _getHeight(renderer, start.x, start.z); + height = _getHeight(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 = _getHeight(renderer, start.x, start.z); + start.y = _getHeight(renderer, start.x, start.z, 1); } else { @@ -236,7 +240,7 @@ static LightDefinition _alterLight(Renderer* renderer, LightDefinition* light, V inc_vector = v3Scale(direction_to_light, inc_value); length += v3Norm(inc_vector); location = v3Add(location, inc_vector); - height = _getHeight(renderer, location.x, location.z); + height = _getHeight(renderer, location.x, location.z, 1); diff = location.y - height; if (diff < 0.0) { @@ -279,6 +283,19 @@ static LightDefinition _alterLight(Renderer* renderer, LightDefinition* light, V } } +/******************** Public tools ********************/ +double terrainGetGridHeight(TerrainDefinition* definition, int x, int z, int with_painting) +{ + double height; + + if (!with_painting || !terrainHeightmapGetHeight(definition->height_map, (double)x, (double)z, &height)) + { + height = noiseGet2DTotal(definition->_height_noise, (double)x, (double)z); + } + + return height; +} + /******************** Renderer ********************/ static TerrainRenderer* _createRenderer() { diff --git a/lib_paysages/terrain/painting.c b/lib_paysages/terrain/painting.c index 2edd9e0..9ad1ec2 100644 --- a/lib_paysages/terrain/painting.c +++ b/lib_paysages/terrain/painting.c @@ -71,13 +71,13 @@ void terrainHeightmapCopy(TerrainHeightMap* source, TerrainHeightMap* destinatio { destination->fixed_data[i].xstart = source->fixed_data[i].xstart; destination->fixed_data[i].xsize = source->fixed_data[i].xsize; - destination->fixed_data[i].ystart = source->fixed_data[i].ystart; - destination->fixed_data[i].ysize = source->fixed_data[i].ysize; - if (destination->fixed_data[i].xsize * destination->fixed_data[i].ysize > 0) + destination->fixed_data[i].zstart = source->fixed_data[i].zstart; + destination->fixed_data[i].zsize = source->fixed_data[i].zsize; + if (destination->fixed_data[i].xsize * destination->fixed_data[i].zsize > 0) { - destination->fixed_data[i].data = realloc(destination->fixed_data[i].data, sizeof(double) * destination->fixed_data[i].xsize * destination->fixed_data[i].ysize); + destination->fixed_data[i].data = realloc(destination->fixed_data[i].data, sizeof(double) * destination->fixed_data[i].xsize * destination->fixed_data[i].zsize); } - memcpy(destination->fixed_data[i].data, source->fixed_data[i].data, sizeof(double) * destination->fixed_data[i].xsize * destination->fixed_data[i].ysize); + memcpy(destination->fixed_data[i].data, source->fixed_data[i].data, sizeof(double) * destination->fixed_data[i].xsize * destination->fixed_data[i].zsize); } destination->floating_used = 0; @@ -92,9 +92,9 @@ void terrainHeightmapSave(PackStream* stream, TerrainHeightMap* heightmap) { packWriteInt(stream, &heightmap->fixed_data[i].xstart); packWriteInt(stream, &heightmap->fixed_data[i].xsize); - packWriteInt(stream, &heightmap->fixed_data[i].ystart); - packWriteInt(stream, &heightmap->fixed_data[i].ysize); - for (j = 0; j < heightmap->fixed_data[i].xsize * heightmap->fixed_data[i].ysize; j++) + packWriteInt(stream, &heightmap->fixed_data[i].zstart); + packWriteInt(stream, &heightmap->fixed_data[i].zsize); + for (j = 0; j < heightmap->fixed_data[i].xsize * heightmap->fixed_data[i].zsize; j++) { packWriteDouble(stream, &heightmap->fixed_data[i].data[j]); } @@ -112,13 +112,13 @@ void terrainHeightmapLoad(PackStream* stream, TerrainHeightMap* heightmap) { packReadInt(stream, &heightmap->fixed_data[i].xstart); packReadInt(stream, &heightmap->fixed_data[i].xsize); - packReadInt(stream, &heightmap->fixed_data[i].ystart); - packReadInt(stream, &heightmap->fixed_data[i].ysize); - if (heightmap->fixed_data[i].xsize * heightmap->fixed_data[i].ysize > 0) + packReadInt(stream, &heightmap->fixed_data[i].zstart); + packReadInt(stream, &heightmap->fixed_data[i].zsize); + if (heightmap->fixed_data[i].xsize * heightmap->fixed_data[i].zsize > 0) { - heightmap->fixed_data[i].data = realloc(heightmap->fixed_data[i].data, sizeof(double) * heightmap->fixed_data[i].xsize * heightmap->fixed_data[i].ysize); + heightmap->fixed_data[i].data = realloc(heightmap->fixed_data[i].data, sizeof(double) * heightmap->fixed_data[i].xsize * heightmap->fixed_data[i].zsize); } - for (j = 0; j < heightmap->fixed_data[i].xsize * heightmap->fixed_data[i].ysize; j++) + for (j = 0; j < heightmap->fixed_data[i].xsize * heightmap->fixed_data[i].zsize; j++) { packReadDouble(stream, &heightmap->fixed_data[i].data[j]); } @@ -127,32 +127,90 @@ void terrainHeightmapLoad(PackStream* stream, TerrainHeightMap* heightmap) heightmap->floating_used = 0; } +static inline int _checkDataHit(TerrainHeightMapData* data, double x, double z, double* result) +{ + if (x > (double)data->xstart && x < (double)(data->xstart + data->xsize) && z > (double)data->zstart && z < (double)(data->zstart + data->zsize)) + { + /* TODO Get interpolated value */ + *result = 0.0; + return 1; + } + else + { + return 0; + } +} + +int terrainHeightmapGetHeight(TerrainHeightMap* heightmap, double x, double z, double* result) +{ + int i; + + for (i = 0; i < heightmap->fixed_count; i++) + { + if (_checkDataHit(heightmap->fixed_data + i, x, z, result)) + { + return 1; + } + } + + if (heightmap->floating_used && _checkDataHit(&heightmap->floating_data, x, z, result)) + { + return 1; + } + else + { + return 0; + } +} + static void _prepareBrushStroke(TerrainHeightMap* heightmap, TerrainBrush* brush) { - double cx = brush->relative_x / TERRAIN_HEIGHTMAP_DETAIL; - double cz = brush->relative_z / TERRAIN_HEIGHTMAP_DETAIL; + double cx = brush->relative_x; + double cz = brush->relative_z; double s = brush->smoothed_size + brush->hard_radius; - double sx = s / TERRAIN_HEIGHTMAP_DETAIL; - double sz = s / TERRAIN_HEIGHTMAP_DETAIL; + double sx = s; + double sz = s; int x1 = (int)floor(cx - sx); int x2 = (int)ceil(cx + sx); int z1 = (int)floor(cz - sz); int z2 = (int)ceil(cz + sz); - /* TODO Prepare floating data */ + /* Prepare floating data */ + if (heightmap->floating_used) + { + /* Grow floating area */ + /* TODO */ + } + else + { + /* Init flaoting area */ + heightmap->floating_used = 1; + heightmap->floating_data.xstart = x1; + heightmap->floating_data.xsize = x2 - x1 + 1; + heightmap->floating_data.zstart = z1; + heightmap->floating_data.zsize = z2 - z1 + 1; + + size_t new_size; + new_size = sizeof(double) * heightmap->floating_data.xsize * heightmap->floating_data.zsize; + heightmap->floating_data.data = realloc(heightmap->floating_data.data, new_size); + memset(heightmap->floating_data.data, 0, new_size); + } } void terrainBrushElevation(TerrainHeightMap* heightmap, TerrainBrush* brush, double value) { + _prepareBrushStroke(heightmap, brush); } void terrainBrushSmooth(TerrainHeightMap* heightmap, TerrainBrush* brush, double value) { + _prepareBrushStroke(heightmap, brush); } void terrainBrushAddNoise(TerrainHeightMap* heightmap, TerrainBrush* brush, NoiseGenerator* generator, double value) { + _prepareBrushStroke(heightmap, brush); } void terrainBrushReset(TerrainHeightMap* heightmap, TerrainBrush* brush, double value) diff --git a/lib_paysages/terrain/presets.c b/lib_paysages/terrain/presets.c index a6c731c..590bd32 100644 --- a/lib_paysages/terrain/presets.c +++ b/lib_paysages/terrain/presets.c @@ -7,14 +7,15 @@ void terrainAutoPreset(TerrainDefinition* definition, TerrainPreset preset) { + int resolution = 8; switch (preset) { case TERRAIN_PRESET_STANDARD: noiseClearLevels(definition->_height_noise); - noiseAddLevelsSimple(definition->_height_noise, 8, 12.8, 12.8); /* Detail = 0.1 */ + noiseAddLevelsSimple(definition->_height_noise, resolution, pow(2.0, resolution - 1), 25.0); noiseSetFunctionParams(definition->_height_noise, NOISE_FUNCTION_SIMPLEX, 0.0); - definition->height = 2.0; - definition->scaling = 10.0; + definition->scaling = 1.0; + definition->height = 1.0; definition->shadow_smoothing = 0.03; break; default: diff --git a/lib_paysages/terrain/preview.c b/lib_paysages/terrain/preview.c index 0c68067..b764d37 100644 --- a/lib_paysages/terrain/preview.c +++ b/lib_paysages/terrain/preview.c @@ -88,7 +88,7 @@ Color terrainGetPreviewColor(Renderer* renderer, double x, double z, double deta Vector3 point; point.x = x; - point.y = renderer->terrain->getHeight(renderer, x, z); + point.y = renderer->terrain->getHeight(renderer, x, z, 1); point.z = z; return renderer->terrain->getFinalColor(renderer, point, detail); diff --git a/lib_paysages/terrain/private.h b/lib_paysages/terrain/private.h index 2439925..45b7857 100644 --- a/lib_paysages/terrain/private.h +++ b/lib_paysages/terrain/private.h @@ -3,14 +3,12 @@ #include "public.h" -#define TERRAIN_HEIGHTMAP_DETAIL 0.1 - typedef struct { int xstart; - int ystart; + int zstart; int xsize; - int ysize; + int zsize; double* data; } TerrainHeightMapData; @@ -27,5 +25,6 @@ void terrainHeightmapDelete(TerrainHeightMap* heightmap); void terrainHeightmapCopy(TerrainHeightMap* source, TerrainHeightMap* destination); void terrainHeightmapSave(PackStream* stream, TerrainHeightMap* heightmap); void terrainHeightmapLoad(PackStream* stream, TerrainHeightMap* heightmap); +int terrainHeightmapGetHeight(TerrainHeightMap* heightmap, double x, double z, double* result); #endif diff --git a/lib_paysages/terrain/public.h b/lib_paysages/terrain/public.h index dd9c9a0..569d6f6 100644 --- a/lib_paysages/terrain/public.h +++ b/lib_paysages/terrain/public.h @@ -30,7 +30,7 @@ typedef struct double _max_height; } TerrainDefinition; -typedef double (*FuncTerrainGetHeight)(Renderer* renderer, double x, double z); +typedef double (*FuncTerrainGetHeight)(Renderer* renderer, double x, double z, int with_painting); typedef Color (*FuncTerrainGetFinalColor)(Renderer* renderer, Vector3 location, double precision); typedef struct @@ -50,6 +50,7 @@ extern StandardRenderer TerrainRendererClass; void terrainAutoPreset(TerrainDefinition* definition, TerrainPreset preset); void terrainRenderSurface(Renderer* renderer); +double terrainGetGridHeight(TerrainDefinition* definition, int x, int z, int with_painting); Renderer terrainCreatePreviewRenderer(); Color terrainGetPreviewColor(Renderer* renderer, double x, double z, double detail); diff --git a/lib_paysages/terrain/raster.c b/lib_paysages/terrain/raster.c index d4f8616..7a3efb9 100644 --- a/lib_paysages/terrain/raster.c +++ b/lib_paysages/terrain/raster.c @@ -13,7 +13,7 @@ static inline Vector3 _getPoint(TerrainDefinition* definition, Renderer* rendere Vector3 result; result.x = x; - result.y = renderer->terrain->getHeight(renderer, x, z); + result.y = renderer->terrain->getHeight(renderer, x, z, 1); result.z = z; return result; diff --git a/lib_paysages/textures.c b/lib_paysages/textures.c index 8378ef8..cb4c5c8 100644 --- a/lib_paysages/textures.c +++ b/lib_paysages/textures.c @@ -178,25 +178,25 @@ static inline TextureResult _getTerrainResult(Renderer* renderer, double x, doub center.x = x; center.z = z; - center.y = renderer->terrain->getHeight(renderer, center.x, center.z); + center.y = renderer->terrain->getHeight(renderer, center.x, center.z, 1); east.x = x + detail; east.z = z; - east.y = renderer->terrain->getHeight(renderer, east.x, east.z); + east.y = renderer->terrain->getHeight(renderer, east.x, east.z, 1); south.x = x; south.z = z + detail; - south.y = renderer->terrain->getHeight(renderer, south.x, south.z); + south.y = renderer->terrain->getHeight(renderer, south.x, south.z, 1); if (renderer->render_quality > 5) { west.x = x - detail; west.z = z; - west.y = renderer->terrain->getHeight(renderer, west.x, west.z); + west.y = renderer->terrain->getHeight(renderer, west.x, west.z, 1); north.x = x; north.z = z - detail; - north.y = renderer->terrain->getHeight(renderer, north.x, north.z); + north.y = renderer->terrain->getHeight(renderer, north.x, north.z, 1); result.normal = _getNormal4(center, north, east, south, west); }