Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/shaders/ssao.cg
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/src/shaders/ssao.cg	(revision 3212)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/src/shaders/ssao.cg	(revision 3213)
@@ -258,5 +258,6 @@
 			float3 viewDir,
 			float newWeight,
-			float sampleIntensity
+			float sampleIntensity,
+			bool isMovingObject
 			)
 {
@@ -312,24 +313,35 @@
 
 		++ numSamples;
-		
+
 		// check if the samples have been valid in the last frame
-		// only mark sample as invalid if taking it into account can have influence the ssao:
-		// hence we also check if the sample or the same sample in the previous frame
-		// had any chance to be near the current sample
+		// only mark sample as invalid if in the last / current frame
+		// they possibly have any influence on the ao
 		const float changeFactor = sampleColor.y;
 		const float pixelValid = sampleColor.x;
 
-		// hack: cedistance measure can fail in some cases => choose something different
+		// we check if the sample could have been near enough to the current pixel 
+		// to have any influence in the current or last frame
 		const float tooFarAway = step(0.5f, lengthToSample - changeFactor);
 		validSamples = max(validSamples, (1.0f - tooFarAway) * pixelValid);
-		//validSamples += sampleColor.x;
-
-		//if ((validSamples < 1.0f) && (newWeight > 200) && (numSamples >= 8)) break;
-		//if ((validSamples < 1.0f) && (numSamples >= 8)) break;
-	}
-
+
+#ifdef USE_GTX
+		// we can bail out early and use a minimal #samples)
+		// if some conditions are met as long as the hardware supports it
+		if (numSamples >= 8)
+		{
+			// if the pixel belongs to a static object and all the samples stay valid in the current frame
+			if (!isMovingObject && (validSamples < 1.0f)) break;
+			// if the pixel belongs to a dynamic object but the #accumulated samples for this pixel is sufficiently high 
+			// (=> there was no discontinuity recently)
+			else if (isMovingObject && (newWeight > NUM_SAMPLES * 5)) break;
+		}
+#endif
+
+	}
+
+	// scale ao contribution
 	total_ao /= numSamples;
 
-	return float3(max(0.0f, 1.0f - total_ao), validSamples, numSamples);
+	return float3(total_ao, validSamples, numSamples);
 }
 
@@ -382,4 +394,7 @@
 	float scaleFactor = kernelRadius * invw;
 
+	const float sqrMoveSpeed = SqrLen(diffVec);
+	const bool isMovingObject = (sqrMoveSpeed > DYNAMIC_OBJECTS_THRESHOLD);
+
 	
 	/////////////////
@@ -403,5 +418,5 @@
 	if (eyeSpaceDepth < 1e10f)
 	{
-		ao = ssao(IN, colors, noiseTex, samples, normal, eyeSpacePos.xyz, scaleFactor, bl, br, tl, tr, normalize(viewDir), oldWeight, sampleIntensity);
+		ao = ssao(IN, colors, noiseTex, samples, normal, eyeSpacePos.xyz, scaleFactor, bl, br, tl, tr, normalize(viewDir), oldWeight, sampleIntensity, isMovingObject);
 		//ao = ssao2(IN, colors, noiseTex, samples, normal, eyeSpacePos.xyz, scaleFactor, bl, br, tl, tr, normalize(viewDir), normals, sampleIntensity);
 	}
@@ -411,21 +426,30 @@
 	}
 
-	const float squaredLen = SqrLen(diffVec);
-
-	// check if we have to reset pixel because one of the sample points was invalid
-	if (squaredLen < DYNAMIC_OBJECTS_THRESHOLD)
-	{
-		if (ao.y > 4.0f) 
-			oldWeight = 0; 
-		else if (ao.y > 1.0f)
-			oldWeight = min(oldWeight, 4.0f * NUM_SAMPLES);
-	}
-
+	
+	///////////
+	//-- check if we have to reset pixel because one of the sample points was invalid
+	//-- only do this if the current pixel does not belong to a moving object
+
+	// the weight equals the number of sampled shot in this pass
 	const float newWeight = ao.z;
