Index: GTP/trunk/Lib/Vis/Preprocessing/scripts/run_gvs_vps.sh
===================================================================
--- GTP/trunk/Lib/Vis/Preprocessing/scripts/run_gvs_vps.sh	(revision 2725)
+++ GTP/trunk/Lib/Vis/Preprocessing/scripts/run_gvs_vps.sh	(revision 2726)
@@ -13,17 +13,17 @@
 #SCENE=../data/Arena/arena-high-lods.obj
 SCENE=../data/Arena/arena_trees.obj
-VIEWCELLS=../data/Arena/arena-high-lods-5000-viewcells.xml.gz
+#VIEWCELLS=../data/Arena/arena-high-lods-5000-viewcells.xml.gz
 #SCENE=../data/vienna/vienna_cropped.obj
 #SCENE=../data/roofs_new.obj
-#SCENE=../data/vienna/city_full_hp.obj
+SCENE=../data/vienna/city_full_hp.obj
 #SCENE=../data/vienna/vienna_rep.obj
 
 #SCENE=../data/vienna/vienna_cropped.obj
-#VIEWCELLS=../data/vienna/vienna_cropped-gradient-viewcells.xml.gz 
-#VIEWPOINTS=../data/vienna/testwalk.vp
-VIEWPOINTS=../data/arena/arena_key_cropped.vp
+VIEWCELLS=../data/vienna/vienna_cropped-gradient-viewcells.xml.gz 
+VIEWPOINTS=../data/vienna/testwalk.vp
+#VIEWPOINTS=../data/arena/arena_key_cropped.vp
 
 #LOG_PREFIX=../src/SG08/rebut-arena-pixel2
-#LOG_PREFIX=../src/SG08/full
+LOG_PREFIX=../src/SG08/speedtest
 LOG_PREFIX=../src/SG08/arena_trees
 
@@ -40,9 +40,9 @@
 -preprocessor_use_vbos- \
 -gvs_epsilon=0.0001 \
--gvs_total_samples=100000 \
--gvs_samples_per_pass=100000 \
--gvs_initial_samples=16 \
--gvs_max_viewcells=200000 \
--gvs_min_contribution=2000 \
+-gvs_total_samples=1000000 \
+-gvs_samples_per_pass=1000000 \
+-gvs_initial_samples=2000 \
+-gvs_max_viewcells=1 \
+-gvs_min_contribution=50 \
 -gvs_per_viewcell=true \
 -preprocessor_detect_empty_viewspace+ \
Index: GTP/trunk/Lib/Vis/Preprocessing/src/GvsPreprocessor.h
===================================================================
--- GTP/trunk/Lib/Vis/Preprocessing/src/GvsPreprocessor.h	(revision 2705)
+++ GTP/trunk/Lib/Vis/Preprocessing/src/GvsPreprocessor.h	(revision 2726)
@@ -39,4 +39,6 @@
 		mGvsRuns = 0;
 
+		mRandomSamples = 0;
+		mGvsSamples = 0;
 		mTotalPvs = 0;
 		mViewCells = 0;
@@ -54,4 +56,6 @@
 public:
 
+	int mRandomSamples;
+	int mGvsSamples;
 	int mPass;
 	int mTotalSamples;
@@ -141,5 +145,5 @@
 		b) if triangle was found reverse sampling
 	*/
-	bool HandleRay(VssRay *ray);
+	inline bool HandleRay(VssRay *ray);
 
 	/** The adaptive border sampling step. It aims to find neighbouring 
@@ -157,4 +161,9 @@
 							const VssRay &oldRay);
 
+	bool ReverseSampling2(const VssRay &currentRay,
+                          const Triangle3 &hitTriangle,
+						  const VssRay &oldRay,
+						  VssRayContainer &reverseRays);
+
 	/** Returns true if we sampled a closer triangle than with the previous ray. 
 		Does reverse sampling if gap found.
@@ -167,5 +176,5 @@
 		with respect to the previous ray.
 	*/
-	void EnqueueRays(VssRayContainer &samples, VssRayContainer &invalidSamples);
+	void EnqueueRays(VssRayContainer &samples);
 
 	/** Hepler function for adaptive border sampling. It finds 
@@ -239,15 +248,17 @@
 	*/
 	void UpdateStatsForVisualization(KdIntersectable *kdInt);
+	
+	void CompileViewCellsFromPointList();
+
+	void ComputeStats();
+
+	int ConvertObjectPvs();
 	/** Keep count of new objects for stats. Returns number of new pvs entries.
 	*/
-	int CountObject(Intersectable *triObj);
-
-	void CompileViewCellsFromPointList();
-
-	bool AddTriangleObject(Intersectable *triObj);
-
-	void ComputeStats();
-
-	int ConvertObjectPvs();
+	inline int CountObject(Intersectable *triObj);
+
+	inline bool AddTriangleObject(Intersectable *triObj);
+
+	inline void AddKdNodeToPvs(const Vector3 &termination);
 
 
Index: GTP/trunk/Lib/Vis/Preprocessing/src/Preprocessor.cpp
===================================================================
--- GTP/trunk/Lib/Vis/Preprocessing/src/Preprocessor.cpp	(revision 2724)
+++ GTP/trunk/Lib/Vis/Preprocessing/src/Preprocessor.cpp	(revision 2726)
@@ -966,5 +966,14 @@
 						   SimpleRayContainer &rays)
 {
-  return strategy.GenerateSamples(number, rays);
+	int invalidSamples;
+	return strategy.GenerateSamples(number, rays, invalidSamples);
+}
+
+
+int Preprocessor::GenerateRays(const int number,
+							   SamplingStrategy &strategy,
+							   SimpleRayContainer &rays, int &invalidSamples)
+{
+	return strategy.GenerateSamples(number, rays, invalidSamples);
 }
 
