From 7c608c20032624c2f6ef43d8005ec176c63c79ca Mon Sep 17 00:00:00 2001
From: Frederic Bouvier <fredfgfs01@free.fr>
Date: Tue, 2 Nov 2010 22:31:39 +0100
Subject: [PATCH] Restore QDM urban shader technique for quality level >= 4

---
 Effects/urban.eff  | 143 +++++++++++++++++++++++++++++++++++++++++++++
 Shaders/urban.frag | 112 +++++++++++++++++++++++++++++++++--
 2 files changed, 250 insertions(+), 5 deletions(-)

diff --git a/Effects/urban.eff b/Effects/urban.eff
index f8eecd141..1f43cbb73 100644
--- a/Effects/urban.eff
+++ b/Effects/urban.eff
@@ -13,6 +13,149 @@
     <tangent type="int">6</tangent>
     <binormal type="int">7</binormal>
   </generate>
+  <technique n="8">
+    <predicate>
+      <and>
+        <property>/sim/rendering/urban-shader</property>
+        <property>/sim/rendering/shader-effects</property>
+	<less-equal>
+	  <value type="float">4.0</value>
+	  <float-property>/sim/rendering/quality-level</float-property>
+	</less-equal>
+        <or>
+          <less-equal>
+            <value type="float">2.0</value>
+            <glversion/>
+          </less-equal>
+          <and>
+            <extension-supported>GL_ARB_shader_objects</extension-supported>
+            <extension-supported>GL_ARB_shading_language_100</extension-supported>
+            <extension-supported>GL_ARB_vertex_shader</extension-supported>
+            <extension-supported>GL_ARB_fragment_shader</extension-supported>
+          </and>
+        </or>
+      </and>
+    </predicate>
+    <pass>
+      <lighting>true</lighting>
+      <material>
+        <ambient><use>material/ambient</use></ambient>
+        <diffuse><use>material/diffuse</use></diffuse>
+        <specular><use>material/specular</use></specular>
+        <color-mode>ambient-and-diffuse</color-mode>
+      </material>
+      <blend><use>transparent</use></blend>
+      <alpha-test><use>transparent</use></alpha-test>
+      <shade-model>smooth</shade-model>
+      <cull-face>back</cull-face>
+      <render-bin>
+        <bin-number><use>render-bin/bin-number</use></bin-number>
+        <bin-name><use>render-bin/bin-name</use></bin-name>
+      </render-bin>
+      <texture-unit>
+        <unit>0</unit>
+          <image><use>texture[0]/image</use></image>
+          <filter><use>texture[0]/filter</use></filter>
+          <wrap-s><use>texture[0]/wrap-s</use></wrap-s>
+          <wrap-t><use>texture[0]/wrap-t</use></wrap-t>
+          <internal-format>
+            <use>texture[0]/internal-format</use>
+          </internal-format>
+      </texture-unit>
+      <texture-unit>
+        <unit>1</unit>
+          <image><use>texture[2]/image</use></image>
+          <filter><use>texture[2]/filter</use></filter>
+          <wrap-s><use>texture[2]/wrap-s</use></wrap-s>
+          <wrap-t><use>texture[2]/wrap-t</use></wrap-t>
+          <internal-format><use>texture[2]/internal-format</use></internal-format>
+      </texture-unit>
+      <texture-unit>
+        <unit>2</unit>
+          <image><use>texture[2]/image</use></image>
+          <filter>nearest-mipmap-nearest</filter>
+          <wrap-s><use>texture[2]/wrap-s</use></wrap-s>
+          <wrap-t><use>texture[2]/wrap-t</use></wrap-t>
+          <internal-format><use>texture[2]/internal-format</use></internal-format>
+		  <mipmap-control>
+			<function-r>average</function-r>
+			<function-g>average</function-g>
+			<function-b>average</function-b>
+			<function-a>min</function-a>
+		  </mipmap-control>
+      </texture-unit>
+      <texture-unit>
+        <unit>3</unit>
+        <type>noise</type>
+      </texture-unit>
+      <program>
+        <vertex-shader>Shaders/urban.vert</vertex-shader>
+        <fragment-shader>Shaders/urban.frag</fragment-shader>
+        <attribute>
+          <name>tangent</name>
+          <index>6</index>
+        </attribute>
+        <attribute>
+          <name>binormal</name>
+          <index>7</index>
+        </attribute>
+        <attribute>
+          <name>normal</name>
+          <index>15</index>
+        </attribute>
+      </program>
+      <uniform>
+        <name>BaseTex</name>
+        <type>sampler-2d</type>
+        <value type="int">0</value>
+      </uniform>
+      <uniform>
+        <name>NormalTex</name>
+        <type>sampler-2d</type>
+        <value type="int">1</value>
+      </uniform>
+      <uniform>
+        <name>QDMTex</name>
+        <type>sampler-2d</type>
+        <value type="int">2</value>
+      </uniform>
+      <uniform>
+        <name>NoiseTex</name>
+        <type>sampler-3d</type>
+        <value type="int">3</value>
+      </uniform>
+      <uniform>
+        <name>depth_factor</name>
+        <type>float</type>
+        <value><use>depth-factor</use></value>
+      </uniform>
+      <uniform>
+        <name>tile_size</name>
+        <type>float</type>
+        <value><use>xsize</use></value>
+      </uniform>
+      <uniform>
+        <name>night_color</name>
+        <type>float-vec3</type>
+        <value><use>night-color</use></value>
+      </uniform>
+      <uniform>
+        <name>quality_level</name>
+        <type>float</type>
+        <value><use>quality-level</use></value>
+      </uniform>
+      <uniform>
+        <name>snowlevel</name>
+        <type>float</type>
+        <value><use>snow-level</use></value>
+      </uniform>
+      <uniform>
+        <name>max_lod_level</name>
+        <type>float</type>
+        <value><use>max-lod-level</use></value>
+      </uniform>
+    </pass>
+  </technique>
   <technique n="9">
     <predicate>
       <and>
