uniform vec2 uGridSizeRCP;
uniform vec3 uVecU;
uniform vec3 uVecV;

out vec3 vPosition;
out vec3 vObjPos;
out vec2 vHeightTexCoord, vValueTexCoord;
out vec2 vTexCoordFull;
out vec2 vCullQuads;
out vec2 vLimit;

uniform sampler2D HeightTex;
uniform sampler2D PropertyTex1;
uniform vec2 cHeightNormalizationOffsetScale;

uniform ivec2 cPatchPosition, cPatchSize;
uniform ivec2 cVertexCullLimit;
uniform ivec4 cLodGlueSnap;
uniform ivec2 cHeightPos, cValuePos;
uniform int nLODStep;

in vec2 cVertexPosition;

void main()
{
  vec3 pos;
  pos.xy = cVertexPosition;

  // snap y-coordinates for x-gluing
  pos.y = cVertexPosition.x < 0.5                  ? ceil(pos.y / cLodGlueSnap.x) * cLodGlueSnap.x : pos.y;
  pos.y = cVertexPosition.x > (cPatchSize.x - 0.5) ? ceil(pos.y / cLodGlueSnap.y) * cLodGlueSnap.y : pos.y;

  // snap x-coordinates for y-gluing
  pos.x = cVertexPosition.y < 0.5                  ? ceil(pos.x / cLodGlueSnap.z) * cLodGlueSnap.z : pos.x;
  pos.x = cVertexPosition.y > (cPatchSize.y - 0.5) ? ceil(pos.x / cLodGlueSnap.w) * cLodGlueSnap.w : pos.x;

  pos.xy = min(pos.xy, vec2(cPatchSize));

  vHeightTexCoord = pos.xy + cHeightPos + 0.5;
  vValueTexCoord = (pos.xy + cValuePos + 0.5) / textureSize(PropertyTex1, 0);

  vCullQuads = pos.xy / nLODStep;
  vLimit = vec2(cPatchSize) + cHeightPos.xy + 0.5;

  pos.xy += vec2(cPatchPosition.xy);
  vec2 temp = (pos.xy * uGridSizeRCP) + vec2(uVecU.z, uVecV.z);
  vTexCoordFull.x = dot(temp, uVecU.xy);
  vTexCoordFull.y = dot(temp, uVecV.xy);

  pos.z = texelFetch(HeightTex, ivec2(vHeightTexCoord), 0).r;
  if (cVertexPosition.x > cVertexCullLimit.x || cVertexPosition.y > cVertexCullLimit.y || // edge-cull
      !IsHeightValid(pos.z)) // height-cull
  {
    gl_Position = vec4(0.0, 0.0, 1.0, 0.0); // discard vertex (and by extension all triangles that use it)
  }
  else
  {
    pos.z = (pos.z + cHeightNormalizationOffsetScale.x) * cHeightNormalizationOffsetScale.y;
    gl_Position = gl_ModelViewProjectionMatrix * vec4(pos, 1.0);
    gl_ClipVertex = gl_ModelViewMatrix * vec4(pos, 1.0);
  }

  // varyings required for lighting
  vPosition = (gl_ModelViewMatrix * vec4(pos, 1.0)).xyz;
  vObjPos = vPosition;
  vObjPos.z -= gl_ModelViewMatrix[3][2];
}
