paysages3d/lib_paysages/terrain/raster.c
2013-01-19 22:42:50 +00:00

100 lines
3.1 KiB
C

#include "public.h"
#include "private.h"
#include <stdlib.h>
#include "../renderer.h"
/*
* Terrain rasterization.
*/
static inline Vector3 _getPoint(TerrainDefinition* definition, Renderer* renderer, double x, double z)
{
Vector3 result;
result.x = x;
result.y = renderer->terrain->getHeight(renderer, x, z, 1);
result.z = z;
return result;
}
static Color _postProcessFragment(Renderer* renderer, Vector3 point, void* data)
{
double precision;
point = _getPoint(renderer->terrain->definition, renderer, point.x, point.z);
precision = renderer->getPrecision(renderer, point);
return renderer->terrain->getFinalColor(renderer, point, precision);
}
static void _renderQuad(TerrainDefinition* definition, Renderer* renderer, double x, double z, double size, double water_height)
{
Vector3 v1, v2, v3, v4;
v1 = _getPoint(definition, renderer, x, z);
v2 = _getPoint(definition, renderer, x, z + size);
v3 = _getPoint(definition, renderer, x + size, z + size);
v4 = _getPoint(definition, renderer, x + size, z);
if (v1.y > water_height || v2.y > water_height || v3.y > water_height || v4.y > water_height)
{
renderer->pushQuad(renderer, v1, v2, v3, v4, _postProcessFragment, NULL);
}
}
void terrainRenderSurface(Renderer* renderer)
{
int chunk_factor, chunk_count, i;
double cx = renderer->camera_location.x;
double cz = renderer->camera_location.z;
double min_chunk_size, visible_chunk_size;
double radius_int, radius_ext, chunk_size;
double water_height;
TerrainDefinition* definition = renderer->terrain->definition;
min_chunk_size = 0.1 / (double)renderer->render_quality;
visible_chunk_size = 0.05 / (double)renderer->render_quality;
if (renderer->render_quality > 7)
{
min_chunk_size *= 0.5;
visible_chunk_size *= 0.5;
}
chunk_factor = 1;
chunk_count = 2;
radius_int = 0.0;
radius_ext = min_chunk_size;
chunk_size = min_chunk_size;
water_height = renderer->getWaterHeightInfo(renderer).max_height;
while (radius_int < 5000.0)
{
if (!renderer->addRenderProgress(renderer, 0.0))
{
return;
}
for (i = 0; i < chunk_count - 1; i++)
{
_renderQuad(definition, renderer, cx - radius_ext + chunk_size * i, cz - radius_ext, chunk_size, water_height);
_renderQuad(definition, renderer, cx + radius_int, cz - radius_ext + chunk_size * i, chunk_size, water_height);
_renderQuad(definition, renderer, cx + radius_int - chunk_size * i, cz + radius_int, chunk_size, water_height);
_renderQuad(definition, renderer, cx - radius_ext, cz + radius_int - chunk_size * i, chunk_size, water_height);
}
if (chunk_count % 64 == 0 && chunk_size / radius_int < visible_chunk_size)
{
chunk_count /= 2;
chunk_factor *= 2;
/* TODO Fill in gaps with triangles */
}
chunk_count += 2;
chunk_size = min_chunk_size * chunk_factor;
radius_int = radius_ext;
radius_ext += chunk_size;
}
}