diff --git a/Shaders/urban.frag b/Shaders/urban.frag
index 7e207cf44..addceb67c 100644
--- a/Shaders/urban.frag
+++ b/Shaders/urban.frag
@@ -5,6 +5,11 @@
 
 #version 120
 
+#define TEXTURE_MIP_LEVELS 10
+#define TEXTURE_PIX_COUNT  1024 //pow(2,TEXTURE_MIP_LEVELS)
+#define BINARY_SEARCH_COUNT 10
+#define BILINEAR_SMOOTH_FACTOR 2.0
+
 varying vec4  rawpos;
 varying vec4  ecPosition;
 varying vec3  VNormal;
@@ -16,6 +21,7 @@ varying vec4  constantColor;
 uniform sampler3D NoiseTex;
 uniform sampler2D BaseTex;
 uniform sampler2D NormalTex;
+uniform sampler2D QDMTex;
 uniform float depth_factor;
 uniform float tile_size;
 uniform float quality_level; // From /sim/rendering/quality-level
@@ -24,8 +30,96 @@ uniform vec3 night_color;
 
 const float scale = 1.0;
 int linear_search_steps = 10;
+int GlobalIterationCount = 0;
+int gIterationCap = 64;
 
-float ray_intersect(sampler2D reliefMap, vec2 dp, vec2 ds)
+void QDM(inout vec3 p, inout vec3 v)
+{
+	const int MAX_LEVEL = TEXTURE_MIP_LEVELS;
+	const float NODE_COUNT = TEXTURE_PIX_COUNT;
+	const float TEXEL_SPAN_HALF = 1.0 / NODE_COUNT / 2.0;
+
+	float fDeltaNC = TEXEL_SPAN_HALF * depth_factor;
+
+	vec3 p2 = p;
+	float level = MAX_LEVEL;
+    vec2 dirSign = (sign(v.xy) + 1.0) * 0.5;
+    GlobalIterationCount = 0;
+    float d = 0.0;
+
+	while (level >= 0.0 && GlobalIterationCount < gIterationCap)
+	{
+		vec4 uv = vec4(p2.xyz, level);
+		d = texture2DLod(QDMTex, uv.xy, uv.w).w;
+
+		if (d > p2.z)
+		{
+			//predictive point of ray traversal
+			vec3 tmpP2 = p + v * d;
+
+			//current node count
+			float nodeCount = pow(2.0, (MAX_LEVEL - level));
+			//current and predictive node ID
+			vec4 nodeID = floor(vec4(p2.xy, tmpP2.xy)*nodeCount);
+
+			//check if we are crossing the current cell
+			if (nodeID.x != nodeID.z || nodeID.y != nodeID.w)
+			{
+				//calculate distance to nearest bound
+				vec2 a = p2.xy - p.xy;
+				vec2 p3 = (nodeID.xy + dirSign) / nodeCount;
+				vec2 b = p3.xy - p.xy;
+
+				vec2 dNC = (b.xy * p2.z) / a.xy;
+				//take the nearest cell
+				d = min(d,min(dNC.x, dNC.y))+fDeltaNC;
+
+				level++;
+
+				//use additional convergence speed-up
+	            #ifdef USE_QDM_ASCEND_INTERVAL
+			    if(frac(level*0.5) > EPSILON)
+				  level++;
+				#elseif USE_QDM_ASCEND_CONST
+				 level++;
+				#endif
+			}
+			p2 = p + v * d;
+		}
+		level--;
+		GlobalIterationCount++;
+	}
+
+	//
+	// Manual Bilinear filtering
+	//
+	float rayLength =  length(p2.xy - p.xy) + fDeltaNC;
+
+	float dA = p2.z * (rayLength - BILINEAR_SMOOTH_FACTOR * TEXEL_SPAN_HALF) / rayLength;
+	float dB = p2.z * (rayLength + BILINEAR_SMOOTH_FACTOR * TEXEL_SPAN_HALF) / rayLength;
+
+	vec4 p2a = vec4(p + v * dA, 0.0);
+	vec4 p2b = vec4(p + v * dB, 0.0);
+	dA = texture2DLod(NormalTex, p2a.xy, p2a.w).w;
+	dB = texture2DLod(NormalTex, p2b.xy, p2b.w).w;
+
+	dA = abs(p2a.z - dA);
+	dB = abs(p2b.z - dB);
+
+	p2 = mix(p2a.xyz, p2b.xyz, dA / (dA + dB));
+
+	p = p2;
+}
+
+float ray_intersect_QDM(vec2 dp, vec2 ds)
+{
+    vec3 p = vec3( dp, 0.0 );
+    vec3 v = vec3( ds, 1.0 );
+    QDM( p, v );
+    return p.z;
+}
+
+float ray_intersect_relief(vec2 dp, vec2 ds)
 {
 	float size = 1.0 / float(linear_search_steps);
 	float depth = 0.0;
@@ -34,7 +128,7 @@ float ray_intersect(sampler2D reliefMap, vec2 dp, vec2 ds)
 	for(int i = 0; i < linear_search_steps - 1; ++i)
 	{
 		depth += size;
-		float t = step(0.95, texture2D(reliefMap, dp + ds * depth).a);
+		float t = step(0.95, texture2D(NormalTex, dp + ds * depth).a);
 		if(best_depth > 0.996)
 			if(depth >= t)
 				best_depth = depth;
@@ -46,7 +140,7 @@ float ray_intersect(sampler2D reliefMap, vec2 dp, vec2 ds)
 	for(int i = 0; i < binary_search_steps; ++i)
 	{
 		size *= 0.5;
-		float t = step(0.95, texture2D(reliefMap, dp + ds * depth).a);
+		float t = step(0.95, texture2D(NormalTex, dp + ds * depth).a);
 		if(depth >= t)
 		{
 			best_depth = depth;
@@ -58,6 +152,14 @@ float ray_intersect(sampler2D reliefMap, vec2 dp, vec2 ds)
 	return(best_depth);
 }
 
+float ray_intersect(vec2 dp, vec2 ds)
+{
+    if ( quality_level >= 4.0 )
+        return ray_intersect_QDM( dp, ds );
+    else
+        return ray_intersect_relief( dp, ds );
+}
+
 void main (void)
 {
 	if ( quality_level >= 3.5 ) {
@@ -68,7 +170,7 @@ void main (void)
 	vec3 s = vec3(dot(V, VTangent), dot(V, VBinormal), dot(VNormal, -V));
 	vec2 ds = s.xy * depth_factor / s.z;
 	vec2 dp = gl_TexCoord[0].st - ds;
-	float d = ray_intersect(NormalTex, dp, ds);
+	float d = ray_intersect(dp, ds);
 
 	vec2 uv = dp + ds * d;
 	vec3 N = texture2D(NormalTex, uv).xyz * 2.0 - 1.0;
@@ -89,7 +191,7 @@ void main (void)
 		vec3 sl = normalize( vec3( dot( l, VTangent ), dot( l, VBinormal ), dot( -l, VNormal ) ) );
 		ds = sl.xy * depth_factor / sl.z;
 		dp -= ds * d;
-		float dl = ray_intersect(NormalTex, dp, ds);
+		float dl = ray_intersect(dp, ds);
 		if ( dl < d - 0.05 )
 			shadow_factor = dot( constantColor.xyz, vec3( 1.0, 1.0, 1.0 ) ) * 0.25;
 	}