paysages : Now the terrain leads the water height (relative to terrain scaling).
git-svn-id: https://subversion.assembla.com/svn/thunderk/paysages@569 b1fd45b6-86a6-48da-8261-f70d1f35bdcc
This commit is contained in:
parent
b5b3e401db
commit
e820d336a8
14 changed files with 432 additions and 381 deletions
|
@ -121,10 +121,15 @@ protected:
|
||||||
cameraSetLocation(_renderer->render_camera, camera_location);
|
cameraSetLocation(_renderer->render_camera, camera_location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static double _getWaterHeight(Renderer* renderer)
|
||||||
|
{
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
void updateData()
|
void updateData()
|
||||||
{
|
{
|
||||||
WaterRendererClass.bind(_renderer, _definition);
|
WaterRendererClass.bind(_renderer, _definition);
|
||||||
_renderer->water->definition->height = 0.0;
|
_renderer->terrain->getWaterHeight = _getWaterHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
void choiceChangeEvent(const QString& key, int position)
|
void choiceChangeEvent(const QString& key, int position)
|
||||||
|
@ -234,7 +239,7 @@ BaseForm(parent)
|
||||||
addPreview(previewCoverage, tr("Coverage preview"));
|
addPreview(previewCoverage, tr("Coverage preview"));
|
||||||
addPreview(previewColor, tr("Rendered 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);
|
addInputMaterial(tr("Surface material"), &_definition->material);
|
||||||
addInputColor(tr("Depth color"), &_definition->depth_color);
|
addInputColor(tr("Depth color"), &_definition->depth_color);
|
||||||
addInputDouble(tr("Transparency"), &_definition->transparency, 0.0, 1.0, 0.001, 0.1);
|
addInputDouble(tr("Transparency"), &_definition->transparency, 0.0, 1.0, 0.001, 0.1);
|
||||||
|
|
|
@ -20,8 +20,9 @@ MainTerrainForm::MainTerrainForm(QWidget *parent) :
|
||||||
_form_helper->addPreview("preview_shape", _renderer_shape);
|
_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_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_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->setApplyButton("button_apply");
|
||||||
_form_helper->setRevertButton("button_revert");
|
_form_helper->setRevertButton("button_revert");
|
||||||
|
|
|
@ -250,7 +250,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="WidgetSliderDecimal" name="horizontalSlider_4">
|
<widget class="WidgetSliderDecimal" name="input_water_height">
|
||||||
<property name="maximumSize">
|
<property name="maximumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>400</width>
|
<width>400</width>
|
||||||
|
|
|
@ -399,13 +399,14 @@ void WidgetExplorer::paintGL()
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
// Render water
|
// Render water
|
||||||
|
double water_height = _renderer->terrain->getWaterHeight(_renderer);
|
||||||
glDisable(GL_TEXTURE_2D);
|
glDisable(GL_TEXTURE_2D);
|
||||||
glColor3f(water->material.base.r, water->material.base.g, water->material.base.b);
|
glColor3f(water->material.base.r, water->material.base.g, water->material.base.b);
|
||||||
glBegin(GL_QUADS);
|
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();
|
glEnd();
|
||||||
|
|
||||||
// Render chunks
|
// Render chunks
|
||||||
|
|
|
@ -27,9 +27,9 @@ QGLWidget(parent)
|
||||||
|
|
||||||
_water = true;
|
_water = true;
|
||||||
_wireframe = true;
|
_wireframe = true;
|
||||||
WaterDefinition* water_definition = (WaterDefinition*) WaterDefinitionClass.create();
|
WaterDefinition* water_definition = (WaterDefinition*)WaterDefinitionClass.create();
|
||||||
sceneryGetWater(water_definition);
|
sceneryGetWater(water_definition);
|
||||||
_water_height = water_definition->height;
|
_water_height = _renderer->terrain->getWaterHeight(_renderer);
|
||||||
WaterDefinitionClass.destroy(water_definition);
|
WaterDefinitionClass.destroy(water_definition);
|
||||||
|
|
||||||
_average_frame_time = 0.0;
|
_average_frame_time = 0.0;
|
||||||
|
@ -74,6 +74,7 @@ void WidgetHeightMap::setTerrain(TerrainDefinition* terrain)
|
||||||
{
|
{
|
||||||
_terrain = terrain;
|
_terrain = terrain;
|
||||||
TerrainRendererClass.bind(_renderer, _terrain);
|
TerrainRendererClass.bind(_renderer, _terrain);
|
||||||
|
_water_height = _renderer->terrain->getWaterHeight(_renderer);
|
||||||
|
|
||||||
revert();
|
revert();
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,8 @@ typedef struct
|
||||||
|
|
||||||
TerrainHeightMap* height_map;
|
TerrainHeightMap* height_map;
|
||||||
|
|
||||||
|
double water_height;
|
||||||
|
|
||||||
double _detail;
|
double _detail;
|
||||||
NoiseGenerator* _height_noise;
|
NoiseGenerator* _height_noise;
|
||||||
double _min_height;
|
double _min_height;
|
||||||
|
@ -40,7 +42,8 @@ typedef struct
|
||||||
|
|
||||||
typedef double (*FuncTerrainGetHeight)(Renderer* renderer, double x, double z, int with_painting);
|
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 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
|
typedef struct
|
||||||
{
|
{
|
||||||
|
@ -50,6 +53,7 @@ typedef struct
|
||||||
FuncTerrainGetHeight getHeight;
|
FuncTerrainGetHeight getHeight;
|
||||||
FuncTerrainGetResult getResult;
|
FuncTerrainGetResult getResult;
|
||||||
FuncTerrainGetFinalColor getFinalColor;
|
FuncTerrainGetFinalColor getFinalColor;
|
||||||
|
FuncGetWaterHeight getWaterHeight;
|
||||||
|
|
||||||
void* _internal_data;
|
void* _internal_data;
|
||||||
} TerrainRenderer;
|
} TerrainRenderer;
|
||||||
|
|
|
@ -10,10 +10,17 @@ static void _validateDefinition(TerrainDefinition* definition)
|
||||||
{
|
{
|
||||||
noiseValidate(definition->_height_noise);
|
noiseValidate(definition->_height_noise);
|
||||||
|
|
||||||
|
if (definition->height < 1.0)
|
||||||
|
{
|
||||||
|
definition->height = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Get minimal and maximal height */
|
/* Get minimal and maximal height */
|
||||||
noiseGetRange(definition->_height_noise, &definition->_min_height, &definition->_max_height);
|
noiseGetRange(definition->_height_noise, &definition->_min_height, &definition->_max_height);
|
||||||
definition->_min_height *= definition->height;
|
definition->_min_height *= definition->height * definition->scaling;
|
||||||
definition->_max_height *= definition->height;
|
definition->_max_height *= definition->height * definition->scaling;
|
||||||
|
|
||||||
|
/* TODO Alter with heightmap min/max */
|
||||||
}
|
}
|
||||||
|
|
||||||
static TerrainDefinition* _createDefinition()
|
static TerrainDefinition* _createDefinition()
|
||||||
|
@ -26,6 +33,8 @@ static TerrainDefinition* _createDefinition()
|
||||||
|
|
||||||
definition->height_map = terrainHeightMapCreate(definition);
|
definition->height_map = terrainHeightMapCreate(definition);
|
||||||
|
|
||||||
|
definition->water_height = -0.8;
|
||||||
|
|
||||||
definition->_height_noise = noiseCreateGenerator();
|
definition->_height_noise = noiseCreateGenerator();
|
||||||
|
|
||||||
terrainAutoPreset(definition, TERRAIN_PRESET_STANDARD);
|
terrainAutoPreset(definition, TERRAIN_PRESET_STANDARD);
|
||||||
|
@ -48,6 +57,8 @@ static void _copyDefinition(TerrainDefinition* source, TerrainDefinition* destin
|
||||||
|
|
||||||
terrainHeightmapCopy(source->height_map, destination->height_map);
|
terrainHeightmapCopy(source->height_map, destination->height_map);
|
||||||
|
|
||||||
|
destination->water_height = source->water_height;
|
||||||
|
|
||||||
noiseCopy(source->_height_noise, destination->_height_noise);
|
noiseCopy(source->_height_noise, destination->_height_noise);
|
||||||
|
|
||||||
_validateDefinition(destination);
|
_validateDefinition(destination);
|
||||||
|
@ -59,6 +70,7 @@ static void _saveDefinition(PackStream* stream, TerrainDefinition* definition)
|
||||||
packWriteDouble(stream, &definition->scaling);
|
packWriteDouble(stream, &definition->scaling);
|
||||||
packWriteDouble(stream, &definition->shadow_smoothing);
|
packWriteDouble(stream, &definition->shadow_smoothing);
|
||||||
terrainHeightmapSave(stream, definition->height_map);
|
terrainHeightmapSave(stream, definition->height_map);
|
||||||
|
packWriteDouble(stream, &definition->water_height);
|
||||||
noiseSaveGenerator(stream, definition->_height_noise);
|
noiseSaveGenerator(stream, definition->_height_noise);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +80,7 @@ static void _loadDefinition(PackStream* stream, TerrainDefinition* definition)
|
||||||
packReadDouble(stream, &definition->scaling);
|
packReadDouble(stream, &definition->scaling);
|
||||||
packReadDouble(stream, &definition->shadow_smoothing);
|
packReadDouble(stream, &definition->shadow_smoothing);
|
||||||
terrainHeightmapLoad(stream, definition->height_map);
|
terrainHeightmapLoad(stream, definition->height_map);
|
||||||
|
packReadDouble(stream, &definition->water_height);
|
||||||
noiseLoadGenerator(stream, definition->_height_noise);
|
noiseLoadGenerator(stream, definition->_height_noise);
|
||||||
|
|
||||||
_validateDefinition(definition);
|
_validateDefinition(definition);
|
||||||
|
@ -82,294 +95,6 @@ StandardDefinition TerrainDefinitionClass = {
|
||||||
(FuncObjectLoad)_loadDefinition
|
(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 ********************/
|
/******************** Public tools ********************/
|
||||||
double terrainGetGridHeight(TerrainDefinition* definition, int x, int z, int with_painting)
|
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);
|
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)
|
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;
|
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
|
|
||||||
};
|
|
||||||
|
|
|
@ -307,12 +307,12 @@ static double* _getDataPointer(HeightMapData* data, int x, int z, HeightMapData*
|
||||||
}
|
}
|
||||||
else if (terrain)
|
else if (terrain)
|
||||||
{
|
{
|
||||||
*pixel = terrainGetGridHeight(terrain, x, z, 0);
|
*pixel = terrainGetGridHeight(terrain, x, z, 0) / (terrain->height * terrain->scaling);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (terrain)
|
else if (terrain)
|
||||||
{
|
{
|
||||||
*pixel = terrainGetGridHeight(terrain, x, z, 0);
|
*pixel = terrainGetGridHeight(terrain, x, z, 0) / (terrain->height * terrain->scaling);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pixel;
|
return pixel;
|
||||||
|
@ -411,7 +411,7 @@ int terrainHeightmapGetInterpolatedHeight(TerrainHeightMap* heightmap, double x,
|
||||||
{
|
{
|
||||||
if (!terrainHeightmapGetGridHeight(heightmap, ix, iz, &value))
|
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;
|
stencil[(iz - (zlow - 1)) * 4 + ix - (xlow - 1)] = value;
|
||||||
}
|
}
|
||||||
|
@ -462,6 +462,8 @@ static inline void _applyBrush(TerrainHeightMap* heightmap, TerrainBrush* brush,
|
||||||
int x, z;
|
int x, z;
|
||||||
double dx, dz, distance, influence;
|
double dx, dz, distance, influence;
|
||||||
|
|
||||||
|
force /= (heightmap->terrain->height * heightmap->terrain->scaling);
|
||||||
|
|
||||||
for (x = brush_rect.xstart; x <= brush_rect.xend; x++)
|
for (x = brush_rect.xstart; x <= brush_rect.xend; x++)
|
||||||
{
|
{
|
||||||
dx = (double)x;
|
dx = (double)x;
|
||||||
|
|
|
@ -11,19 +11,19 @@ void terrainAutoPreset(TerrainDefinition* definition, TerrainPreset preset)
|
||||||
int resolution = 8;
|
int resolution = 8;
|
||||||
switch (preset)
|
switch (preset)
|
||||||
{
|
{
|
||||||
case TERRAIN_PRESET_STANDARD:
|
case TERRAIN_PRESET_STANDARD:
|
||||||
noiseRandomizeOffsets(definition->_height_noise);
|
noiseRandomizeOffsets(definition->_height_noise);
|
||||||
noiseClearLevels(definition->_height_noise);
|
noiseClearLevels(definition->_height_noise);
|
||||||
noiseAddLevelSimple(definition->_height_noise, pow(2.0, resolution + 1), -15.0, 15.0);
|
noiseAddLevelSimple(definition->_height_noise, pow(2.0, resolution + 1), -1.0, 1.0);
|
||||||
noiseAddLevelsSimple(definition->_height_noise, resolution - 2, pow(2.0, resolution - 1), -10.0, 10.0, 0.5);
|
noiseAddLevelsSimple(definition->_height_noise, resolution - 2, pow(2.0, resolution - 1), -0.7, 0.7, 0.5);
|
||||||
noiseNormalizeAmplitude(definition->_height_noise, -15.0, 15.0, 0);
|
noiseNormalizeAmplitude(definition->_height_noise, -1.0, 1.0, 0);
|
||||||
noiseSetFunctionParams(definition->_height_noise, NOISE_FUNCTION_SIMPLEX, 0.0, 0.0);
|
noiseSetFunctionParams(definition->_height_noise, NOISE_FUNCTION_SIMPLEX, 0.0, 0.0);
|
||||||
definition->scaling = 1.0;
|
definition->scaling = 1.0;
|
||||||
definition->height = 1.0;
|
definition->height = 15.0;
|
||||||
definition->shadow_smoothing = 0.03;
|
definition->shadow_smoothing = 0.03;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
TerrainDefinitionClass.validate(definition);
|
TerrainDefinitionClass.validate(definition);
|
||||||
|
|
350
src/rendering/terrain/ter_render.c
Normal file
350
src/rendering/terrain/ter_render.c
Normal file
|
@ -0,0 +1,350 @@
|
||||||
|
#include "private.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#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
|
||||||
|
};
|
||||||
|
|
|
@ -20,7 +20,6 @@ typedef enum
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
double height;
|
|
||||||
double transparency;
|
double transparency;
|
||||||
double reflection;
|
double reflection;
|
||||||
SurfaceMaterial material;
|
SurfaceMaterial material;
|
||||||
|
|
|
@ -22,7 +22,6 @@ static WaterDefinition* _createDefinition()
|
||||||
{
|
{
|
||||||
WaterDefinition* definition = malloc(sizeof(WaterDefinition));
|
WaterDefinition* definition = malloc(sizeof(WaterDefinition));
|
||||||
|
|
||||||
definition->height = -4.0;
|
|
||||||
definition->_waves_noise = noiseCreateGenerator();
|
definition->_waves_noise = noiseCreateGenerator();
|
||||||
|
|
||||||
waterAutoPreset(definition, WATER_PRESET_LAKE);
|
waterAutoPreset(definition, WATER_PRESET_LAKE);
|
||||||
|
@ -48,7 +47,6 @@ static void _copyDefinition(WaterDefinition* source, WaterDefinition* destinatio
|
||||||
|
|
||||||
static void _saveDefinition(PackStream* stream, WaterDefinition* definition)
|
static void _saveDefinition(PackStream* stream, WaterDefinition* definition)
|
||||||
{
|
{
|
||||||
packWriteDouble(stream, &definition->height);
|
|
||||||
materialSave(stream, &definition->material);
|
materialSave(stream, &definition->material);
|
||||||
colorSave(stream, &definition->depth_color);
|
colorSave(stream, &definition->depth_color);
|
||||||
packWriteDouble(stream, &definition->transparency_depth);
|
packWriteDouble(stream, &definition->transparency_depth);
|
||||||
|
@ -69,7 +67,6 @@ static void _saveDefinition(PackStream* stream, WaterDefinition* definition)
|
||||||
|
|
||||||
static void _loadDefinition(PackStream* stream, WaterDefinition* definition)
|
static void _loadDefinition(PackStream* stream, WaterDefinition* definition)
|
||||||
{
|
{
|
||||||
packReadDouble(stream, &definition->height);
|
|
||||||
materialLoad(stream, &definition->material);
|
materialLoad(stream, &definition->material);
|
||||||
colorLoad(stream, &definition->depth_color);
|
colorLoad(stream, &definition->depth_color);
|
||||||
packReadDouble(stream, &definition->transparency_depth);
|
packReadDouble(stream, &definition->transparency_depth);
|
||||||
|
|
|
@ -14,7 +14,7 @@ Color waterGetPreviewCoverage(Renderer* renderer, double x, double y, double sca
|
||||||
double height;
|
double height;
|
||||||
|
|
||||||
height = renderer->terrain->getHeight(renderer, x, y, 1);
|
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);
|
return terrainGetPreviewColor(renderer, x, y, scaling);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,12 +42,12 @@ static WaterResult _fakeGetResult(Renderer* renderer, double x, double z)
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************** Helpers ********************/
|
/******************** 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;
|
Vector3 back, right;
|
||||||
double x, z;
|
double x, z;
|
||||||
|
@ -56,12 +56,12 @@ static inline Vector3 _getNormal(WaterDefinition* definition, Vector3 base, doub
|
||||||
z = base.z;
|
z = base.z;
|
||||||
|
|
||||||
back.x = x;
|
back.x = x;
|
||||||
back.y = _getHeight(definition, x, z + detail);
|
back.y = _getHeight(definition, base_height, x, z + detail);
|
||||||
back.z = z + detail;
|
back.z = z + detail;
|
||||||
back = v3Sub(back, base);
|
back = v3Sub(back, base);
|
||||||
|
|
||||||
right.x = x + detail;
|
right.x = x + detail;
|
||||||
right.y = _getHeight(definition, x + detail, z);
|
right.y = _getHeight(definition, base_height, x + detail, z);
|
||||||
right.z = z;
|
right.z = z;
|
||||||
right = v3Sub(right, base);
|
right = v3Sub(right, base);
|
||||||
|
|
||||||
|
@ -97,31 +97,33 @@ static inline Color _getFoamMask(Renderer* renderer, WaterDefinition* definition
|
||||||
{
|
{
|
||||||
Color result;
|
Color result;
|
||||||
double foam_factor, normal_diff, location_offset;
|
double foam_factor, normal_diff, location_offset;
|
||||||
|
double base_height;
|
||||||
|
|
||||||
|
base_height = renderer->terrain->getWaterHeight(renderer);
|
||||||
location_offset = 2.0 * detail;
|
location_offset = 2.0 * detail;
|
||||||
|
|
||||||
foam_factor = 0.0;
|
foam_factor = 0.0;
|
||||||
location.x += location_offset;
|
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)
|
if (normal_diff > foam_factor)
|
||||||
{
|
{
|
||||||
foam_factor = normal_diff;
|
foam_factor = normal_diff;
|
||||||
}
|
}
|
||||||
location.x -= location_offset * 2.0;
|
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)
|
if (normal_diff > foam_factor)
|
||||||
{
|
{
|
||||||
foam_factor = normal_diff;
|
foam_factor = normal_diff;
|
||||||
}
|
}
|
||||||
location.x += location_offset;
|
location.x += location_offset;
|
||||||
location.z -= 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)
|
if (normal_diff > foam_factor)
|
||||||
{
|
{
|
||||||
foam_factor = normal_diff;
|
foam_factor = normal_diff;
|
||||||
}
|
}
|
||||||
location.z += location_offset * 2.0;
|
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)
|
if (normal_diff > foam_factor)
|
||||||
{
|
{
|
||||||
foam_factor = normal_diff;
|
foam_factor = normal_diff;
|
||||||
|
@ -162,12 +164,14 @@ static int _alterLight(Renderer* renderer, LightDefinition* light, Vector3 at)
|
||||||
{
|
{
|
||||||
WaterDefinition* definition = renderer->water->definition;
|
WaterDefinition* definition = renderer->water->definition;
|
||||||
double factor;
|
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)
|
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)
|
if (factor > 1.0)
|
||||||
{
|
{
|
||||||
factor = 1.0;
|
factor = 1.0;
|
||||||
|
@ -200,17 +204,17 @@ static HeightInfo _realGetHeightInfo(Renderer* renderer)
|
||||||
HeightInfo info;
|
HeightInfo info;
|
||||||
double noise_minvalue, noise_maxvalue;
|
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);
|
noiseGetRange(definition->_waves_noise, &noise_minvalue, &noise_maxvalue);
|
||||||
info.min_height = definition->height + noise_minvalue;
|
info.min_height = info.base_height + noise_minvalue;
|
||||||
info.max_height = definition->height + noise_maxvalue;
|
info.max_height = info.base_height + noise_maxvalue;
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
static double _realGetHeight(Renderer* renderer, double x, double z)
|
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)
|
static WaterResult _realGetResult(Renderer* renderer, double x, double z)
|
||||||
|
@ -220,10 +224,12 @@ static WaterResult _realGetResult(Renderer* renderer, double x, double z)
|
||||||
RayCastingResult refracted;
|
RayCastingResult refracted;
|
||||||
Vector3 location, normal, look_direction;
|
Vector3 location, normal, look_direction;
|
||||||
Color color, foam;
|
Color color, foam;
|
||||||
double detail, depth;
|
double base_height, detail, depth;
|
||||||
|
|
||||||
|
base_height = renderer->terrain->getWaterHeight(renderer);
|
||||||
|
|
||||||
location.x = x;
|
location.x = x;
|
||||||
location.y = _getHeight(definition, x, z);
|
location.y = _getHeight(definition, base_height, x, z);
|
||||||
location.z = z;
|
location.z = z;
|
||||||
result.location = location;
|
result.location = location;
|
||||||
|
|
||||||
|
@ -233,7 +239,7 @@ static WaterResult _realGetResult(Renderer* renderer, double x, double z)
|
||||||
detail = 0.00001;
|
detail = 0.00001;
|
||||||
}
|
}
|
||||||
|
|
||||||
normal = _getNormal(definition, location, detail);
|
normal = _getNormal(definition, base_height, location, detail);
|
||||||
look_direction = v3Normalize(v3Sub(location, renderer->getCameraLocation(renderer, location)));
|
look_direction = v3Normalize(v3Sub(location, renderer->getCameraLocation(renderer, location)));
|
||||||
|
|
||||||
/* Reflection */
|
/* Reflection */
|
||||||
|
|
Loading…
Reference in a new issue