+
+	const float completelyResetThres = 4.0f;
+	const float partlyResetThres = 1.0f;
+	
+	if (!isMovingObject)
+	{
+		if (ao.y > completelyResetThres) 
+			oldWeight = .0f; 
+		else if (ao.y > partlyResetThres)
+			oldWeight = min(oldWeight, 4.0f * newWeight);
+	}
+
+	// the new weight for the next frame
 	const float combinedWeight = clamp(newWeight + oldWeight, .0f, temporalCoherence);
 
-	
-	// blend between old and new samples (and avoid division by zero)
+	//////////
+	//-- blend ao between old and new samples (and avoid division by zero)
 	OUT.illum_col.x = (ao.x * newWeight + oldSsao * oldWeight) / max(1e-6f, newWeight + oldWeight);
+
 	OUT.illum_col.z = SqrLen(diffVec);
 	OUT.illum_col.y = combinedWeight;
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/shaders/lenseFlare.cg
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/src/shaders/lenseFlare.cg	(revision 3212)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/src/shaders/lenseFlare.cg	(revision 3213)
@@ -6,20 +6,36 @@
 };
 
-float4 main(fragment IN, 
-			uniform sampler2D colors,
-			uniform sampler2D ,
-			): COLOR
+
+
+float4 LenseFlare(fragment IN, 
+				  uniform sampler2D colorsTex,
+				  uniform sampler2D flareTex1,
+				  uniform sampler2D flareTex2,
+				  uniform sampler2D flareTex3,
+				  uniform sampler2D flareTex4,
+				  uniform float2 vectorToLight, // vector to current light position
+				  uniform float distanceToLight // distance to current light position
+				  ): COLOR
 {
 	// center color
-	const float4 centerColor = tex2Dlod(colors, float4(IN.texCoords, 0, 0));
-	// center depth
-	const float4 centerDepth = float4(centerColor.w);
+	const float4 color = tex2Dlod(colorsTex, float4(IN.texCoords, 0, 0));
 	
-	const float2 lt = IN.texCoords + offsets[0];
-	const float2 rb = IN.texCoords + offsets[1];
-	const float2 rt = IN.texCoords + offsets[2];
-	const float2 lb = IN.texCoords + offsets[3];
+	const float scale = 0.5f;
+	const float center = float2(.5f, .5f);
+	const float2 newPos = vectorToLight * distanceToLight;
 
+	const float2 newTexCoords = (IN.texCoords - center) / scale + center - newPos;
 
-	return col;
+	const float4 flare1 = tex2Dlod(flareTex1, float4(newTexCoords, 0, 0));
+
+	float4 result;
+
+	result.w = color.w;
+
+	//const float factor = 0.9f;
+	//result.xyz = lerp(color.xyz, flare1.xyz, factor);
+	//result.xyz = color.xyz * (1.0f - flare1.w) + flare1.xyz * flare1.w;
+	result.xyz = color.xyz + flare1.xyz;
+
+	return result;
 }
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/shaders/common.h
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/src/shaders/common.h	(revision 3170)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/src/shaders/common.h	(revision 3213)
@@ -1,2 +1,8 @@
+/************************************/
+/*     Common shader functions      */
+/************************************/
+
+/** Interpolate bilinearly between 2 vectors
+*/
 inline float3 Interpol(float2 w, float3 bl, float3 br, float3 tl, float3 tr)
 {
@@ -9,5 +15,6 @@
 
 
-// reconstruct world space position
+/** reconstruct world space position
+*/
 inline float3 ReconstructSamplePos(uniform sampler2D tex,
 								   float2 texcoord, 
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/DeferredRenderer.h
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/src/DeferredRenderer.h	(revision 3212)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/src/DeferredRenderer.h	(revision 3213)
@@ -119,4 +119,6 @@
 	void SortSamples();
 
+	void LenseFlare(FrameBufferObject *fbo, DirectionalLight *light);
+ 
 
 	////////////
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/irradiance.cpp
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/src/irradiance.cpp	(revision 3207)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/src/irradiance.cpp	(revision 3213)
@@ -1155,4 +1155,5 @@
 
 		ShadowMap *sm = showShadowMap ? shadowMap : NULL;
+
 		deferredShader->Render(fbo, ssaoTempCohFactor, light, useHDR, useAntiAliasing, sm);
 	}
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/DeferredRenderer.cpp
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/src/DeferredRenderer.cpp	(revision 3212)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/src/DeferredRenderer.cpp	(revision 3213)
@@ -10,4 +10,6 @@
 #include "Light.h"
 #include "ShaderManager.h"
+#include "Texture.h"
+
 #include <math.h>
 
@@ -61,4 +63,5 @@
 static ShaderProgram *sCgScaleDepthProgram = NULL;
 static ShaderProgram *sCgPrepareSsaoProgram = NULL;
+static ShaderProgram *sCgLenseFlareProgram = NULL;
 
 
@@ -76,36 +79,9 @@
 static float ssaoFilterWeights[NUM_SSAO_FILTER_SAMPLES];
 
-static GLuint sBurstTex;
-static GLuint sHaloTex[4];
+static Texture *sHaloTex[4];
 
 int DeferredRenderer::colorBufferIdx = 0;
 
 
-static void PrepareLenseFlare()
-{
-	sBurstTex = new Texture("burst.jpg");
-
-	Texture(const std::string &filename);
-
-	glEnable(GL_TEXTURE_2D);
-	glGenTextures(1, &sBurstTex);
-	glBindTexture(GL_TEXTURE_2D, sBurstTex);
-		
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-
-	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, randomNormals);
-
-	glBindTexture(GL_TEXTURE_2D, 0);
-	glDisable(GL_TEXTURE_2D);
-
-	delete [] randomNormals;
-
-	cout << "prepared lense flare textures" << endl;
-
-	PrintGLerror("prepare lense flare");
-}
 
 
@@ -322,4 +298,24 @@
 
 
+static void PrepareLenseFlare()
+{
+	string textures[] = {"lens1.jpg", "lens2.jpg", "lens3.jpg", "lens4.jpg"};
+
+	for (int i = 0; i < 4; ++ i)
+	{
+		sHaloTex[i] = new Texture(model_path + textures[i]);
+
+		sHaloTex[i]->SetBoundaryModeS(Texture::CLAMP);
+		sHaloTex[i]->SetBoundaryModeT(Texture::CLAMP);
+
+		sHaloTex[i]->Create();
+	}
+
+	cout << "prepared lense flare textures" << endl;
+
+	PrintGLerror("prepare lense flare");
+}
+
+
 DeferredRenderer::DeferredRenderer(int w, int h, PerspectiveCamera *cam):
 mWidth(w), mHeight(h), 