@@ -975,15 +984,13 @@
 						   SimpleRayContainer &rays)
 {
-	const int startSize = (int)rays.size();
 	SamplingStrategy *strategy = GenerateSamplingStrategy(sampleType);
+	
+	if (!strategy)
+		return 0;
+
 	int castRays = 0;
-
-	if (!strategy)
-	{
-		return 0;
-	}
-
+	int invalidSamples;
 #if 1
-	castRays = strategy->GenerateSamples(number, rays);
+	castRays = strategy->GenerateSamples(number, rays, invalidSamples);
 #else
 	GenerateRayBundle(rays, newRay, 16, 0);
@@ -1197,7 +1204,5 @@
 
 	// !!!!!!!!!!!!!!!! VH no sorting
-	if (
-		rays.size() > 10000
-		)
+	if (rays.size() > 10000)
 	{
 		mRayCaster->SortRays(rays);
@@ -1316,25 +1321,26 @@
 
 
-bool Preprocessor::GenerateRayBundle(SimpleRayContainer &rayBundle,									
-									 const SimpleRay &mainRay,
-									 const int number,
-									 const int pertubType) const
-{
-	rayBundle.push_back(mainRay);
-
-	const float pertubOrigin = 0.0f;
-	const float pertubDir = 0.2f;
-
-	for (int i = 0; i < number - 1; ++ i)
-	{
-		Vector3 pertub;
-
-		pertub.x = RandomValue(0.0f, pertubDir);
-		pertub.y = RandomValue(0.0f, pertubDir);
-		pertub.z = RandomValue(0.0f, pertubDir);
-
-		const Vector3 newDir = mainRay.mDirection + pertub;
+bool Preprocessor::GenerateJitteredRays(SimpleRayContainer &rayBundle,	
+										const SimpleRay &mainRay,
+										int number,
+										int pertubType) const
+{
+	//rayBundle.push_back(mainRay);
+	//const float pertubOrigin = 0.0f;
+	const float pertubDir = 0.01f;
+	Vector3 pertub;
+
+	for (int i = 0; i < number; ++ i)
+	{
+		pertub.x = RandomValue(-pertubDir, pertubDir);
+		pertub.y = RandomValue(-pertubDir, pertubDir);
+		pertub.z = RandomValue(-pertubDir, pertubDir);
+
+		Vector3 newDir = mainRay.mDirection + pertub;
+		const float c = Magnitude(newDir);
+		newDir *= 1.0f / c;
+
 		//const Vector3 newDir = mainRay.mDirection;
-
+#if 0
 		pertub.x = RandomValue(0.0f, pertubOrigin);
 		pertub.y = RandomValue(0.0f, pertubOrigin);
@@ -1342,5 +1348,6 @@
 
 		const Vector3 newOrigin = mainRay.mOrigin + pertub;
-		//const Vector3 newOrigin = mainRay.mOrigin;
+#endif
+		const Vector3 newOrigin = mainRay.mOrigin;
 
 		rayBundle.push_back(SimpleRay(newOrigin, newDir, 0, 1.0f));
Index: GTP/trunk/Lib/Vis/Preprocessing/src/RssPreprocessor.cpp
===================================================================
--- GTP/trunk/Lib/Vis/Preprocessing/src/RssPreprocessor.cpp	(revision 2105)
+++ GTP/trunk/Lib/Vis/Preprocessing/src/RssPreprocessor.cpp	(revision 2726)
@@ -492,8 +492,9 @@
 	  
 	} else {
+		int invalidSamples = 0;
 	  for (int i=0; i < mInitialSamples; i+=batch) {
 		rays.clear();
 		mVssRays.clear();
-		mMixtureDistribution->GenerateSamples(batch, rays);
+		mMixtureDistribution->GenerateSamples(batch, rays, invalidSamples);
 		CastRays(rays, mVssRays, true, pruneInvalidRays);
 		mMixtureDistribution->ComputeContributions(mVssRays);
Index: GTP/trunk/Lib/Vis/Preprocessing/src/Preprocessor.h
===================================================================
--- GTP/trunk/Lib/Vis/Preprocessing/src/Preprocessor.h	(revision 2720)
+++ GTP/trunk/Lib/Vis/Preprocessing/src/Preprocessor.h	(revision 2726)
@@ -132,12 +132,17 @@
 							 SimpleRayContainer &rays);
 
+	virtual int	GenerateRays(const int number,
+							 SamplingStrategy &strategy,
+							 SimpleRayContainer &rays, 
+							 int &invalidSamples);
+
 	virtual int GenerateRays(const int number,
 							 const int raysType,
 							 SimpleRayContainer &rays);
 
-	bool GenerateRayBundle(SimpleRayContainer &rayBundle,
-						   const SimpleRay &mainRay,
-						   const int number,
-						   const int shuffleType) const;
+	bool GenerateJitteredRays(SimpleRayContainer &rayBundle,
+							 const SimpleRay &mainRay,
+							 int number,
+							 int shuffleType) const;
 
 	virtual void CastRays(SimpleRayContainer &rays,
Index: GTP/trunk/Lib/Vis/Preprocessing/src/SamplingStrategy.h
===================================================================
--- GTP/trunk/Lib/Vis/Preprocessing/src/SamplingStrategy.h	(revision 2694)
+++ GTP/trunk/Lib/Vis/Preprocessing/src/SamplingStrategy.h	(revision 2726)
@@ -7,4 +7,6 @@
 #include "common.h"
 #include "Halton.h"
+#include "Vector3.h"
+
 namespace GtpVisibilityPreprocessor {
 
@@ -59,10 +61,8 @@
 	virtual ~SamplingStrategy();
 
+	virtual int GenerateSamples(int number, SimpleRayContainer &rays, int &invalidSamples);
 	/** Each strategy has to implement this function.
-	@returns true if generated valid sample.
+		@returns true if generated valid sample.
 	*/
-
-	virtual int GenerateSamples(const int number, SimpleRayContainer &rays);
-
 	virtual bool GenerateSample(SimpleRay &ray) = 0;
 
@@ -262,4 +262,11 @@
 
 	ViewCell *mViewCell;
+
+	Vector3 origin;
+	Vector3 direction; 
+	Vector3 point;
+	Vector3 normal;
+	float r[2];
+
 	static HaltonSequence sHalton;
 };
@@ -307,5 +314,5 @@
   }
   
-  virtual int GenerateSamples(const int number, SimpleRayContainer &rays);
+  virtual int GenerateSamples(int number, SimpleRayContainer &rays, int &invalidSamples);
   
 private:
Index: GTP/trunk/Lib/Vis/Preprocessing/src/GlobalLinesRenderer.cpp
===================================================================
--- GTP/trunk/Lib/Vis/Preprocessing/src/GlobalLinesRenderer.cpp	(revision 2552)
+++ GTP/trunk/Lib/Vis/Preprocessing/src/GlobalLinesRenderer.cpp	(revision 2726)
@@ -169,5 +169,6 @@
 
 			SimpleRayContainer simpleRays;
-			glStrategy.GenerateSamples(5, simpleRays);
+			int invalidSamples = 0;
+			glStrategy.GenerateSamples(5, simpleRays, invalidSamples);
 
 			//cout << "simple ray: " << simpleRays[4] << endl;
Index: GTP/trunk/Lib/Vis/Preprocessing/src/ViewCellsManager.cpp
===================================================================
--- GTP/trunk/Lib/Vis/Preprocessing/src/ViewCellsManager.cpp	(revision 2723)
+++ GTP/trunk/Lib/Vis/Preprocessing/src/ViewCellsManager.cpp	(revision 2726)
@@ -137,6 +137,6 @@
 	//rays.clear();
 	//passSamples.clear();
-	
-	mMixtureDistribution->GenerateSamples(samplesPerPass, rays);
+	int invalidSamples = 0;
+	mMixtureDistribution->GenerateSamples(samplesPerPass, rays, invalidSamples);
 	
 	const bool doubleRays = true;
Index: GTP/trunk/Lib/Vis/Preprocessing/src/GlRenderer.cpp
===================================================================
--- GTP/trunk/Lib/Vis/Preprocessing/src/GlRenderer.cpp	(revision 2725)
+++ GTP/trunk/Lib/Vis/Preprocessing/src/GlRenderer.cpp	(revision 2726)
@@ -1587,10 +1587,9 @@
 		mViewDirection = sray.mDirection;
 
-		cout << "handling vp " << mFrame << " " << mViewPoint << " " << mViewDirection << endl;
+		//cout << "handling vp " << mFrame << " " << mViewPoint << " " << mViewDirection << endl;
 		// skip all frames which have already 0 pixel error
 		// $$ Reverted back by JB for efficiency
 		if (1)//mPvsErrorBuffer[i].mError > 0.0f) 
 		{
-			cout << "here3" << endl;
 			// compute the pixel error
 			mPvsErrorBuffer[i].mError = GetPixelError(pvsSize, mPvsStat.pass);
Index: GTP/trunk/Lib/Vis/Preprocessing/src/common.h
===================================================================
--- GTP/trunk/Lib/Vis/Preprocessing/src/common.h	(revision 2705)
+++ GTP/trunk/Lib/Vis/Preprocessing/src/common.h	(revision 2726)
@@ -538,14 +538,14 @@
 
 
-#define QT_VISUALIZATION_SHOWN 1
-
-
-#endif
-
-
-
-
-
-
-
-
+#define QT_VISUALIZATION_SHOWN 0
+
+
+#endif
+
+
+
+
+
+
+
+
Index: GTP/trunk/Lib/Vis/Preprocessing/src/SimpleRay.h
===================================================================
--- GTP/trunk/Lib/Vis/Preprocessing/src/SimpleRay.h	(revision 2588)
+++ GTP/trunk/Lib/Vis/Preprocessing/src/SimpleRay.h	(revision 2726)
@@ -55,7 +55,7 @@
   SimpleRay(const Vector3 &o,
 			const Vector3 &d,
-			const unsigned char distribution,
-			const float weight,
-			const unsigned char flags = F_BIDIRECTIONAL
+			unsigned char distribution,
+			float weight,
+			unsigned char flags = F_BIDIRECTIONAL
 			):
     mOrigin(o),
Index: GTP/trunk/Lib/Vis/Preprocessing/src/CombinedPreprocessor.cpp
===================================================================
--- GTP/trunk/Lib/Vis/Preprocessing/src/CombinedPreprocessor.cpp	(revision 2723)
+++ GTP/trunk/Lib/Vis/Preprocessing/src/CombinedPreprocessor.cpp	(revision 2726)
@@ -92,6 +92,6 @@
 	vssRays.clear();
 	
-	
-	mMixtureDistribution->GenerateSamples(mSamplesPerPass, rays);
+	int invalidSamples = 0;
+	mMixtureDistribution->GenerateSamples(mSamplesPerPass, rays, invalidSamples);
 
 	cerr<<"Casting rays..."<<endl;
Index: GTP/trunk/Lib/Vis/Preprocessing/src/GvsPreprocessor.cpp
===================================================================
--- GTP/trunk/Lib/Vis/Preprocessing/src/GvsPreprocessor.cpp	(revision 2725)
+++ GTP/trunk/Lib/Vis/Preprocessing/src/GvsPreprocessor.cpp	(revision 2726)
@@ -13,5 +13,5 @@
 #include "Polygon3.h"
 #include "IntersectableWrapper.h"
-
+#include "Timer/PerfTimer.h"
 
 
@@ -27,4 +27,23 @@
 
 static ObjectContainer myobjects;
+static int sInvalidSamples = 0;
+
+///////////
+//-- timers
+
+
+static PerfTimer rayTimer;
+static PerfTimer kdPvsTimer;
+static PerfTimer gvsTimer;
+static PerfTimer initialTimer;
+static PerfTimer intersectionTimer;
+static PerfTimer preparationTimer;
+static PerfTimer mainLoopTimer;
+static PerfTimer contributionTimer;
+static PerfTimer castTimer;
+static PerfTimer generationTimer;
+
+
+/////////////////////
 
 
@@ -145,12 +164,10 @@
 	const float len = Magnitude(currentRay.mTermination - currentRay.mOrigin);
 	
-#if 1
 	// distance large => this is likely to be a discontinuity
-	if ((predictedLen - len) > mThreshold)
-#else 
+	if ((predictedLen - len) > mThreshold) 
 	// q: rather use relative distance?
-	if ((predictedLen / len) > mThreshold)
-#endif
-	{
+	//if ((predictedLen / len) > mThreshold)
+	{
+#if 0
 		// apply reverse sampling to find the gap
 		VssRay *newRay = ReverseSampling(currentRay, hitTriangle, oldRay);
@@ -162,10 +179,39 @@
 			if (0) newRay->mFlags |= VssRay::ReverseSample;
 		
+			rayTimer.Entry();
 			// check if ray can be processed further
 			// note: ray deletion handled by ray pool)
 			HandleRay(newRay);
+			rayTimer.Exit();
 
 			return 1;
 		}
+#else
+		static VssRayContainer reverseRays;
+		reverseRays.clear();
+
+		// apply reverse sampling to find the gap
+		ReverseSampling2(currentRay, hitTriangle, oldRay, reverseRays);
+
+		rayTimer.Entry();
+
+		int castRays = 0;
+		// check if reverse sampling was successful
+		for (size_t i = 0; i < reverseRays.size(); ++ i)
+		{
+			// check if ray can be processed further
+			// note: ray deletion handled by ray pool)
+			if (reverseRays[i])
+			{
+				++ castRays;
+				HandleRay(reverseRays[i]);
+			}
+		}
+		
+		rayTimer.Exit();
+
+		return castRays;
+
+#endif
 	}
 
@@ -193,4 +239,6 @@
 void GvsPreprocessor::UpdateStatsForVisualization(KdIntersectable *kdInt)
 {
+	int numObj = 0;
+
 	// count new objects in pvs due to kd node conversion	
 	myobjects.clear();
@@ -198,10 +246,8 @@
 	mKdTree->CollectObjectsWithDublicates(kdInt->GetItem(), myobjects);
 
-	int numObj;
-
 	ObjectContainer::const_iterator oit, oit_end = myobjects.end();
 
 	for (oit = myobjects.begin(); oit != oit_end; ++ oit)
-		numObj = CountObject(*oit);
+		numObj += CountObject(*oit);
 
 	mViewCellsManager->UpdateStatsForViewCell(mCurrentViewCell, kdInt, numObj);
@@ -209,4 +255,27 @@
 
 
+void GvsPreprocessor::AddKdNodeToPvs(const Vector3 &termination)
+{
+	kdPvsTimer.Entry();
+
+	// exchange the triangle with the node in the pvs for kd pvs
+	KdNode *node = mKdTree->GetPvsNode(termination);
+
+	//KdNode *node = mKdTree->GetPvsNodeCheck(ray.mTermination, obj);
+	//if (!node) cerr << "e " << obj->GetBox() << " " << ray.mTermination << endl; else 
+	if (!node->Mailed())
+	{
+		// add to pvs
+		node->Mail();
+		KdIntersectable *kdInt = mKdTree->GetOrCreateKdIntersectable(node);
+		mCurrentViewCell->GetPvs().AddSampleDirty(kdInt, 1.0f);
+
+		if (QT_VISUALIZATION_SHOWN) UpdateStatsForVisualization(kdInt);	
+	}
+
+	kdPvsTimer.Exit();
+}
+
+
 bool GvsPreprocessor::HasContribution(VssRay &ray)
 {
@@ -214,4 +283,6 @@
 		return false;
 
+	contributionTimer.Entry();
+
 	bool result;
 
@@ -219,5 +290,5 @@
 	{
 		// store the rays + the intersected view cells
-		const bool storeViewCells = false; //GVS_DEBUG;
+		const bool storeViewCells = false;
 
 		mViewCellsManager->ComputeSampleContribution(ray, 
@@ -230,27 +301,12 @@
 	else // original per view cell gvs
 	{
-		Intersectable *obj = ray.mTerminationObject;
-
 		// test if triangle was accounted for yet
-		result = AddTriangleObject(obj);
+		result = AddTriangleObject(ray.mTerminationObject);
 		
-		if (mUseKdPvs && (1 || result))
-		{
-			// exchange the triangle with the node in the pvs for kd pvs
-			KdNode *node = mKdTree->GetPvsNode(ray.mTermination);
-
-			//KdNode *node = mKdTree->GetPvsNodeCheck(ray.mTermination, obj);
-			//if (!node) cerr << "e " << obj->GetBox() << " " << ray.mTermination << endl; else 
-			if (!node->Mailed())
-			{
-				// add to pvs
-				node->Mail();
-				KdIntersectable *kdInt = mKdTree->GetOrCreateKdIntersectable(node);
-				mCurrentViewCell->GetPvs().AddSampleDirty(kdInt, 1.0f);
-
-				if (QT_VISUALIZATION_SHOWN) UpdateStatsForVisualization(kdInt);	
-			}
-		}
-	}
+		if (mUseKdPvs)
+			AddKdNodeToPvs(ray.mTermination);
+	}
+
+	contributionTimer.Exit();
 
 	return result;
@@ -363,25 +419,80 @@
 	const Vector3 p = (p1 + p2) * 0.5f;
 	//cout << "p: " << p << " " << p1 << " " << p2 << endl;
+
+	SimpleRay sray(oldRay.mOrigin, p - oldRay.mOrigin, SamplingStrategy::GVS, 1.0f);
+
+#if 1
+	castTimer.Entry();
+	// cast single ray to check if a triangle was missed
+	VssRay *newRay = mRayCaster->CastRay(sray, mViewCellsManager->GetViewSpaceBox(), !mPerViewCell);
+	castTimer.Exit();
+	++ castRays;
+
+	// this ray will not be further processed
+	// note: ray deletion is handled by ray pool
+	if (!newRay) return castRays;
+
+	// new triangle discovered? => add new ray to queue
+	rayTimer.Entry();
+	HandleRay(newRay);
+	rayTimer.Exit();
+
+
+
+#else
+
 	// cast ray into the new point
-	SimpleRay sray(oldRay.mOrigin, p - oldRay.mOrigin, SamplingStrategy::GVS, 1.0f);
-
-	VssRay *newRay = mRayCaster->CastRay(sray, mViewCellsManager->GetViewSpaceBox(), !mPerViewCell);
-	
-	++ castRays;
-
+	static SimpleRayContainer importanceRays;
+	importanceRays.clear();
+
+	generationTimer.Entry();
+
+	
+	importanceRays.push_back(sray);
+
+	const int numRandomRays = 15;
+
+	GenerateJitteredRays(importanceRays, sray, numRandomRays, 0);
+	GenerateRays(numRandomRays, *mDistribution, importanceRays, sInvalidSamples);
+
+	generationTimer.Exit();
+	
+	// for the original implementation we don't cast double rays
+	const bool castDoubleRays = !mPerViewCell;
+	// cannot prune invalid rays because we have to compare adjacent rays
+	const bool pruneInvalidRays = false;
+
+	static VssRayContainer vssRays;
+	vssRays.clear();
+
+	castTimer.Entry();
+	CastRays(importanceRays, vssRays, castDoubleRays, pruneInvalidRays);
+	castTimer.Exit();
+
+	castRays += (int)vssRays.size();
+
+	VssRay *newRay = vssRays.empty() ? NULL : vssRays[0];
+
+	// new triangle discovered? => add new ray to queue
+	rayTimer.Entry();
+	for (size_t i = 0; i < vssRays.size(); ++ i)
+	{
+		if (vssRays[i])
+			HandleRay(vssRays[i]);
+	}
+
+	rayTimer.Exit();
+
+	// this ray will not be further processed
+	// note: ray deletion is handled by ray pool
 	if (!newRay) return castRays;
+#endif
 
 	//newRay->mFlags |= VssRay::BorderSample;
-
-	// add new ray to queue
-	const bool enqueued = HandleRay(newRay);
 
 	// subdivide further
 	castRays += SubdivideEdge(hitTriangle, p1, p, ray1, *newRay, oldRay);
 	castRays += SubdivideEdge(hitTriangle, p, p2, *newRay, ray2, oldRay);
-
-	// this ray will not be further processed
-	// note: ray deletion is handled by ray pool
-
+	
 	return castRays;
 }
@@ -391,5 +502,6 @@
 {
 	Intersectable *tObj = currentRay.mTerminationObject;
-	// q matt: can this be possible
+
+	// question matt: can this be possible?
 	if (!tObj) return 0;
 
@@ -410,6 +522,7 @@
 	
 	/// create rays from sample points and handle them
-	SimpleRayContainer simpleRays;
-	simpleRays.reserve(9);
+	static SimpleRayContainer simpleRays;
+	simpleRays.clear();
+	//simpleRays.reserve(9);
 
 	VertexContainer::const_iterator vit, vit_end = enlargedTriangle.end();
@@ -432,29 +545,35 @@
 	}
 
-	// cast rays to triangle vertices and determine visibility
+	
+	//////////
+	//-- fill up simple rays with random rays so we can cast 16 rays at a time
+
+	const int numRandomRays = 16 - (int)simpleRays.size();
+	SimpleRay mainRay = SimpleRay(currentRay.GetOrigin(), currentRay.GetNormalizedDir(), SamplingStrategy::GVS, 1.0f);
+
+	GenerateJitteredRays(simpleRays, mainRay, numRandomRays, 0);
+	//GenerateRays(numRandomRays, *mDistribution, simpleRays, sInvalidSamples);
+
+
+	/////////////////////
+	//-- cast rays to vertices and determine visibility
+	
 	VssRayContainer vssRays;
 
-	// don't cast double rays as we need only the forward rays
+	// for the original implementation we don't cast double rays
 	const bool castDoubleRays = !mPerViewCell;
-	// cannot prune invalid rays because we have to compare adjacent  rays.
+	// cannot prune invalid rays because we have to compare adjacent rays
 	const bool pruneInvalidRays = false;
 
-
-	//////////
-	//-- fill up simple rays with random rays so we can cast 16 rays simultaniosly
-
-	//const int numRandomRays = 0;
-	const int numRandomRays = 16 - (int)simpleRays.size();
-
-	GenerateRays(numRandomRays, *mDistribution, simpleRays);
-
-
-	/////////////////////
-
-	// keep origin for per view cell sampling
+	castTimer.Entry();
 	CastRays(simpleRays, vssRays, castDoubleRays, pruneInvalidRays);
+	castTimer.Exit();
 
 	const int numBorderSamples = (int)vssRays.size() - numRandomRays;
-
+	int castRays = (int)simpleRays.size();
+
+	// handle cast rays
+	EnqueueRays(vssRays);
+	
 #if 0
 	// set flags
@@ -464,10 +583,4 @@
 #endif
 
-	int castRays = (int)simpleRays.size();
-
-	VssRayContainer invalidSamples;
-
-	// handle rays
-	EnqueueRays(vssRays, invalidSamples);
 
     // recursivly subdivide each edge
@@ -483,5 +596,4 @@
 	
 	mGvsStats.mBorderSamples += castRays;
-
 	
 	return castRays;
@@ -546,11 +658,8 @@
 	// other types not implemented yet
 	if (tObj->Type() == Intersectable::TRIANGLE_INTERSECTABLE)
-	{
 		occluder = static_cast<TriangleIntersectable *>(tObj)->GetItem();
-	}
 	else
-	{
 		cout << "reverse sampling: " << tObj->Type() << " not yet implemented" << endl;
-	}
+	
 	// get a point which is passing just outside of the occluder
     Vector3 newPoint;
@@ -564,6 +673,8 @@
 	Vector3 newDir, newOrigin;
 
+	//////////////
 	//-- Construct the mutated ray with xnew,
 	//-- dir = predicted(x)- pnew as direction vector
+
 	newDir = predicted - newPoint;
 
@@ -608,36 +719,125 @@
 
 
+bool GvsPreprocessor::ReverseSampling2(const VssRay &currentRay,
+									   const Triangle3 &hitTriangle,
+									   const VssRay &oldRay,
+									   VssRayContainer &reverseRays)
+{
+	// get triangle occluding the path to the hit mesh
+	Triangle3 occluder;
+	Intersectable *tObj = currentRay.mTerminationObject;
+
+	// q: why can this happen?
+	if (!tObj)
+		return NULL;
+
+	// other types not implemented yet
+	if (tObj->Type() == Intersectable::TRIANGLE_INTERSECTABLE)
+		occluder = static_cast<TriangleIntersectable *>(tObj)->GetItem();
+	else
+		cout << "reverse sampling: " << tObj->Type() << " not yet implemented" << endl;
+	
+	// get a point which is passing just outside of the occluder
+    Vector3 newPoint;
+
+	// q: why is there sometimes no intersecton found?
+	if (!GetPassingPoint(currentRay, occluder, oldRay, newPoint))
+		return NULL;
+
+	const Vector3 predicted = CalcPredictedHitPoint(currentRay, hitTriangle, oldRay);
+
+	Vector3 newDir, newOrigin;
+
+	//////////////
+	//-- Construct the mutated ray with xnew,
+	//-- dir = predicted(x)- pnew as direction vector
+
+	newDir = predicted - newPoint;
+
+	// take xnew, p = intersect(viewcell, line(pnew, predicted(x)) as origin ?
+	// difficult to say!!
+	const float offset = 0.5f;
+	newOrigin = newPoint - newDir * offset;
+	
+
+	//////////////
+	//-- for per view cell sampling, we must check for intersection
+	//-- with the current view cell
+
+    if (mPerViewCell)
+	{
+		// send ray to view cell
+		static Ray ray;
+
+		ray.Clear();
+		ray.Init(newOrigin, -newDir, Ray::LOCAL_RAY);
+		
+		// check if ray intersects view cell
+		if (!mCurrentViewCell->CastRay(ray))
+			return NULL;
+
+		Ray::Intersection &hit = ray.intersections[0];
+	
+		// the ray starts from the view cell
+		newOrigin = ray.Extrap(hit.mT);
+	}
+
+	static SimpleRayContainer reverseSimpleRays;
+	reverseSimpleRays.clear();
+
+	SimpleRay mainRay = SimpleRay(newOrigin, newDir, SamplingStrategy::GVS, 1.0f);
+
+	reverseSimpleRays.push_back(mainRay);
+	GenerateJitteredRays(reverseSimpleRays, mainRay, 15, 0);
+
+	castTimer.Entry();
+	CastRays(reverseSimpleRays, reverseRays, false, false);
+	castTimer.Exit();
+
+	mGvsStats.mReverseSamples += reverseRays.size();
+
+	return true;
+}
+
+
 int GvsPreprocessor::CastInitialSamples(int numSamples)
 {	
-	const long startTime = GetTime();
+	initialTimer.Entry();
 
 	// generate simple rays
-	SimpleRayContainer simpleRays;
-	
+	static SimpleRayContainer simpleRays;
+	simpleRays.clear();
+
+	
+	generationTimer.Entry();
 	ViewCellBorderBasedDistribution vcStrat(*this, mCurrentViewCell);
-    GenerateRays(numSamples, *mDistribution, simpleRays);
+    GenerateRays(numSamples, *mDistribution, simpleRays, sInvalidSamples);
+	generationTimer.Exit();
 
 	//cout << "sr: " << simpleRays.size() << endl;
 	// generate vss rays
-	VssRayContainer samples;
-	
+	static VssRayContainer samples;
+	samples.clear();
+
 	const bool castDoubleRays = !mPerViewCell;
 	const bool pruneInvalidRays = true;
 	
+	castTimer.Entry();
 	CastRays(simpleRays, samples, castDoubleRays, pruneInvalidRays);
-	
-	VssRayContainer invalidSamples;
+	castTimer.Exit();
 
 	// add to ray queue
-	EnqueueRays(samples, invalidSamples);
-
-	//CLEAR_CONTAINER(invalidSamples);
-	//Debug << "generated " <<  numSamples << " samples in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
+	EnqueueRays(samples);
+
+	initialTimer.Exit();
+
 	return (int)simpleRays.size();
 }
 
 
-void GvsPreprocessor::EnqueueRays(VssRayContainer &samples, VssRayContainer &invalidSamples)
-{
+void GvsPreprocessor::EnqueueRays(VssRayContainer &samples)
+{
+	rayTimer.Entry();
+
 	// add samples to ray queue
 	VssRayContainer::const_iterator vit, vit_end = samples.end();
@@ -645,8 +845,9 @@
 	{
 		VssRay *ray = *vit;
-
 		HandleRay(ray);
-		//if (!HandleRay(ray)) invalidSamples.push_back(ray);
-	}
+		// note: deletion of invalid samples handked by ray pool
+	}
+
+	rayTimer.Exit();
 }
 
@@ -654,9 +855,11 @@
 int GvsPreprocessor::ProcessQueue()
 {
+	gvsTimer.Entry();
+
 	++ mGvsStats.mGvsRuns;
 
 	int castSamples = 0;
 
-	while (!mRayQueue.empty())//&& (mGvsStats.mTotalSamples + castSamples < mTotalSamples) )
+	while (!mRayQueue.empty())
 	{
 		// handle next ray
@@ -664,15 +867,9 @@
 		mRayQueue.pop();
 		
-		const int newSamples = AdaptiveBorderSampling(*ray);
-
-		castSamples += newSamples;
+		castSamples += AdaptiveBorderSampling(*ray);
 		// note: don't have to delete because handled by ray pool
 	}
 
-	/*if (mRayCaster->mVssRayPool.mIndex > mSamplesPerPass)
-	{
-		cout << "warning: new samples: " << castSamples << " " << "queue: "  << (int)mRayQueue.size() << endl;
-		Debug << "warning: new samples: " << castSamples << " " << "queue: "  << (int)mRayQueue.size() << endl;
-	}*/
+	gvsTimer.Exit();
 
 	return castSamples;
@@ -694,16 +891,10 @@
 		{
 			if ((*rit)->mFlags & VssRay::BorderSample)
-			{
 				vcRays.push_back(*rit);
-			}
 			else if ((*rit)->mFlags & VssRay::ReverseSample)
-			{
 				vcRays2.push_back(*rit);
-			}
 			else
-			{
 				vcRays3.push_back(*rit);
-			}	
-		}
+		} 
 	}
 
@@ -719,5 +910,5 @@
 	Material m;
 	
-	char str[64]; sprintf(str, "pass%06d.wrl", mProcessedViewCells);
+	char str[64]; sprintf_s(str, "pass%06d.wrl", mProcessedViewCells);
 
 	Exporter *exporter = Exporter::GetExporter(str);
@@ -880,4 +1071,6 @@
 void GvsPreprocessor::ComputeViewCellGeometryIntersection()
 {
+	intersectionTimer.Entry();
+
 	AxisAlignedBox3 box = mCurrentViewCell->GetBox();
 
@@ -927,4 +1120,6 @@
 
 	cout << "added " << (int)mTrianglePvs.size() - oldTrianglePvs << " triangles (" << newKdObj << " objects) by intersection" << endl;
+
+	intersectionTimer.Exit();
 }
 
@@ -934,11 +1129,15 @@
 	while (mCurrentViewCell = NextViewCell())
 	{
-		// hack: reset counters
+		preparationTimer.Entry();
+
+		// hack: reset counters (could be done with a mailing-like approach
 		ObjectContainer::const_iterator oit, oit_end = mObjects.end();
-
 		for (oit = mObjects.begin(); oit != oit_end; ++ oit)
 			(*oit)->mCounter = NOT_ACCOUNTED_OBJECT;
 
+		preparationTimer.Exit();
+
 		mDistribution->SetViewCell(mCurrentViewCell);
+
         ComputeViewCell();
 	}
@@ -1041,4 +1240,6 @@
 {
 	int passSamples = 0;
+	int randomSamples = 0;
+	int gvsSamples = 0;
 	int oldContribution = 0;
 
@@ -1046,14 +1247,20 @@
 	{
 		mRayCaster->InitPass();
+
+		int newRandomSamples, newGvsSamples;
 
 		// Ray queue empty => 
 		// cast a number of uniform samples to fill ray queue
-		int newSamples = CastInitialSamples(mInitialSamples);
-
+		newRandomSamples = CastInitialSamples(mInitialSamples);
+		
 		if (!mOnlyRandomSampling)
-			newSamples += ProcessQueue();
-
-		passSamples += newSamples;
-		mGvsStats.mTotalSamples += newSamples;
+			newGvsSamples = ProcessQueue();
+
+		passSamples += newRandomSamples + newGvsSamples;
+		mGvsStats.mTotalSamples += newRandomSamples + newGvsSamples;
+
+		mGvsStats.mRandomSamples += newRandomSamples;
+		mGvsStats.mGvsSamples += newGvsSamples;
+
 
 		if (passSamples % (mGvsSamplesPerPass + 1) == mGvsSamplesPerPass)
@@ -1062,5 +1269,5 @@
 
 			mGvsStats.mPassContribution = mGvsStats.mTotalContribution - oldContribution;
-
+			
 			////////
 			//-- stats
@@ -1220,14 +1427,22 @@
 void GvsPreprocessor::ComputeViewCell()
 {
-	//if (mCurrentViewCell->GetId() != 499) return;
-
-	// clean up
+	const long startTime = GetTime();
+
+	// initialise
+	mGvsStats.mPerViewCellSamples = 0;
+
+	int oldContribution = 0;
+	int passSamples = 0;
+	for (int i = 0; i < 0; ++ i)
+		mGenericStats[i] = 0;
+
 	mTrianglePvs.clear();
 
+
+	// hack: take bounding box of view cell as view cell bounds
 	mCurrentViewCell->GetMesh()->ComputeBoundingBox();
 
+	// use mailing for kd node pvs
 	KdNode::NewMail();
-
-	const long startTime = GetTime();
 
 	cout << "\n***********************\n" 
@@ -1236,31 +1451,30 @@
 	cout << "bb: " << mCurrentViewCell->GetBox() << endl;
 
-	mGvsStats.mPerViewCellSamples = 0;
-
-	int oldContribution = 0;
-	int passSamples = 0;
-	
-	for (int i = 0; i < 0; ++ i)
-		mGenericStats[i] = 0;
+	mainLoopTimer.Entry();
 
 	while (1)
 	{
+		sInvalidSamples = 0;
 		int oldPvsSize = mCurrentViewCell->GetPvs().GetSize();
 		
 		mRayCaster->InitPass();
 
+		int newRandomSamples, newGvsSamples, newSamples;
+
 		// Ray queue empty => 
 		// cast a number of uniform samples to fill ray queue
-		int newSamples = CastInitialSamples(mInitialSamples);
-
+		newRandomSamples = CastInitialSamples(mInitialSamples);
+		
 		if (!mOnlyRandomSampling)
-		{
-			int samplesPerRun = ProcessQueue();
-			newSamples += samplesPerRun;
-			//if (samplesPerRun > 0) cout << "spr: " << samplesPerRun << " ";
-		}
+			newGvsSamples = ProcessQueue();
+
+		newSamples = newRandomSamples + newGvsSamples;
 
 		passSamples += newSamples;
-        mGvsStats.mPerViewCellSamples += newSamples;
+		mGvsStats.mPerViewCellSamples += newSamples;
+
+		mGvsStats.mRandomSamples += newRandomSamples;
+		mGvsStats.mGvsSamples += newGvsSamples;
+
 
 		if (passSamples >= mGvsSamplesPerPass)
@@ -1303,8 +1517,10 @@
 	}
 	
+	mainLoopTimer.Exit();
+
 	// at last compute objects that directly intersect view cell
 	ComputeViewCellGeometryIntersection();
-
 		
+
 	////////
 	//-- stats
@@ -1321,5 +1537,4 @@
 	// compute pvs size using larger (bvh objects)
 	// note: for kd pvs we had to do this during gvs computation
-
 	if (!mUseKdPvs)
 	{
@@ -1343,9 +1558,6 @@
 		mGvsStats.mPvsCost = 0; // todo objectPvs.EvalPvsCost();
 	}
-	else if (0)
-	{
-		//KdNode::NewMail();
-
-		// compute pvs kd nodes that intersect view cell
+	else if (0) // compute pvs kd nodes that intersect view cell
+	{
 		ObjectContainer mykdobjects;
 
@@ -1387,16 +1599,48 @@
 	mGvsStats.mTotalSamples += mGvsStats.mPerViewCellSamples;
 
+	cout << "id: " << mCurrentViewCell->GetId() << " pvs cost: " 
+	     << mGvsStats.mPvsCost << " pvs tri: " << mTrianglePvs.size() << endl;
+
+	cout << "invalid samples ratio: " << (float)sInvalidSamples / mGvsStats.mPerViewCellSamples << endl;
+
+	float rayTime = rayTimer.TotalTime();
+	float kdPvsTime = kdPvsTimer.TotalTime();
+	float gvsTime = gvsTimer.TotalTime();
+	float initialTime = initialTimer.TotalTime();
+	float intersectionTime = intersectionTimer.TotalTime();
+	float preparationTime = preparationTimer.TotalTime();
+	float mainLoopTime = mainLoopTimer.TotalTime();
+	float contributionTime = contributionTimer.TotalTime();
+	float castTime = castTimer.TotalTime();
+	float generationTime = generationTimer.TotalTime();
+
+	cout << "handleRay              : " << rayTime << endl;
+	cout << "kd pvs                 : " << kdPvsTime << endl;
+	cout << "gvs sampling           : " << gvsTime << endl;
+	cout << "initial sampling       : " << initialTime << endl;
+	cout << "view cell intersection : " << intersectionTime << endl;
+	cout << "preparation            : " << preparationTime << endl;
+	cout << "main loop              : " << mainLoopTime << endl;
+	cout << "has contribution       : " << contributionTime << endl;
+	cout << "cast time              : " << castTime << endl;
+	cout << "generation time       : " << generationTime << endl;
+
+	float randomRaysPerSec = mGvsStats.mRandomSamples / (1e6f * initialTime);
+	float gvsRaysPerSec = mGvsStats.mGvsSamples / (1e6f * gvsTime);
+
+	cout << "cast " << randomRaysPerSec << " M random rays/s: " << endl;
+	cout << "cast " << gvsRaysPerSec << " M gvs rays/s: " << endl;
+	
 	mGvsStats.Stop();
 	mGvsStats.Print(mGvsStatsStream);
 
-	cout << "id: " << mCurrentViewCell->GetId() << " pvs cost: " 
-	     << mGvsStats.mPvsCost << " pvs tri: " << mTrianglePvs.size() << endl;
-}
-
-
-ObjectContainer triangles;
+}
+
+
 
 int GvsPreprocessor::ConvertObjectPvs()
 {
+	static ObjectContainer triangles;
+
 	int newObjects = 0;
 
Index: GTP/trunk/Lib/Vis/Preprocessing/src/SamplingStrategy.cpp
===================================================================
--- GTP/trunk/Lib/Vis/Preprocessing/src/SamplingStrategy.cpp	(revision 2698)
+++ GTP/trunk/Lib/Vis/Preprocessing/src/SamplingStrategy.cpp	(revision 2726)
@@ -54,32 +54,30 @@
 
 int
-SamplingStrategy::GenerateSamples(const int number,
-								  SimpleRayContainer &rays)
+SamplingStrategy::GenerateSamples(int number,
+								  SimpleRayContainer &rays, 
+								  int &invalidSamples)
 {
 	SimpleRay ray;
-	int samples = 0;
-	int i = 0;
-	const int maxTries = 20;
+	int oldSamples = (int)rays.size();
+	
+	static const int maxTries = 20;
+
 	// tmp changed matt. Q: should one rejected sample 
 	// terminate the whole method?
-	for (; i < number; i++) 
+	for (int i = 0; i < number; ++ i) 
 	{
-		int j = 0;
-		bool sampleGenerated = false;
-
-		for (j = 0; !sampleGenerated && (j < maxTries); ++ j)
+		for (int j = 0; j < maxTries; ++ j)
 		{
-			sampleGenerated = GenerateSample(ray);
-
-			if (sampleGenerated)
+			if (GenerateSample(ray))
 			{		
-				++ samples;
 				rays.push_back(ray);
-				//cout << "d " << ray.mDirection << " ";
+				break;
 			}
+			cerr<<"x";
+			++ invalidSamples;
 		}
 	}
 
-	return samples;
+	return (int)rays.size() - oldSamples;
 }
 
@@ -722,11 +720,12 @@
 
 int
-MixtureDistribution::GenerateSamples(const int number,
-									 SimpleRayContainer &rays)
+MixtureDistribution::GenerateSamples(int number,
+									 SimpleRayContainer &rays,
+									 int &invalidSamples)
 {
   for (int i=0; i < mDistributions.size(); i++) 
 	mDistributions[i]->mGeneratedRays = 0;
 
-  return SamplingStrategy::GenerateSamples(number, rays);
+  return SamplingStrategy::GenerateSamples(number, rays, invalidSamples);
 }
 
@@ -804,40 +803,32 @@
 bool ViewCellBasedDistribution::GenerateSample(SimpleRay &ray)
 {
-	Vector3 origin, direction; 
-
-	Vector3 point;
-	Vector3 normal;
-		
-	float r[2];
-	//for (int i=0; i < 2; i++)
-	// r[i] = RandomValue(0, 1);
-
 	sHalton.GetNext(2, r);
-
 	direction = UniformRandomVector(r[0], r[1]);
+	
+#if 0
 	const float c = Magnitude(direction);
 
+	if (!((c < 1.00001f) && (c > 0.999999f)))
+		cerr << "len wrong" << endl;
     if (c <= Limits::Small) 
 		return false;
 
 	direction *= 1.0f / c;
+#endif
 
 	// get point on view cell surface
-	if (0)
+	if (1)
 	{
 		//mViewCell->GetRandomEdgePoint(origin, normal);
-		mViewCell->GetRandomSurfacePoint(origin, normal);
+		origin = mViewCell->GetBox().GetRandomSurfacePoint();
 
 		// move a little bit back to avoid piercing through walls
 		// that bound the view cell
-		if (0) origin -= 0.01f * normal;
+		//origin -= 0.01f * normal;
 	}
 	else
 		origin = mViewCell->GetBox().GetUniformRandomSurfacePoint();
 
-	//direction = point - origin;
-
-	// $$ jb the pdf is yet not correct for all sampling methods!
-	const float pdf = 1.0f;
+	static const float pdf = 1.0f;
 
 	ray = SimpleRay(origin, direction, VIEWCELL_BASED_DISTRIBUTION, pdf);
