openclonk/planet/Graphics.ocg/LandscapeShader.c

118 lines
3.9 KiB
C

#version 110
// Input textures
uniform sampler2D landscapeTex[1];
uniform sampler2D scalerTex;
uniform sampler3D materialTex;
// Resolution of the landscape texture
uniform vec2 resolution;
// Texture map
#ifdef BROKEN_ARRAYS_WORKAROUND
uniform sampler1D matMapTex;
#else
uniform float matMap[256];
#endif
uniform int materialDepth;
// Expected parameters for the scaler
const vec2 scalerStepX = vec2(1.0 / 8.0, 0.0);
const vec2 scalerStepY = vec2(0.0, 1.0 / 32.0);
const vec2 scalerOffset = scalerStepX / 3.0 + scalerStepY / 3.0;
const vec2 scalerPixel = vec2(scalerStepX.x, scalerStepY.y) / 3.0;
#ifdef NO_TEXTURE_LOD_IN_FRAGMENT
#define texture1DLod(t,c,l) texture1D(t,c)
#define texture2DLod(t,c,l) texture2D(t,c)
#endif
// Converts the pixel range 0.0..1.0 into the integer range 0..255
int f2i(float x) {
return int(x * 255.9);
}
float queryMatMap(int pix)
{
#ifdef BROKEN_ARRAYS_WORKAROUND
int idx = f2i(texture1D(matMapTex, float(pix) / 256.0 + 0.5 / 256.0).r);
return float(idx) / 256.0 + 0.5 / float(materialDepth);
#else
return matMap[pix];
#endif
}
void main()
{
// full pixel steps in the landscape texture (depends on landscape resolution)
vec2 fullStep = vec2(1.0, 1.0) / resolution;
vec2 fullStepX = vec2(fullStep.x, 0.0);
vec2 fullStepY = vec2(0.0, fullStep.y);
// calculate pixel position in landscape, find center of current pixel
vec2 pixelCoo = gl_TexCoord[0].st * resolution;
vec2 centerCoo = (floor(pixelCoo) + vec2(0.5, 0.5)) / resolution;
// our pixel color (with and without interpolation)
vec4 lpx = texture2D(landscapeTex[0], centerCoo);
vec4 rlpx = texture2D(landscapeTex[0], gl_TexCoord[0].st);
// find scaler coordinate
vec2 scalerCoo = scalerOffset + mod(pixelCoo, vec2(1.0, 1.0)) * scalerPixel;
#ifdef SCALER_IN_GPU
if(texture2D(landscapeTex[0], centerCoo - fullStepX - fullStepY).r == lpx.r)
scalerCoo += scalerStepX;
if(texture2D(landscapeTex[0], centerCoo - fullStepY).r == lpx.r)
scalerCoo += 2.0 * scalerStepX;
if(texture2D(landscapeTex[0], centerCoo + fullStepX - fullStepY).r == lpx.r)
scalerCoo += 4.0 * scalerStepX;
if(texture2D(landscapeTex[0], centerCoo - fullStepX ).r == lpx.r)
scalerCoo += scalerStepY;
if(texture2D(landscapeTex[0], centerCoo + fullStepX ).r == lpx.r)
scalerCoo += 2.0 * scalerStepY;
if(texture2D(landscapeTex[0], centerCoo - fullStepX + fullStepY).r == lpx.r)
scalerCoo += 4.0 * scalerStepY;
if(texture2D(landscapeTex[0], centerCoo + fullStepY).r == lpx.r)
scalerCoo += 8.0 * scalerStepY;
if(texture2D(landscapeTex[0], centerCoo + fullStepX + fullStepY).r == lpx.r)
scalerCoo += 16.0 * scalerStepY;
#else
int iScaler = f2i(lpx.a), iRow = iScaler / 8;
scalerCoo.x += float(iScaler - iRow * 8) / 8.0;
scalerCoo.y += float(iScaler / 8) / 32.0;
#endif
// Note: scalerCoo will jump around a lot, causing some GPUs to apparantly get confused with
// the level-of-detail calculation. We therefore try to disable LOD.
vec4 spx = texture2DLod(scalerTex, scalerCoo, 0.0);
// gen3 other coordinate calculation. Still struggles a bit with 3-ways
vec2 otherCoo = centerCoo + fullStep * floor(vec2(-0.5, -0.5) + spx.gb * 255.0 / 64.0);
vec4 lopx = texture2D(landscapeTex[0], otherCoo);
// Get material pixels
float mi = queryMatMap(f2i(lpx.r));
vec4 mpx = texture3D(materialTex, vec3(gl_TexCoord[0].st * resolution / vec2(512.0, 512.0) * vec2(4.0, 4.0), mi));
float omi = queryMatMap(f2i(lopx.r));
vec4 ompx = texture3D(materialTex, vec3(gl_TexCoord[0].st * resolution / vec2(512.0, 512.0) * vec2(4.0, 4.0), omi));
// Brightness
float ambientBright = 1.0, shadeBright = 0.8;
vec2 normal = (2.0 * mix(rlpx.yz, lpx.yz, spx.a) - vec2(1.0, 1.0));
vec2 normal2 = (2.0 * lopx.yz - vec2(1.0, 1.0));
float bright = ambientBright + shadeBright * dot(normal, vec2(0.0, -1.0));
float bright2 = ambientBright + shadeBright * dot(normal2, vec2(0.0, -1.0));
gl_FragColor = mix(
vec4(bright2 * ompx.rgb, ompx.a),
vec4(bright * mpx.rgb, mpx.a),
spx.r);
}