@@ -383,4 +379,6 @@
 
 	mEyePos = mOldEyePos = Vector3::ZERO();
+
+	PrepareLenseFlare();
 
 	InitCg();
@@ -420,4 +418,5 @@
 	sCgLogLumProgram = sm->CreateFragmentProgram("tonemap", "CalcAvgLogLum", "avgLogLum");
 	sCgPrepareSsaoProgram = sm->CreateFragmentProgram("deferred", "PrepareSsao", "PrepareSsao");
+	sCgLenseFlareProgram = sm->CreateFragmentProgram("lenseFlare", "LenseFlare", "LenseFlare");
 
 
@@ -498,4 +497,16 @@
 
 	////////////////
+
+	
+	string lenseFlareParams[] = 
+		{"colorsTex", "flareTex1", "flareTex2", "flareTex3", "flareTex4", 
+		 "vectorToLight", "distanceToLight"};
+
+	sCgLenseFlareProgram->AddParameters(lenseFlareParams, 0, 7);
+
+
+	////////////////
+	//-- prepare filters for ssao
+
 
 	const float filterWidth = 1.0f;
@@ -560,6 +571,5 @@
 	}
 
-	// multisampling is difficult / costly with deferred shading
-	// at least do some edge blurring 
+	// q: use antialiasing before or after ssao?
 	//if (useAntiAliasing) AntiAliasing(fbo, light);
 
@@ -587,4 +597,7 @@
 	}
 
+
+	LenseFlare(fbo, light);
+
 	// multisampling is difficult / costly with deferred shading
 	// at least do some edge blurring 
@@ -1210,5 +1223,6 @@
 	///////////////////
 
-
+	// use view orientation as we assume that the eye point is always in the center
+	// of our coordinate system, this way we have the highest precision near the eye point
 	mCamera->GetViewOrientationMatrix(matViewing);
 	mCamera->GetProjectionMatrix(matProjection);
@@ -1257,16 +1271,45 @@
 
 
-void DeferredRenderer::LenseFlare(FrameBufferObject *fbo)
-{
+void DeferredRenderer::LenseFlare(FrameBufferObject *fbo,
+								  DirectionalLight *light
+								  )
+{
+	// the sun is a large distance in the reverse light direction
+	// => extrapolate light pos
+	
+	const Vector3 lightPos = light->GetDirection() * -1e3f;
+
+	Vector3 projLightPos = mProjViewMatrix * lightPos * 0.5f + Vector3(0.5f);
+	cout << "lightPos " << projLightPos << endl;
+
+	// check if light is visible in the image
+	if ((projLightPos.x < -0.2f) || (projLightPos.y < -0.2f) ||
+		(projLightPos.x >= 1.2f) || (projLightPos.y >= 1.2f))
+		return;
+
+	// vector to light from screen center in texture space
+	Vector3 vectorToLight = projLightPos - Vector3(0.5f);
+	vectorToLight.z = .0f;
+
+	const float distanceToLight = Magnitude(vectorToLight);
+	vectorToLight /= distanceToLight;
+
+	cout << "dist " << distanceToLight << " v " << vectorToLight << endl;
+
+
 	ColorBufferObject *colorBuffer = fbo->GetColorBuffer(colorBufferIdx);
-
+	GLuint colorsTex = colorBuffer->GetTexture();
+	
 	FlipFbos(fbo);
 
-	sCgLenseFlareProgram->SetTexture(0, colorsTex);
-	sCgLenseFlareProgram->SetTexture(1, sBurstTex);
-	sCgLenseFlareProgram->SetTexture(2, sHaloTex[0]);
-	sCgLenseFlareProgram->SetTexture(3, sHaloTex[1]);
-	sCgLenseFlareProgram->SetValue1f(4, sHaloTex[2]);
-	sCgLenseFlareProgram->SetValue1f(5, sHaloTex[3]);
+	int i = 0;
+
+	sCgLenseFlareProgram->SetTexture(i ++, colorsTex);
+	sCgLenseFlareProgram->SetTexture(i ++, sHaloTex[0]->GetId());
+	sCgLenseFlareProgram->SetTexture(i ++, sHaloTex[1]->GetId());
+	sCgLenseFlareProgram->SetTexture(i ++, sHaloTex[2]->GetId());
+	sCgLenseFlareProgram->SetTexture(i ++, sHaloTex[3]->GetId());
+	sCgLenseFlareProgram->SetValue2f(i ++, vectorToLight.x, vectorToLight.y);
+	sCgLenseFlareProgram->SetValue1f(i ++, distanceToLight);
 
 	DrawQuad(sCgLenseFlareProgram);
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/Camera.cpp
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/src/Camera.cpp	(revision 3102)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/src/Camera.cpp	(revision 3213)
@@ -134,5 +134,5 @@
 	mat.x[3][0] = -DotProd(GetRightVector(), mPosition);
 	mat.x[3][1] = -DotProd(GetUpVector(), mPosition);
-	mat.x[3][2] = DotProd(GetDirection(), mPosition);
+	mat.x[3][2] =  DotProd(GetDirection(), mPosition);
 }
 
