Index: /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreKdTreeSceneManager.cpp
===================================================================
--- /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreKdTreeSceneManager.cpp	(revision 2455)
+++ /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreKdTreeSceneManager.cpp	(revision 2562)
@@ -1033,7 +1033,5 @@
 				QueuedRenderableCollection::OM_SORT_DESCENDING, true);
 		}
-
-
-	}// for each priority
+	} // for each priority
 }
 //-----------------------------------------------------------------------
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/QtInterface/QtGlRenderer.cpp
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/QtInterface/QtGlRenderer.cpp	(revision 2560)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/QtInterface/QtGlRenderer.cpp	(revision 2562)
@@ -50,4 +50,11 @@
 }
 
+
+inline static bool nearerThan(ViewCell *vc1, ViewCell *vc2)
+{
+	return vc1->GetDistance() > vc2->GetDistance();
+}
+
+
 #if USE_CG
 static void handleCgError() 
@@ -322,5 +329,5 @@
 		glMatrixMode(GL_PROJECTION);
 		glLoadIdentity();
-		gluPerspective(angle, ww/(float)hh, 0.1, 2.0*Magnitude(mSceneGraph->GetBox().Diagonal()));
+		gluPerspective(angle, ww/(float)hh, 0.1, 2.0 * Magnitude(mSceneGraph->GetBox().Diagonal()));
 		glMatrixMode(GL_MODELVIEW);
 	} else {
@@ -330,5 +337,5 @@
 		glMatrixMode(GL_PROJECTION);
 		glLoadIdentity();
-		gluPerspective(50.0, ww/(float)hh, 0.1, 20.0*Magnitude(mSceneGraph->GetBox().Diagonal()));
+		gluPerspective(50.0, ww / (float)hh, 0.1, 20.0 * Magnitude(mSceneGraph->GetBox().Diagonal()));
 		glMatrixMode(GL_MODELVIEW);
 	}
@@ -830,4 +837,7 @@
 	mRenderFilter = true;
 	mRenderVisibilityEstimates = false;
+
+	mHideByCost = false;
+
 	mTransferFunction = 0.2f;
 	mIndexBufferSize = 0;
@@ -835,5 +845,5 @@
 	//mCurrentFrame = 0;
 
-	const int delay = 500; // half a second
+	const int delay = 250; // in milliseconds
 	timerId = startTimer(delay);
 
@@ -873,4 +883,5 @@
 	connect(mControlWidget, SIGNAL(SetVisibilityFilterSize(int)), this, SLOT(SetVisibilityFilterSize(int)));
 	connect(mControlWidget, SIGNAL(SetSpatialFilterSize(int)), this, SLOT(SetSpatialFilterSize(int)));
+	connect(mControlWidget, SIGNAL(SetHidingCost(int)), this, SLOT(SetHidingCost(int)));
 
 	connect(mControlWidget, SIGNAL(SetShowViewCells(bool)), this, SLOT(SetShowViewCells(bool)));
@@ -879,4 +890,5 @@
 	connect(mControlWidget, SIGNAL(SetTopView(bool)), this, SLOT(SetTopView(bool)));
 	connect(mControlWidget, SIGNAL(SetCutViewCells(bool)), this, SLOT(SetCutViewCells(bool)));
+	connect(mControlWidget, SIGNAL(SetHideByCost(bool)), this, SLOT(SetHideByCost(bool)));
 	connect(mControlWidget, SIGNAL(SetCutScene(bool)), this, SLOT(SetCutScene(bool)));
 	connect(mControlWidget, SIGNAL(SetRenderErrors(bool)), this, SLOT(SetRenderErrors(bool)));
@@ -1119,12 +1131,22 @@
 	// shift it along y according to number, which is percentage of the bounding
 	// box position
-	if (mViewCellsManager) {
+	if (mViewCellsManager) 
+	{
 		AxisAlignedBox3 box = mViewCellsManager->GetViewSpaceBox();
 		Vector3 p = box.Min() + (number/1000.0f)*box.Max();
 		mSceneCutPlane.mNormal = Vector3(0,-1,0);
 		mSceneCutPlane.mD = -DotProd(mSceneCutPlane.mNormal, p);
+
 		updateGL();
 	}
 }
+
+void
+QtGlRendererWidget::SetHidingCost(int number)
+{
+	mHidingCost = (float)number / 1000.0f;
+	cout << "hiding cost " << mHidingCost << endl;
+}
+
 
 void
@@ -1144,6 +1166,6 @@
 	glEnable(GL_CULL_FACE);
 	glCullFace(GL_FRONT);
-
-	glDisable(GL_CULL_FACE);
+	//glDisable(GL_CULL_FACE);
+
 	double eq[4];
 	eq[0] = mSceneCutPlane.mNormal.x;
@@ -1159,7 +1181,8 @@
 
 	int i;
+
 	ViewCellContainer &viewcells = mViewCellsManager->GetViewCells();
 	int maxPvs = -1;
-	int maxPiercingRays = 0;
+	int maxPiercingRays = 1; // for savety
 
 	for (i = 0; i < viewcells.size(); ++ i) 
@@ -1171,42 +1194,94 @@
 		if (p > maxPvs)
 			maxPvs = p;
+
 		const int piercingRays = vc->GetNumPiercingRays();
+		
 		if (piercingRays > maxPiercingRays)
 			maxPiercingRays = piercingRays;
 	}
 
-
-	for (i = 0; i < viewcells.size(); ++ i) 
+	cout << "here22 " << mHideByCost << " " << mHidingCost << endl;
+
+	if (!mShowPvsSizes && !mShowPiercingRays)
 	{
-		ViewCell *vc = viewcells[i];
-		//	Mesh *m = vc->GetMesh();
+		for (i = 0; i < viewcells.size(); ++ i) 
+		{
+			ViewCell *vc = viewcells[i];
+			RgbColor c;
+
+			if (!mShowPvsSizes && !mShowPiercingRays)
+			{
+				mWireFrame = true;
+				c = vc->GetColor();
+			} 
+
+			glColor3f(c.r, c.g, c.b);
+
+			if (!mHideByCost || (mHidingCost < vc->GetNumPiercingRays() / (float)maxPiercingRays)) 
+			{
+                RenderViewCell(vc);
+			}
+		}
+	}
+	else
+	{
+		//glDisable(GL_CULL_FACE);
+		//glEnable(GL_CULL_FACE);
+		//glFrontFace(GL_CCW);	
+		//glCullFace(GL_BACK);
+		glEnable(GL_DEPTH_TEST);
+		glDisable(GL_BLEND);
+
+		//glDisable(GL_DEPTH_TEST);
+		//glEnable(GL_BLEND);
+	
+		//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+		glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+
+		for (i = 0; i < viewcells.size(); ++ i) 
+		{
+			ViewCell *vc = viewcells[i];
+			const float dist = SqrDistance(mViewPoint, vc->GetBox().Center());
+
+			vc->SetDistance(dist);
+		}
+
+		sort(viewcells.begin(), viewcells.end(), nearerThan);
 
 		RgbColor c;
 
-		if (!mShowPvsSizes && !mShowPiercingRays)
+        for (i = 0; i < viewcells.size(); ++ i) 
 		{
-			mWireFrame = true;
-			c = vc->GetColor();
-		} 
-		else if (mShowPiercingRays)
-		{
-			// const float importance = 5.0f*mTransferFunction * ((float)vc->GetPvs().CountObjectsInPvs() / (float)maxPvs);
-			const float importance = 5.0f * mTransferFunction *
-				((float)vc->GetNumPiercingRays() / (float)maxPiercingRays);
-			// c = RgbColor(importance, 1.0f - importance, 0.0f);
-			c = RainbowColorMapping(importance);
+            ViewCell *vc = viewcells[i];
+			
+			//cout << "dist: " << vc->GetDistance() << " ";
+
+			if (mShowPiercingRays)
+			{
+				// const float importance = 5.0f*mTransferFunction * ((float)vc->GetPvs().CountObjectsInPvs() / (float)maxPvs);
+				const float importance = 5.0f * mTransferFunction *
+					((float)vc->GetNumPiercingRays() / (float)maxPiercingRays);
+				// c = RgbColor(importance, 1.0f - importance, 0.0f);
+				c = RainbowColorMapping(importance);
+			}
+			else
+			{
+				// const float importance = 5.0f*mTransferFunction * ((float)vc->GetPvs().CountObjectsInPvs() / (float)maxPvs);
+				const float importance = 5.0f * mTransferFunction *
+					((float)vc->GetPvs().GetSize() / (float)maxPvs);
+				// c = RgbColor(importance, 1.0f - importance, 0.0f);
+				c = RainbowColorMapping(importance);
+			}
+			
+			const float alpha = 0.2f;
+			glColor4f(c.r, c.g, c.b, alpha);
+			
+			if (!mHideByCost || (mHidingCost < vc->GetNumPiercingRays() / (float)maxPiercingRays)) 
+			{
+                RenderViewCell(vc);
+			}
 		}
-		else
-		{
-			// const float importance = 5.0f*mTransferFunction * ((float)vc->GetPvs().CountObjectsInPvs() / (float)maxPvs);
-			const float importance = 5.0f * mTransferFunction *
-				((float)vc->GetPvs().GetSize() / (float)maxPvs);
-			// c = RgbColor(importance, 1.0f - importance, 0.0f);
-			c = RainbowColorMapping(importance);
-		}
-
-		glColor3f(c.r, c.g, c.b);
-
-		RenderViewCell(vc);
+
+		glEnable(GL_DEPTH_TEST);	
 	}
 
@@ -1474,4 +1549,18 @@
 		connect(button, SIGNAL(clicked(void)), SLOT(FocusNextPvsErrorFrame(void)));
 	}
+
+	// the render cost visualization
+	slider = new QSlider(Qt::Horizontal, vbox);
+	vbox->layout()->addWidget(slider);
+	slider->show();
+	slider->setRange(0, 1000);
+	slider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+	slider->setValue(100);
+	connect(slider, SIGNAL(valueChanged(int)), SIGNAL(SetHidingCost(int)));
+	
+	cb = new QCheckBox("Hide view cells by render cost ", vbox);
+	vbox->layout()->addWidget(cb);
+	cb->setChecked(false);
+	connect(cb, SIGNAL(toggled(bool)), SIGNAL(SetHideByCost(bool)));
 
 	setWindowTitle("Preprocessor Control Widget");
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/QtInterface/QtGlViewer.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/QtInterface/QtGlViewer.h	(revision 2017)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/QtInterface/QtGlViewer.h	(revision 2562)
@@ -5,12 +5,13 @@
 
 
-namespace GtpVisibilityPreprocessor {
+namespace GtpVisibilityPreprocessor 
+{
 
 class QtGlRendererWidget;
 
+
 class QtGlViewer : public QGLWidget
 {
-
-  //Q_OBJECT
+	//Q_OBJECT
 
 	friend class QtGlRendererWidget;
@@ -19,32 +20,36 @@
 public:
 	QtGlRendererWidget *mRenderer;
-	
+
 	QtGlViewer(QWidget *parent,
-			   QtGlRendererWidget *renderer);
-	
-  virtual ~QtGlViewer(){};
-  
-  QSize minimumSizeHint() const;
-  QSize sizeHint() const;
-  
-  // This method has to be rendefined by all renderer implementations
-  virtual void RenderScene();
-  
+		QtGlRendererWidget *renderer);
+
+	virtual ~QtGlViewer(){};
+
+	QSize minimumSizeHint() const;
+	QSize sizeHint() const;
+
+	// This method has to be rendefined by all renderer implementations
+	virtual void RenderScene();
+
+	void timerEvent(QTimerEvent *event);
+
 protected:
-  void initializeGL();
-  void paintGL();
-  void resizeGL(int width, int height);
-  void mousePressEvent(QMouseEvent *event);
-  void mouseMoveEvent(QMouseEvent *event);
+	void initializeGL();
+	void paintGL();
+	void resizeGL(int width, int height);
+	void mousePressEvent(QMouseEvent *event);
+	void mouseMoveEvent(QMouseEvent *event);
 
 	void keyPressEvent ( QKeyEvent * e );
-	
-  bool mWireframe;
+
+	bool mWireframe;
+
+	int timerId;
 
 private:
 
 	float manipulatorLastQuat[4];
-  float scale;
-  QPoint lastPos;
+	float scale;
+	QPoint lastPos;
 
 };
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/QtInterface/QtGlRenderer.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/QtInterface/QtGlRenderer.h	(revision 2560)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/QtInterface/QtGlRenderer.h	(revision 2562)
@@ -99,4 +99,5 @@
   void SetSceneCut(int);
   void SetTopDistance(int);
+  void SetHidingCost(int);
   void SetVisibilityFilterSize(int);
   void SetSpatialFilterSize(int);
@@ -116,4 +117,6 @@
   void SetCutViewCells(bool);
   void SetCutScene(bool);
+
+  void SetHideByCost(bool);
 };
 
@@ -131,4 +134,5 @@
 	bool mCutViewCells;
 	bool mCutScene;
+	bool mHideByCost;
 	bool mRenderErrors;
 	bool mRenderFilter;
@@ -144,4 +148,6 @@
 
 	Plane3 mSceneCutPlane;
+	float mHidingCost;
+
 	float mTopDistance;
 
@@ -277,4 +283,7 @@
 		SetTopDistance(int dist);
 
+	void
+		SetHidingCost(int dist);
+
 	void SetShowViewCells(bool b) {
 		mRenderViewCells = b;
@@ -308,4 +317,6 @@
 
 	void SetCutViewCells(bool b) {
+		std::cout << "here64" << std::endl;
+
 		mCutViewCells = b;
 		updateGL();
@@ -313,4 +324,10 @@
 	void SetCutScene(bool b) {
 		mCutScene = b;
+		updateGL();
+	}
+
+	void SetHideByCost(bool b) {
+		std::cout << "here45" << std::endl;
+		mHideByCost = b;
 		updateGL();
 	}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/QtInterface/QtGlViewer.cpp
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/QtInterface/QtGlViewer.cpp	(revision 2560)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/QtInterface/QtGlViewer.cpp	(revision 2562)
@@ -29,5 +29,9 @@
 	mWireframe = false;
 	trackball(manipulatorLastQuat, 0.0f, 0.0f, 0.0f, 0.0f);
-	connect(renderer, SIGNAL(PvsUpdated()), this, SLOT(updateGL()));
+	//connect(renderer, SIGNAL(PvsUpdated()), this, SLOT(updateGL()));
+	//connect(renderer, SIGNAL(cutupdated), this, SLOT(updateGL()));
+
+	const int delay = 250; // in milliseconds
+	timerId = startTimer(delay);
 }
   
@@ -47,10 +51,8 @@
 QtGlViewer::RenderScene()
 {
-	mRenderer->mFrame++;
+	++ mRenderer->mFrame;
 	
-	// render into the right side of the window buffer
-	if (mRenderer->mRenderViewCells) 
-	  mRenderer->RenderViewCells();
-	
+	glDisable(GL_DEPTH_TEST);
+
 	glColor3f(0.8f, 0.8f, 0.8f);
 	mRenderer->RenderPvs();
@@ -68,7 +70,11 @@
 // 	  }
 // 	}
-	
+
 	if (mRenderer->mShowRenderCost) 
 	  mRenderer->RenderRenderCost();
+
+	// render into the right side of the window buffer
+	if (mRenderer->mRenderViewCells)
+		mRenderer->RenderViewCells();
 
 	glColor3f(1.0f, 1.0f, 1.0f);
@@ -190,4 +196,10 @@
 }
 
-}
-
+void QtGlViewer::timerEvent(QTimerEvent *event) 
+{
+	update();
+}
+
+
+}
+
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/GlRenderer.cpp
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/GlRenderer.cpp	(revision 2560)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/GlRenderer.cpp	(revision 2562)
@@ -309,5 +309,5 @@
 		SetupMaterial(mesh->mMaterial);
 
-	for (i=0; i < mesh->mFaces.size(); i++) 
+	for (i = 0; i < mesh->mFaces.size(); i++) 
 	{
 		if (mWireFrame)
@@ -337,7 +337,7 @@
   glFrontFace(GL_CCW);
   glCullFace(GL_BACK);
-  glEnable(GL_CULL_FACE);
+
   glShadeModel(GL_FLAT);
-  glDepthFunc( GL_LESS );
+  glDepthFunc(GL_LESS );
   glEnable(GL_DEPTH_TEST);
   glEnable(GL_CULL_FACE);
@@ -345,7 +345,7 @@
   InitExtensions();
 
-  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
-
-  glEnable( GL_NORMALIZE );
+  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+  glEnable(GL_NORMALIZE);
   
   glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/CHCRenderer.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/CHCRenderer.h	(revision 2562)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/CHCRenderer.h	(revision 2562)
@@ -0,0 +1,376 @@
+#ifndef __GLRENDERER_H
+#define __GLRENDERER_H
+
+#include "ObjectPvs.h"
+#include "Vector3.h"
+#include "Containers.h"
+#include "Halton.h"
+#include "Renderer.h"
+#include "Beam.h"
+
+
+
+namespace GtpVisibilityPreprocessor {
+
+class SceneGraph;
+class ViewCellsManager;
+class Mesh;
+class MeshInstance;
+class Intersectable;
+class Material;
+class Beam;
+class KdTree;
+class GlRendererBuffer;
+class BeamSampleStatistics;
+class OcclusionQuery;
+class TransformedMeshInstance;
+class TriangleIntersectable;
+class BvhNode;
+class SimpleRayContainer;
+
+struct VssRayContainer;
+
+  struct GLUquadric;
+  
+struct PvsRenderStatistics {
+  
+  float maxError;
+  float sumError;
+  int sumPvsSize;
+  int frames;
+  int errorFreeFrames;
+
+  PvsRenderStatistics() { Reset(); }
+  
+  void Reset() {
+	maxError = 0.0f;
+	sumError = 0.0f;
+	frames = 0;
+	errorFreeFrames = 0;
+	sumPvsSize = 0;
+  }
+
+  float GetMaxError() { return maxError; }
+  float GetAvgError() { return sumError/frames; }
+  float GetErrorFreeFrames() { return errorFreeFrames/(float)frames; }
+  float GetAvgPvs() { return sumPvsSize/(float)frames; }
+  
+};
+
+	struct PvsCache {
+		
+		PvsCache():mViewCell(NULL), mUnfilteredPvsSize(0) {}
+
+		void Reset()
+		{ 
+			mViewCell = NULL; mPvs.Clear(); 
+			filteredBoxes.clear(); 
+			mUnfilteredPvsSize = 0;
+		}
+		
+		ViewCell *mViewCell;
+		ObjectPvs mPvs;
+		int mUnfilteredPvsSize;
+		vector<AxisAlignedBox3> filteredBoxes;
+	};
+
+
+struct RenderCostSample {
+
+  RenderCostSample() {}
+
+  void Reset() {
+	mVisibleObjects = 0;
+	mVisiblePixels = 0;
+  }
+  
+  Vector3 mPosition;
+
+  // visible object from the given point
+  int mVisibleObjects;
+
+  // visible pixels
+  int mVisiblePixels;
+
+  ObjectPvs mPvs;
+  
+};
+
+/** Class encapsulating gl rendering for the scene.
+	There is no gl context binding so the binding is performed in the
+	derived classes
+*/
+class GlRenderer: public Renderer
+{
+friend class GlobalLinesRenderer;
+friend class ViewCellsManager;
+
+public:
+
+  GlRenderer(SceneGraph *sceneGraph,
+			 ViewCellsManager *viewcells,
+			 KdTree *tree);
+  
+  GlRenderer() {}
+
+  virtual ~GlRenderer();
+
+
+  virtual void RandomViewPoint();
+
+  void SetupFalseColor(const unsigned int id);
+  void RenderIntersectable(Intersectable *);
+  void RenderViewCell(ViewCell *vc);
+  void RenderMeshInstance(MeshInstance *mi);
+  void RenderTransformedMeshInstance(TransformedMeshInstance *mi);
+  void RenderMesh(Mesh *m);
+  void SetupMaterial(Material *m);
+  virtual void SetupCamera();
+
+  void
+  RenderRays(const VssRayContainer &rays);
+
+  void
+  RenderTriangle(TriangleIntersectable *object);
+
+  void
+  RenderBox(const AxisAlignedBox3 &box);
+
+  void
+  RenderBvhNode(BvhNode *node);
+
+  void
+  RenderKdNode(KdNode *node);
+
+  bool
+  RenderScene();
+
+  void
+  _RenderScene();
+
+  void
+  _RenderSceneTriangles();
+
+  void _RenderSceneTrianglesWithDrawArrays();
+
+  void
+  RenderViewPoint();
+
+  virtual void
+  SetupProjection(const int w, const int h, const float angle = 70.0f);
+
+  virtual bool ValidViewPoint();
+  
+  virtual float
+  GetPixelError(int &pvsSize);
+  
+  virtual void
+  EvalPvsStat();
+
+  virtual void EvalPvsStat(const SimpleRayContainer &viewPoints);
+
+  virtual void InitGL();
+
+  virtual int GetWidth() const { return 0; }
+  virtual int GetHeight() const { return 0; }
+
+  unsigned int GetId(const unsigned char r, 
+					 const unsigned char g, 
+					 const unsigned char b) const;
+
+  inline const bool GetSnapErrorFrames() { return mSnapErrorFrames; }
+  inline const std::string GetSnapPrefix() { return mSnapPrefix; }
+
+  inline void SetSnapErrorFrames(bool snapframes) { mSnapErrorFrames = snapframes; }
+  inline void SetSnapPrefix(const std::string &pref) { mSnapPrefix = pref; }
+
+  virtual void ClearErrorBuffer();
+  
+  virtual float GetAvgPixelError() {
+	return mPvsStat.GetAvgError()*GetWidth()*GetHeight();
+  }
+
+  virtual float GetMaxPixelError() {
+	  return mPvsStat.GetMaxError()*GetWidth()*GetHeight();
+  }
+
+public:
+
+	int mCurrentFrame;
+	int mFrame;
+	bool mWireFrame;
+
+	PvsRenderStatistics mPvsStat;
+
+	int mPvsStatFrames;
+	struct PvsErrorEntry {
+		PvsErrorEntry() {}
+		float mError;
+		int mPvsSize;
+		Vector3 mPosition;
+		Vector3 mDirection;
+	};
+
+	vector<PvsErrorEntry> mPvsErrorBuffer;
+
+protected:
+
+	void CreateVertexArrays();
+	void DeleteVbos();
+	void EnableDrawArrays();
+	void DisableDrawArrays();
+
+	void RenderKdLeaf(KdLeaf *leaf);
+
+
+	//////////////////
+
+	PvsCache mPvsCache;
+
+	unsigned int mVboId;
+	vector<OcclusionQuery *> mOcclusionQueries;
+
+	ObjectContainer mObjects;
+
+	Vector3 mViewPoint;
+	Vector3 mViewDirection;
+
+	int timerId;
+	bool mUseFalseColors;
+	bool mUseForcedColors;
+
+	HaltonSequence halton;
+
+
+	bool mDetectEmptyViewSpace;
+	bool mSnapErrorFrames;
+
+	bool mRenderBoxes;
+
+	bool mUseGlLists;
+
+	std::string mSnapPrefix;
+
+	GLUquadric *mSphere;
+
+	KdTree *mKdTree;
+
+	Vector3 *mData;
+	unsigned int *mIndices;
+
+	bool mUseVbos;
+};
+
+
+/* Class implementing an OpenGl render buffer.
+*/
+class GlRendererBuffer: public GlRenderer
+{
+
+public:
+
+	GlRendererBuffer(SceneGraph *sceneGraph,
+		ViewCellsManager *viewcells,
+		KdTree *tree);
+
+	virtual ~GlRendererBuffer();
+
+	/** Evaluates render cost of a point sample.
+	@param sample the render cost sample to be evaluated
+	@param useOcclusionQueries if occlusion queries should be used or item buffer
+	@param threshold number of pixels / samples from where an object is considered visible.
+	*/
+	virtual void EvalRenderCostSample(RenderCostSample &sample,
+		const bool useOcclusionQueries,
+		const int threshold);
+
+	/** Evaluates render cost of a number of point samples. The point samples
+	are distributed uniformly over the defined view space.
+
+	@param numSamples the number of point samples taken
+	@param samples stores the taken point samples in a container
+	@param useOcclusionQueries if occlusion queries should be used or item buffer
+	@param threshold number of pixels / samples from where an object is considered visible.
+	*/
+	virtual void SampleRenderCost(const int numSamples, 
+								  vector<RenderCostSample> &samples,
+								  const bool useOcclusionQueries,
+								  const int threshold = 0);
+	/** Implerment in subclasses.
+	*/
+	virtual void EvalPvsStat();
+
+	virtual void EvalPvsStat(const SimpleRayContainer &viewPoints);
+
+	virtual int GetWidth() const = 0;
+	virtual int GetHeight() const  = 0; 
+
+	virtual void MakeCurrent() = 0;
+	virtual void DoneCurrent() = 0;
+
+	virtual bool ValidViewPoint();
+
+	virtual void SampleBeamContributions(
+										 Intersectable *sourceObject,
+										 Beam &beam,
+										 const int samples,
+										 BeamSampleStatistics &stat
+										 );
+
+	virtual void SampleViewpointContributions(
+											  Intersectable *sourceObject,
+											  const Vector3 viewPoint,
+											  Beam &beam,
+											  const int desiredSamples,
+											  BeamSampleStatistics &stat
+											  );
+
+	virtual void InitGL();
+	/** Computes rays from information gained with hw sampling-
+	*/
+	virtual void ComputeRays(Intersectable *sourceObj, VssRayContainer &rays);
+
+	virtual int ComputePvs() const = 0;
+
+	virtual int ComputePvs(ObjectContainer &objects, ObjectContainer &pvs) const = 0;
+
+
+protected:
+
+	unsigned int *mPixelBuffer;
+
+	static void GenQueries(const int numQueries);
+
+	virtual void SetupProjectionForViewPoint(const Vector3 &viewPoint, 
+											 const Beam &beam, 
+											 Intersectable *sourceObject);
+	/** Evaluates query for one direction using item buffer.
+	*/
+	virtual void EvalQueryWithItemBuffer();
+	/** Evaluates query for one direction using occlusion queries.
+	*/
+	virtual void EvalQueryWithOcclusionQueries();
+};
+
+
+/** Abstract class for implmenenting a gl render widget.
+*/
+class GlRendererWidget: public GlRenderer
+{
+public:
+
+	GlRendererWidget(SceneGraph *sceneGraph, ViewCellsManager *vcm, KdTree *kdTree):
+	  GlRenderer(sceneGraph, vcm, kdTree)
+	  {}
+
+	  GlRendererWidget() {}
+
+	  virtual ~GlRendererWidget() {}
+	  
+	  virtual void Show() {}
+};
+
+
+};
+
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/ViewCell.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/ViewCell.h	(revision 2560)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/ViewCell.h	(revision 2562)
@@ -298,9 +298,18 @@
 	}
 
-	int GetNumPiercingRays()
+	int GetNumPiercingRays() const
 	{
 		return mNumPiercingRays;
 	}
 
+	float GetDistance() const
+	{
+		return mDistance;
+	}
+
+	void SetDistance(float dist)
+	{
+		mDistance = dist;
+	}
 
 protected:
@@ -333,4 +342,7 @@
 	/// number of rays piercing this view cell
 	int mNumPiercingRays;
+
+	/// distance from the current view point
+	float mDistance;
 };
 
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/CHCRenderer.cpp
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/CHCRenderer.cpp	(revision 2562)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/CHCRenderer.cpp	(revision 2562)
@@ -0,0 +1,1728 @@
+#include "Mesh.h"
+#include "glInterface.h"
+#include "OcclusionQuery.h"
+#include "GlRenderer.h"
+#include "ViewCellsManager.h"
+#include "SceneGraph.h"
+#include "Viewcell.h"
+#include "Beam.h"
+#include "KdTree.h"
+#include "Environment.h"
+#include "Triangle3.h"
+#include "IntersectableWrapper.h"
+#include "BvHierarchy.h"
+#include "KdTree.h"
+
+#ifdef USE_CG
+
+#include <Cg/cg.h>
+#include <Cg/cgGL.h>
+
+#endif
+
+namespace GtpVisibilityPreprocessor {
+
+
+static bool arbQuerySupport = false;
+static bool nvQuerySupport = false;
+
+static GLuint frontDepthMap;
+static GLuint backDepthMap;
+
+const int depthMapSize = 512;
+
+
+static void InitExtensions() 
+{
+	GLenum err = glewInit();
+
+	if (GLEW_OK != err) 
+	{
+		// problem: glewInit failed, something is seriously wrong
+		cerr << "Error: " << glewGetErrorString(err) << endl;
+		exit(1);
+	}
+
+	if (GLEW_ARB_occlusion_query) 
+		arbQuerySupport = true;
+	
+	if (GLEW_NV_occlusion_query) 
+		nvQuerySupport = true;
+
+	if  (!arbQuerySupport && !nvQuerySupport)
+	{
+		cout << "I require the GL_ARB_occlusion_query or the GL_NV_occlusion_query OpenGL extension to work.\n";
+		exit(1);
+	}
+
+	if (!GLEW_ARB_vertex_buffer_object) 
+	{
+		cout << "vbos not supported" << endl;
+	}
+	else
+	{
+		cout << "vbos supported" << endl;
+	}
+}
+
+
+GlRenderer::GlRenderer(SceneGraph *sceneGraph,
+					   ViewCellsManager *viewCellsManager,
+					   KdTree *tree):
+Renderer(sceneGraph, viewCellsManager),
+mKdTree(tree),
+mUseFalseColors(false),
+mVboId(-1),
+mData(NULL),
+mIndices(NULL),
+//mUseVbos(true),
+mUseVbos(false),
+mCurrentFrame(-1)
+{
+	mSceneGraph->CollectObjects(&mObjects);
+
+	viewCellsManager->GetViewPoint(mViewPoint);
+
+	mViewDirection = Vector3(0,0,1);
+
+	mFrame = 0;
+	mWireFrame = false;
+	Environment::GetSingleton()->GetBoolValue("Preprocessor.detectEmptyViewSpace",
+		                                      mDetectEmptyViewSpace);
+	mSnapErrorFrames = true;
+	mSnapPrefix = "snap/";
+	mUseForcedColors = false;
+	mRenderBoxes = false;
+	//mUseGlLists = true;
+	mUseGlLists = false;
+
+	if (mViewCellsManager->GetViewCellPoints()->size())
+		mPvsStatFrames = (int)mViewCellsManager->GetViewCellPoints()->size();
+	else
+		Environment::GetSingleton()->GetIntValue("Preprocessor.pvsRenderErrorSamples", mPvsStatFrames);
+
+
+	mPvsErrorBuffer.resize(mPvsStatFrames);
+	ClearErrorBuffer();
+}
+
+
+GlRenderer::~GlRenderer()
+{
+	cerr<<"gl renderer destructor..\n";
+
+	CLEAR_CONTAINER(mOcclusionQueries);
+
+	DeleteVbos();
+
+	if (mData) delete [] mData;
+	if (mIndices) delete [] mIndices;
+
+	glDeleteBuffersARB(1, &mVboId);
+	cerr<<"done."<<endl;
+}
+
+
+void GlRenderer::RenderTriangle(TriangleIntersectable *object)
+{
+	Triangle3 &t = object->GetItem();
+
+	glBegin(GL_TRIANGLES);
+	Vector3 normal = t.GetNormal();
+	glNormal3f(normal.x, normal.y, normal.z);
+	glVertex3f(t.mVertices[0].x, t.mVertices[0].y, t.mVertices[0].z);
+	glVertex3f(t.mVertices[1].x, t.mVertices[1].y, t.mVertices[1].z);
+	glVertex3f(t.mVertices[2].x, t.mVertices[2].y, t.mVertices[2].z);
+	glEnd();
+}
+
+
+void GlRenderer::RenderIntersectable(Intersectable *object)
+{
+	if (!object)
+		return;
+
+	if (object->mRenderedFrame == mCurrentFrame)
+		return;
+
+	object->mRenderedFrame = mCurrentFrame;
+
+	//if (object->Mailed())	return;
+	//object->Mail();
+
+	glPushAttrib(GL_CURRENT_BIT);
+
+	if (mUseFalseColors)
+		SetupFalseColor(object->mId);
+
+	switch (object->Type()) 
+	{
+	case Intersectable::MESH_INSTANCE:
+		RenderMeshInstance((MeshInstance *)object);
+		break;
+	case Intersectable::VIEW_CELL:
+		RenderViewCell(static_cast<ViewCell *>(object));
+		break;
+	case Intersectable::TRANSFORMED_MESH_INSTANCE:
+		RenderTransformedMeshInstance(static_cast<TransformedMeshInstance *>(object));
+		break;
+	case Intersectable::TRIANGLE_INTERSECTABLE:
+		RenderTriangle(static_cast<TriangleIntersectable *>(object));
+		break;
+	case Intersectable::BVH_INTERSECTABLE: 
+		{
+			BvhNode *node = static_cast<BvhNode *>(object);
+
+			if (mRenderBoxes)
+				RenderBox(node->GetBoundingBox());
+			else
+				RenderBvhNode(node);
+			break;
+		}
+	case Intersectable::KD_INTERSECTABLE: 
+		{
+			KdNode *node = (static_cast<KdIntersectable *>(object))->GetItem();
+
+			if (mRenderBoxes)
+				RenderBox(mKdTree->GetBox(node));
+			else
+				RenderKdNode(node);
+			break;
+		}
+
+	default:
+		cerr<<"Rendering this object not yet implemented\n";
+		break;
+	}
+
+	glPopAttrib();
+}
+
+
+void GlRenderer::RenderRays(const VssRayContainer &rays)
+{
+	VssRayContainer::const_iterator it = rays.begin(), it_end = rays.end();
+
+	glBegin(GL_LINES);
+	
+	for (; it != it_end; ++it) 
+	{
+		VssRay *ray = *it;
+		const float importance = log10(1e3*ray->mWeightedPvsContribution)/3.0f;
+		
+		glColor3f(importance, importance, importance);
+		glVertex3fv(&ray->mOrigin.x);
+		glVertex3fv(&ray->mTermination.x);
+	}
+
+	glEnd();
+}
+
+
+void GlRenderer::RenderViewCell(ViewCell *vc)
+{
+	if (vc->GetMesh()) 
+	{
+		if (!mUseFalseColors) 
+		{
+			if (vc->GetValid()) 
+				glColor3f(0,1,0);
+			else
+				glColor3f(0,0,1);
+		}
+
+		RenderMesh(vc->GetMesh());
+	} 
+	else 
+	{
+		// render viewcells in the subtree
+		if (!vc->IsLeaf()) 
+		{
+			ViewCellInterior *vci = (ViewCellInterior *) vc;
+
+			ViewCellContainer::iterator it = vci->mChildren.begin();
+			for (; it != vci->mChildren.end(); ++it) 
+			{
+				RenderViewCell(*it);
+			}
+		} 
+		else 
+		{
+			// cerr<<"Empty viewcell mesh\n";
+		}
+	}
+}
+
+
+void GlRenderer::RenderMeshInstance(MeshInstance *mi)
+{
+	RenderMesh(mi->GetMesh());
+}
+
+
+void
+GlRenderer::RenderTransformedMeshInstance(TransformedMeshInstance *mi)
+{
+	// apply world transform before rendering
+	Matrix4x4 m;
+	mi->GetWorldTransform(m);
+
+	glPushMatrix();
+
+	glMultMatrixf((float *)m.x);
+
+	RenderMesh(mi->GetMesh());
+	
+	glPopMatrix();
+}
+
+
+void
+GlRenderer::SetupFalseColor(const unsigned int id)
+{
+	// swap bits of the color
+	glColor3ub(id&255, (id>>8)&255, (id>>16)&255);
+}
+
+
+unsigned int GlRenderer::GetId(const unsigned char r, 
+							   const unsigned char g, 
+							   const unsigned char b) const
+{
+	return r + (g << 8) + (b << 16);
+}
+
+
+void
+GlRenderer::SetupMaterial(Material *m)
+{
+  if (m)
+	glColor3fv(&(m->mDiffuseColor.r));
+}
+
+
+void GlRenderer::RenderMesh(Mesh *mesh)
+{
+	int i = 0;
+
+	if (!mUseFalseColors && !mUseForcedColors)
+		SetupMaterial(mesh->mMaterial);
+
+	for (i=0; i < mesh->mFaces.size(); i++) 
+	{
+		if (mWireFrame)
+			glBegin(GL_LINE_LOOP);
+		else
+			glBegin(GL_POLYGON);
+
+		Face *face = mesh->mFaces[i];
+		for (int j = 0; j < face->mVertexIndices.size(); j++) {
+			glVertex3fv(&mesh->mVertices[face->mVertexIndices[j]].x);
+		}
+		glEnd();
+	}
+}
+	
+void
+GlRenderer::InitGL()
+{
+  mSphere = (GLUquadric *)gluNewQuadric();
+  
+  glMatrixMode(GL_PROJECTION);
+  glLoadIdentity();
+  
+  glMatrixMode(GL_MODELVIEW);
+  glLoadIdentity();
+
+  glFrontFace(GL_CCW);
+  glCullFace(GL_BACK);
+  glEnable(GL_CULL_FACE);
+  glShadeModel(GL_FLAT);
+  glDepthFunc( GL_LESS );
+  glEnable(GL_DEPTH_TEST);
+  glEnable(GL_CULL_FACE);
+  
+  InitExtensions();
+
+  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
+
+  glEnable( GL_NORMALIZE );
+  
+  glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
+  
+  OcclusionQuery::GenQueries(mOcclusionQueries, 10);
+
+  CreateVertexArrays();
+}
+
+
+void
+GlRenderer::SetupProjection(const int w, const int h, const float angle)
+{
+  glViewport(0, 0, w, h);
+  glMatrixMode(GL_PROJECTION);
+  glLoadIdentity();
+  gluPerspective(angle, 1.0, 0.1, 2.0*Magnitude(mSceneGraph->GetBox().Diagonal()));
+  glMatrixMode(GL_MODELVIEW);
+}
+
+
+
+void
+GlRenderer::SetupCamera()
+{
+	Vector3 target = mViewPoint + mViewDirection;
+
+	Vector3 up(0,1,0);
+
+	if (abs(DotProd(mViewDirection, up)) > 0.99f)
+		up = Vector3(1, 0, 0);
+
+	glLoadIdentity();
+	gluLookAt(mViewPoint.x, mViewPoint.y, mViewPoint.z,
+		target.x, target.y, target.z,
+		up.x, up.y, up.z);
+}
+
+void
+GlRenderer::_RenderScene()
+{
+	ObjectContainer::const_iterator oi = mObjects.begin();
+	for (; oi != mObjects.end(); oi++)
+		RenderIntersectable(*oi);
+}
+
+void GlRenderer::_RenderSceneTrianglesWithDrawArrays()
+{
+	EnableDrawArrays();
+	
+	if (mUseVbos)
+		glBindBufferARB(GL_ARRAY_BUFFER_ARB, mVboId);
+
+	int offset = (int)mObjects.size() * 3;
+	char *arrayPtr = mUseVbos ? NULL : (char *)mData;
+	
+	glVertexPointer(3, GL_FLOAT, 0, (char *)arrayPtr);
+	glNormalPointer(GL_FLOAT, 0, (char *)arrayPtr + offset * sizeof(Vector3));
+	
+	glDrawArrays(GL_TRIANGLES, 0, (int)mObjects.size() * 3);
+	//DisableDrawArrays();
+}
+
+
+void GlRenderer::_RenderSceneTriangles()
+{
+	glBegin(GL_TRIANGLES);
+
+	ObjectContainer::const_iterator oi = mObjects.begin();
+	for (; oi != mObjects.end(); oi++) {
+
+		if ((*oi)->Type() == Intersectable::TRIANGLE_INTERSECTABLE) {
+			TriangleIntersectable *object = (TriangleIntersectable *)*oi;
+			Triangle3 &t = object->GetItem();
+
+			Vector3 normal = t.GetNormal();
+			glNormal3f(normal.x, normal.y, normal.z);
+			glVertex3f(t.mVertices[0].x, t.mVertices[0].y, t.mVertices[0].z);
+			glVertex3f(t.mVertices[1].x, t.mVertices[1].y, t.mVertices[1].z);
+			glVertex3f(t.mVertices[2].x, t.mVertices[2].y, t.mVertices[2].z);
+
+		}
+	}
+
+	glEnd();
+}
+
+
+bool
+GlRenderer::RenderScene()
+{
+  Intersectable::NewMail();
+
+#if 1
+  
+  _RenderSceneTrianglesWithDrawArrays();
+
+#else
+  static int glList = -1;
+  if (mUseGlLists) {
+	if (glList == -1) {
+	  glList = glGenLists(1);
+	  glNewList(glList, GL_COMPILE);
+	  _RenderSceneTriangles();
+	  glEndList();
+	}
+	
+	glCallList(glList);
+  } else
+	_RenderSceneTriangles();
+	
+#endif
+  return true;
+}
+
+
+void
+GlRendererBuffer::EvalQueryWithItemBuffer()
+{
+	// read back the texture
+	glReadPixels(0, 0,
+				GetWidth(), GetHeight(),
+				GL_RGBA,
+				GL_UNSIGNED_BYTE,
+				mPixelBuffer);
+		
+			
+	unsigned int *p = mPixelBuffer;
+			
+	for (int y = 0; y < GetHeight(); y++)
+	{
+		for (int x = 0; x < GetWidth(); x++, p++) 
+		{
+			unsigned int id = (*p) & 0xFFFFFF;
+
+			if (id != 0xFFFFFF)
+			{
+				++ mObjects[id]->mCounter;
+			}
+		}
+	}
+}
+
+
+
+/****************************************************************/
+/*               GlRendererBuffer implementation                */
+/****************************************************************/
+
+
+
+GlRendererBuffer::GlRendererBuffer(SceneGraph *sceneGraph,
+								   ViewCellsManager *viewcells,
+								   KdTree *tree):
+GlRenderer(sceneGraph, viewcells, tree)  
+{ 
+  mPixelBuffer = NULL; 
+  // implement width and height in subclasses
+}
+
+
+void
+GlRendererBuffer::EvalQueryWithOcclusionQueries(
+									   //RenderCostSample &sample
+									   )
+{
+	glDepthFunc(GL_LEQUAL);
+		
+	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+	glDepthMask(GL_FALSE);
+
+
+	// simulate detectemptyviewspace using backface culling
+	if (mDetectEmptyViewSpace) 
+	{
+		glEnable(GL_CULL_FACE);
+		//cout << "culling" << endl;
+	}
+	else
+	{
+		//cout << "not culling" << endl;
+		glDisable(GL_CULL_FACE);
+	}
+
+	
+	//const int numQ = 1;
+	const int numQ = (int)mOcclusionQueries.size();
+	
+	//glFinish();
+#if 0
+	//-- now issue queries for all objects
+	for (int j = 0; j < (int)mObjects.size(); ++ j) 
+	{
+		mOcclusionQueries[j]->BeginQuery();
+		RenderIntersectable(mObjects[j]);
+		mOcclusionQueries[j]->EndQuery();
+
+		unsigned int pixelCount;
+
+		pixelCount = mOcclusionQueries[j]->GetQueryResult();
+		
+		mObjects[j]->mCounter += pixelCount;
+	}
+#else
+
+	int q = 0;
+
+	//-- now issue queries for all objects
+	for (int j = 0; j < (int)mObjects.size(); j += q) 
+	{	
+		for (q = 0; ((j + q) < (int)mObjects.size()) && (q < numQ); ++ q) 
+		{
+			//glFinish();
+			mOcclusionQueries[q]->BeginQuery();
+			
+			RenderIntersectable(mObjects[j + q]);
+		
+			mOcclusionQueries[q]->EndQuery();
+			//glFinish();
+		}
+		//cout << "q: " << q << endl;
+		// collect results of the queries
+		for (int t = 0; t < q; ++ t) 
+		{
+			unsigned int pixelCount;
+		
+			//-- reenable other state
+#if 0
+			bool available;
+
+			do 
+			{
+				available = mOcclusionQueries[t]->ResultAvailable();
+				
+				if (!available) cout << "W";
+			} 
+			while (!available);
+#endif
+
+			pixelCount = mOcclusionQueries[t]->GetQueryResult();
+
+			//if (pixelCount > 0)
+			//	cout <<"o="<<j+q<<" q="<<mOcclusionQueries[q]->GetQueryId()<<" pc="<<pixelCount<<" ";
+			mObjects[j + t]->mCounter += pixelCount;
+		
+		}
+
+		//j += q;
+	}
+#endif
+	//glFinish();
+	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+	glDepthMask(GL_TRUE);
+	
+	glEnable(GL_CULL_FACE);
+}
+
+
+void
+GlRenderer::RandomViewPoint()
+{ 
+  // do not use this function since it could return different viewpoints for
+  // different executions of the algorithm
+
+  //  mViewCellsManager->GetViewPoint(mViewPoint);
+
+  while (1) {
+	Vector3 pVector = Vector3(halton.GetNumber(1),
+							  halton.GetNumber(2),
+							  halton.GetNumber(3));
+	
+	mViewPoint =  mViewCellsManager->GetViewSpaceBox().GetPoint(pVector);
+	ViewCell *v = mViewCellsManager->GetViewCell(mViewPoint);
+	if (v && v->GetValid())
+	  break;
+	// generate a new vector
+	halton.GenerateNext();
+  }
+  
+  Vector3 dVector = Vector3(2*M_PI*halton.GetNumber(4),
+							M_PI*halton.GetNumber(5),
+							0.0f);
+  
+  mViewDirection = Normalize(Vector3(sin(dVector.x),
+									 //									 cos(dVector.y),
+									 0.0f,
+									 cos(dVector.x)));
+  halton.GenerateNext();
+}
+
+
+void
+GlRenderer::RenderBox(const AxisAlignedBox3 &box)
+{
+
+  glBegin(GL_LINE_LOOP);
+  glVertex3d(box.Min().x, box.Max().y, box.Min().z );
+  glVertex3d(box.Max().x, box.Max().y, box.Min().z );
+  glVertex3d(box.Max().x, box.Min().y, box.Min().z );
+  glVertex3d(box.Min().x, box.Min().y, box.Min().z );
+  glEnd();
+
+  glBegin(GL_LINE_LOOP);
+  glVertex3d(box.Min().x, box.Min().y, box.Max().z );
+  glVertex3d(box.Max().x, box.Min().y, box.Max().z );
+  glVertex3d(box.Max().x, box.Max().y, box.Max().z );
+  glVertex3d(box.Min().x, box.Max().y, box.Max().z );
+  glEnd();
+
+  glBegin(GL_LINE_LOOP);
+  glVertex3d(box.Max().x, box.Min().y, box.Min().z );
+  glVertex3d(box.Max().x, box.Min().y, box.Max().z );
+  glVertex3d(box.Max().x, box.Max().y, box.Max().z );
+  glVertex3d(box.Max().x, box.Max().y, box.Min().z );
+  glEnd();
+
+  glBegin(GL_LINE_LOOP);
+  glVertex3d(box.Min().x, box.Min().y, box.Min().z );
+  glVertex3d(box.Min().x, box.Min().y, box.Max().z );
+  glVertex3d(box.Min().x, box.Max().y, box.Max().z );
+  glVertex3d(box.Min().x, box.Max().y, box.Min().z );
+  glEnd();
+
+  glBegin(GL_LINE_LOOP);
+  glVertex3d(box.Min().x, box.Min().y, box.Min().z );
+  glVertex3d(box.Max().x, box.Min().y, box.Min().z );
+  glVertex3d(box.Max().x, box.Min().y, box.Max().z );
+  glVertex3d(box.Min().x, box.Min().y, box.Max().z );
+  glEnd();
+
+  glBegin(GL_LINE_LOOP);
+  glVertex3d(box.Min().x, box.Max().y, box.Min().z );
+  glVertex3d(box.Max().x, box.Max().y, box.Min().z );
+  glVertex3d(box.Max().x, box.Max().y, box.Max().z );
+  glVertex3d(box.Min().x, box.Max().y, box.Max().z );
+
+  glEnd();
+
+}
+
+void
+GlRenderer::RenderBvhNode(BvhNode *node)
+{
+  if (node->IsLeaf()) {
+	BvhLeaf *leaf = (BvhLeaf *) node;
+
+#if 0
+	if (leaf->mGlList == 0) {
+	  leaf->mGlList = glGenLists(1);
+	  if (leaf->mGlList != 0)
+		glNewList(leaf->mGlList, GL_COMPILE);
+	  
+	  for (int i=0; i < leaf->mObjects.size(); i++)
+		RenderIntersectable(leaf->mObjects[i]);
+	  
+	  if (leaf->mGlList != 0)
+		glEndList();
+	}
+	
+	if (leaf->mGlList != 0)
+	  glCallList(leaf->mGlList);
+#else
+	for (int i=0; i < leaf->mObjects.size(); i++)
+	  RenderIntersectable(leaf->mObjects[i]);
+#endif
+  } else {
+	BvhInterior *in = (BvhInterior *)node;
+	RenderBvhNode(in->GetBack());
+	RenderBvhNode(in->GetFront());
+  }
+}
+
+void
+GlRenderer::RenderKdNode(KdNode *node)
+{
+	if (node->IsLeaf()) 
+	{
+#if 1
+		RenderKdLeaf(static_cast<KdLeaf *>(node));
+#else
+		KdLeaf *leaf = (KdLeaf *)node;
+		for (int i=0; i < leaf->mObjects.size(); i++) 
+		{
+			RenderIntersectable(leaf->mObjects[i]);
+		}
+#endif
+	} 
+	else 
+	{
+		KdInterior *in = (KdInterior *)node;
+		RenderKdNode(in->mBack);
+		RenderKdNode(in->mFront);
+	}
+}
+
+
+
+
+void
+GlRendererBuffer::EvalRenderCostSample(RenderCostSample &sample,
+									   const bool useOcclusionQueries,
+									   const int threshold
+									   )
+{
+	// choose a random view point
+	mViewCellsManager->GetViewPoint(mViewPoint);
+	sample.mPosition = mViewPoint;
+	//cout << "viewpoint: " << mViewPoint << endl;
+
+	// take a render cost sample by rendering a cube
+	Vector3 directions[6];
+
+	directions[0] = Vector3(1,0,0);
+	directions[1] = Vector3(0,1,0);
+	directions[2] = Vector3(0,0,1);
+	directions[3] = Vector3(-1,0,0);
+	directions[4] = Vector3(0,-1,0);
+	directions[5] = Vector3(0,0,-1);
+
+	sample.mVisibleObjects = 0;
+
+	// reset object counters
+	ObjectContainer::const_iterator it, it_end = mObjects.end();
+
+	for (it = mObjects.begin(); it != it_end; ++ it) 
+	{
+		(*it)->mCounter = 0;
+
+	}
+
+	++ mFrame;
+
+	//glCullFace(GL_FRONT);
+	glCullFace(GL_BACK);
+	glDisable(GL_CULL_FACE);
+
+
+	// query all 6 directions for a full point sample
+	for (int i = 0; i < 6; ++ i) 
+	{
+		mViewDirection = directions[i];
+		SetupCamera();
+
+		glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+		//glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);	glDepthMask(GL_TRUE);
+		glDepthFunc(GL_LESS);
+
+		mUseFalseColors = true;
+
+		// the actual scene rendering fills the depth (for occlusion queries)
+		// and the frame buffer (for item buffer)
+		RenderScene();
+
+
+		if (0) 
+		{
+			char filename[256];
+			sprintf(filename, "snap/frame-%04d-%d.png", mFrame, i);
+			//		  QImage im = toImage();
+			//		  im.save(filename, "PNG");
+		}
+
+		// evaluate the sample
+		if (useOcclusionQueries) 
+		{
+			EvalQueryWithOcclusionQueries();
+		}
+		else 
+		{
+			EvalQueryWithItemBuffer();
+		}
+	}  
+
+	// now evaluate the statistics over that sample
+	// currently only the number of visible objects is taken into account
+	sample.Reset();
+
+	for (it = mObjects.begin(); it != it_end; ++ it) 
+	{
+		Intersectable *obj = *it;
+		if (obj->mCounter >= threshold) 
+		{
+			++ sample.mVisibleObjects;
+			sample.mVisiblePixels += obj->mCounter;
+		}
+	}
+
+	//cout << "RS=" << sample.mVisibleObjects << " ";
+}
+
+
+GlRendererBuffer::~GlRendererBuffer()
+{
+#if 0
+#ifdef USE_CG
+	if (sCgFragmentProgram)
+		cgDestroyProgram(sCgFragmentProgram);
+	if (sCgContext)
+		cgDestroyContext(sCgContext);
+#endif
+#endif
+
+}
+
+
+void
+GlRendererBuffer::SampleRenderCost(const int numSamples,
+								   vector<RenderCostSample> &samples,
+								   const bool useOcclusionQueries,
+								   const int threshold
+								   )
+{
+	MakeCurrent();
+
+	if (mPixelBuffer == NULL)
+		mPixelBuffer = new unsigned int[GetWidth()*GetHeight()];
+
+	// using 90 degree projection to capture 360 view with 6 samples
+	SetupProjection(GetHeight(), GetHeight(), 90.0f);
+
+	//samples.resize(numSamples);
+	halton.Reset();
+
+	// the number of queries queried in batch mode
+	const int numQ = 500;
+
+	//const int numQ = (int)mObjects.size();
+	if (useOcclusionQueries)
+	{
+		cout << "\ngenerating " << numQ << " queries ... ";
+		OcclusionQuery::GenQueries(mOcclusionQueries, numQ);
+		cout << "finished" << endl;
+	}
+
+	// sampling queries 
+	for (int i = 0; i < numSamples; ++ i)
+	{
+		cout << ".";
+		EvalRenderCostSample(samples[i], useOcclusionQueries, threshold);
+	}
+
+	DoneCurrent();
+}
+
+
+
+
+
+void
+GlRenderer::ClearErrorBuffer()
+{
+  for (int i=0; i < mPvsStatFrames; i++) {
+	mPvsErrorBuffer[i].mError = 1.0f;
+  }
+  mPvsStat.maxError = 0.0f;
+}
+
+
+void
+GlRendererBuffer::EvalPvsStat()
+{
+	MakeCurrent();
+	
+	GlRenderer::EvalPvsStat();
+	
+	DoneCurrent();
+  //  mRenderingFinished.wakeAll();
+}
+
+
+void GlRendererBuffer::EvalPvsStat(const SimpleRayContainer &viewPoints)
+{
+	MakeCurrent();
+
+	GlRenderer::EvalPvsStat(viewPoints);
+  
+	DoneCurrent();
+}
+
+
+void GlRendererBuffer::SampleBeamContributions(Intersectable *sourceObject,
+											   Beam &beam,
+											   const int desiredSamples,
+											   BeamSampleStatistics &stat)
+{
+	// TODO: should be moved out of here (not to be done every time)
+	// only back faces are interesting for the depth pass
+	glShadeModel(GL_FLAT);
+	glDisable(GL_LIGHTING);
+
+	// needed to kill the fragments for the front buffer
+	glEnable(GL_ALPHA_TEST);
+	glAlphaFunc(GL_GREATER, 0);
+
+	// assumes that the beam is constructed and contains kd-tree nodes
+	// and viewcells which it intersects
+  
+  
+	// Get the number of viewpoints to be sampled
+	// Now it is a sqrt but in general a wiser decision could be made.
+	// The less viewpoints the better for rendering performance, since less passes
+	// over the beam is needed.
+	// The viewpoints could actually be generated outside of the bounding box which
+	// would distribute the 'efective viewpoints' of the object surface and thus
+	// with a few viewpoints better sample the viewpoint space....
+
+	//TODO: comment in
+	//int viewPointSamples = sqrt((float)desiredSamples);
+	int viewPointSamples = max(desiredSamples / (GetWidth() * GetHeight()), 1);
+	
+	// the number of direction samples per pass is given by the number of viewpoints
+	int directionalSamples = desiredSamples / viewPointSamples;
+	
+	Debug << "directional samples: " << directionalSamples << endl;
+	for (int i = 0; i < viewPointSamples; ++ i) 
+	{
+		Vector3 viewPoint = beam.mBox.GetRandomPoint();
+		
+		// perhaps the viewpoint should be shifted back a little bit so that it always lies
+		// inside the source object
+		// 'ideally' the viewpoints would be distributed on the soureObject surface, but this
+        // would require more complicated sampling (perhaps hierarchical rejection sampling of
+		// the object surface is an option here - only the mesh faces which are inside the box
+		// are considered as candidates) 
+		
+		SampleViewpointContributions(sourceObject,
+									 viewPoint,
+									 beam,
+									 directionalSamples,
+									 stat);
+	}
+
+
+	// note:
+	// this routine would be called only if the number of desired samples is sufficiently
+	// large - for other rss tree cells the cpu based sampling is perhaps more efficient
+	// distributing the work between cpu and gpu would also allow us to place more sophisticated
+	// sample distributions (silhouette ones) using the cpu and the jittered once on the GPU
+	// in order that thios scheme is working well the gpu render buffer should run in a separate
+	// thread than the cpu sampler, which would not be such a big problem....
+
+	// disable alpha test again
+	glDisable(GL_ALPHA_TEST);
+}
+
+
+
+void GlRendererBuffer::SampleViewpointContributions(Intersectable *sourceObject,
+													const Vector3 viewPoint,
+													Beam &beam,
+													const int samples,
+                                                    BeamSampleStatistics &stat)
+{
+    // 1. setup the view port to match the desired samples
+	glViewport(0, 0, samples, samples);
+
+	// 2. setup the projection matrix and view matrix to match the viewpoint + beam.mDirBox
+	SetupProjectionForViewPoint(viewPoint, beam, sourceObject);
+
+
+	// 3. reset z-buffer to 0 and render the source object for the beam
+	//    with glCullFace(Enabled) and glFrontFace(GL_CW)
+	//    save result to the front depth map
+	//    the front depth map holds ray origins
+
+
+	// front depth buffer must be initialised to 0
+	float clearDepth;
+	
+	glGetFloatv(GL_DEPTH_CLEAR_VALUE, &clearDepth);
+	glClearDepth(0.0f);
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+
+
+	// glFrontFace(GL_CCW);
+	glEnable(GL_CULL_FACE);
+	glCullFace(GL_FRONT);
+	glColorMask(0, 0, 0, 0);
+	
+
+	// stencil is increased where the source object is located
+	glEnable(GL_STENCIL_TEST);	
+	glStencilFunc(GL_ALWAYS, 0x1, 0x1);
+	glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
+
+
+#if 0
+	static int glSourceObjList = -1;	 
+	if (glSourceObjList != -1) 
+	{
+		glSourceObjList = glGenLists(1);
+		glNewList(glSourceObjList, GL_COMPILE);
+
+		RenderIntersectable(sourceObject);
+	
+		glEndList();
+	}
+	glCallList(glSourceObjList);
+
+#else
+	RenderIntersectable(sourceObject);
+
+#endif	
+
+	 // copy contents of the front depth buffer into depth texture
+	glBindTexture(GL_TEXTURE_2D, frontDepthMap);	
+	glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, depthMapSize, depthMapSize);
+
+	// reset clear function
+	glClearDepth(clearDepth);
+	
+	
+	// 4. set up the termination depth buffer (= standard depth buffer)
+	//    only rays which have non-zero entry in the origin buffer are valid since
+	//    they realy start on the object surface (this is tagged by setting a
+	//    stencil buffer bit at step 3).
+	
+	glStencilFunc(GL_EQUAL, 0x1, 0x1);
+	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+	glDepthMask(1);
+
+	glEnable(GL_DEPTH_TEST);
+		
+	glEnable(GL_CULL_FACE);
+	glCullFace(GL_BACK);
+
+	// setup front depth buffer
+	glEnable(GL_TEXTURE_2D);
+	
+#if 0
+#ifdef USE_CG
+	// bind pixel shader implementing the front depth buffer functionality
+	cgGLBindProgram(sCgFragmentProgram);
+	cgGLEnableProfile(sCgFragmentProfile);
+#endif
+#endif
+	// 5. render all objects inside the beam 
+	//    we can use id based false color to read them back for gaining the pvs
+
+	glColorMask(1, 1, 1, 1);
+
+	
+	// if objects not stored in beam => extract objects
+	if (beam.mFlags & !Beam::STORE_OBJECTS)
+	{
+		vector<KdNode *>::const_iterator it, it_end = beam.mKdNodes.end();
+
+		Intersectable::NewMail();
+		for (it = beam.mKdNodes.begin(); it != it_end; ++ it)
+		{
+			mKdTree->CollectObjects(*it, beam.mObjects);
+		}
+	}
+
+
+	//    (objects can be compiled to a gl list now so that subsequent rendering for
+	//    this beam is fast - the same hold for step 3)
+	//    Afterwards we have two depth buffers defining the ray origin and termination
+	
+
+#if 0
+	static int glObjList = -1; 
+	if (glObjList != -1) 
+	{
+		glObjList = glGenLists(1);
+		glNewList(glObjList, GL_COMPILE);
+	
+		ObjectContainer::const_iterator it, it_end = beam.mObjects.end();
+		for (it = beam.mObjects.begin(); it != it_end; ++ it)
+		{
+			// render all objects except the source object
+			if (*it != sourceObject)
+				RenderIntersectable(*it);
+		}
+		
+		glEndList();
+	}
+
+	glCallList(glObjList);
+#else
+	ObjectContainer::const_iterator it, it_end = beam.mObjects.end();
+	for (it = beam.mObjects.begin(); it != it_end; ++ it)
+	{	
+		// render all objects except the source object
+		if (*it != sourceObject)
+			RenderIntersectable(*it);
+	}
+#endif
+	
+   	// 6. Use occlusion queries for all viewcell meshes associated with the beam ->
+	//     a fragment passes if the corresponding stencil fragment is set and its depth is
+	//     between origin and termination buffer
+
+	// create new queries if necessary
+	OcclusionQuery::GenQueries(mOcclusionQueries, (int)beam.mViewCells.size());
+
+	// check whether any backfacing polygon would pass the depth test?
+	// matt: should check both back /front facing because of dual depth buffer
+	// and danger of cutting the near plane with front facing polys.
+	
+	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+	glDepthMask(GL_FALSE);
+	glDisable(GL_CULL_FACE);
+
+  
+	ViewCellContainer::const_iterator vit, vit_end = beam.mViewCells.end();
+
+	int queryIdx = 0;
+
+	for (vit = beam.mViewCells.begin(); vit != vit_end; ++ vit)
+	{
+		mOcclusionQueries[queryIdx ++]->BeginQuery();
+		RenderIntersectable(*vit);
+		mOcclusionQueries[queryIdx]->EndQuery();
+
+		++ queryIdx;
+	}
+
+	// at this point, if possible, go and do some other computation
+
+	// 7. The number of visible pixels is the number of sample rays which see the source
+	//    object from the corresponding viewcell -> remember these values for later update
+	//   of the viewcell pvs - or update immediately?
+
+	queryIdx = 0;
+
+	for (vit = beam.mViewCells.begin(); vit != vit_end; ++ vit)
+	{
+		// fetch queries
+		unsigned int pixelCount = mOcclusionQueries[queryIdx ++]->GetQueryResult();
+
+		if (pixelCount)
+			Debug << "view cell " << (*vit)->GetId() << " visible pixels: " << pixelCount << endl;
+	}
+	
+
+	// 8. Copmpute rendering statistics
+	// In general it is not neccessary to remember to extract all the rays cast. I hope it
+	// would be sufficient to gain only the intergral statistics about the new contributions
+	// and so the rss tree would actually store no new rays (only the initial ones)
+	// the subdivision of the tree would only be driven by the statistics (the glrender could
+	// evaluate the contribution entropy for example)
+	// However might be an option to extract/store only those the rays which made a contribution
+	// (new viewcell has been discovered) or relative contribution greater than a threshold ... 
+
+	ObjectContainer pvsObj;
+	stat.pvsSize = ComputePvs(beam.mObjects, pvsObj);
+	
+	// to gain ray source and termination
+	// copy contents of ray termination buffer into depth texture
+	// and compare with ray source buffer
+#if 0
+	VssRayContainer rays;
+
+	glBindTexture(GL_TEXTURE_2D, backDepthMap);	
+	glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, depthMapSize, depthMapSize);
+
+	ComputeRays(Intersectable *sourceObj, rays);
+
+#endif
+
+	////////
+	//-- cleanup
+
+	// reset gl state
+	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+	glDepthMask(GL_TRUE);
+	glEnable(GL_CULL_FACE);
+	glDisable(GL_STENCIL_TEST);
+
+#if 0
+#ifdef USE_CG
+	cgGLDisableProfile(sCgFragmentProfile);
+#endif
+#endif
+
+	glDisable(GL_TEXTURE_2D);
+
+	// remove objects from beam
+	if (beam.mFlags & !Beam::STORE_OBJECTS)
+		beam.mObjects.clear();
+}
+
+
+void GlRendererBuffer::SetupProjectionForViewPoint(const Vector3 &viewPoint, 
+												   const Beam &beam, 
+												   Intersectable *sourceObject)
+{
+	float left, right, bottom, top, znear, zfar;
+
+	beam.ComputePerspectiveFrustum(left, right, bottom, top, znear, zfar,
+								   mSceneGraph->GetBox());
+
+	//Debug << left << " " << right << " " << bottom << " " << top << " " << znear << " " << zfar << endl;
+	glMatrixMode(GL_PROJECTION);
+	glLoadIdentity();
+	glFrustum(left, right, bottom, top, znear, zfar);
+	//glFrustum(-1, 1, -1, 1, 1, 20000);
+
+    const Vector3 center = viewPoint + beam.GetMainDirection() * (zfar - znear) * 0.3f;
+	const Vector3 up = 
+		Normalize(CrossProd(beam.mPlanes[0].mNormal, beam.mPlanes[4].mNormal));
+
+#ifdef GTP_DEBUG
+	Debug << "view point: " << viewPoint << endl;
+	Debug << "eye: " << center << endl;
+	Debug << "up: " << up << endl;
+#endif
+
+	glMatrixMode(GL_MODELVIEW);
+	glLoadIdentity();
+	gluLookAt(viewPoint.x, viewPoint.y, viewPoint.z, 
+			  center.x, center.y, center.z,			  
+			  up.x, up.y, up.z);
+}		
+
+  
+void GlRendererBuffer::InitGL()
+{
+	MakeCurrent(); 
+	GlRenderer::InitGL();
+
+	// initialise dual depth buffer textures
+	glGenTextures(1, &frontDepthMap);
+	glBindTexture(GL_TEXTURE_2D, frontDepthMap);
+
+	glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, depthMapSize, 
+		depthMapSize, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
+
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+
+	glGenTextures(1, &backDepthMap);
+	glBindTexture(GL_TEXTURE_2D, backDepthMap);
+
+	glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, depthMapSize, 
+		depthMapSize, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+
+#if 0
+#ifdef USE_CG
+
+	// cg initialization
+	cgSetErrorCallback(handleCgError);
+	sCgContext = cgCreateContext();
+
+	if (cgGLIsProfileSupported(CG_PROFILE_ARBFP1))
+		sCgFragmentProfile = CG_PROFILE_ARBFP1;
+	else 
+	{
+		// try FP30
+		if (cgGLIsProfileSupported(CG_PROFILE_FP30))
+			sCgFragmentProfile = CG_PROFILE_FP30;
+		else 
+		{
+			Debug << "Neither arbfp1 or fp30 fragment profiles supported on this system" << endl;
+			exit(1);
+		}
+	}
+
+	sCgFragmentProgram = cgCreateProgramFromFile(sCgContext,
+		                                         CG_SOURCE, "../src/dual_depth.cg",
+												 sCgFragmentProfile,
+												 NULL, 
+												 NULL);
+
+	if (!cgIsProgramCompiled(sCgFragmentProgram))
+		cgCompileProgram(sCgFragmentProgram);
+
+	cgGLLoadProgram(sCgFragmentProgram);
+	cgGLBindProgram(sCgFragmentProgram);
+
+	Debug << "---- PROGRAM BEGIN ----\n" <<
+		cgGetProgramString(sCgFragmentProgram, CG_COMPILED_PROGRAM) << "---- PROGRAM END ----\n";
+
+#endif
+
+#endif
+	DoneCurrent();
+}
+
+
+void GlRendererBuffer::ComputeRays(Intersectable *sourceObj, VssRayContainer &rays)
+{
+	for (int i = 0; i < depthMapSize * depthMapSize; ++ i)
+	{
+		//todo glGetTexImage()
+	}
+}
+
+bool GlRendererBuffer::ValidViewPoint()
+{	
+	MakeCurrent();
+
+	SetupProjection(GetWidth(), GetHeight());
+
+	bool result = GlRenderer::ValidViewPoint();
+
+	DoneCurrent();
+	
+	return result;
+}
+
+
+void
+GlRenderer::EvalPvsStat()
+{
+  mPvsStat.Reset();
+  halton.Reset();
+
+  SetupProjection(GetWidth(), GetHeight());
+
+  cout<<"mPvsStatFrames="<<mPvsStatFrames<<endl;
+  
+  for (int i=0; i < mPvsStatFrames; i++) {
+	float err;
+	// set frame id for saving the error buffer
+	mFrame = i;
+	RandomViewPoint();
+
+ 	if (mPvsErrorBuffer[i].mError == 1.0f) {
+	  // check if the view point is valid
+	  if (!ValidViewPoint())
+		mPvsErrorBuffer[i].mError = -1.0f;
+
+	  // manualy corrected view point
+	  if (mFrame == 5105)
+		mPvsErrorBuffer[i].mError = -1.0f;
+	}
+	
+	
+	// atlanta problematic frames: 325 525 691 1543
+#if 0
+	if (mFrame != 325 &&
+		mFrame != 525 &&
+		mFrame != 691 &&
+		mFrame != 1543)
+	  mPvsErrorBuffer[i] = -1;
+	else {
+	  Debug<<"frame ="<<mFrame<<" vp="<<mViewPoint<<" vd="<<mViewDirection<<endl;
+	}
+#endif
+	
+ 	if (mPvsErrorBuffer[i].mError > 0.0f) {
+	  int pvsSize;
+	  
+	  float error = GetPixelError(pvsSize);
+	  mPvsErrorBuffer[i].mError = error;
+	  mPvsErrorBuffer[i].mPvsSize = pvsSize;
+
+	  //	  emit UpdatePvsErrorItem(i,
+	  //							  mPvsErrorBuffer[i]);
+	  cout<<"("<<i<<","<<mPvsErrorBuffer[i].mError<<")";
+	  //	  swapBuffers();
+	}
+	
+	err = mPvsErrorBuffer[i].mError;
+	
+	if (err >= 0.0f) {
+	  if (err > mPvsStat.maxError)
+		mPvsStat.maxError = err;
+	  mPvsStat.sumError += err;
+	  mPvsStat.sumPvsSize += mPvsErrorBuffer[i].mPvsSize;
+	  
+	  if (err == 0.0f)
+		mPvsStat.errorFreeFrames++;
+	  mPvsStat.frames++;
+	}
+  }
+  
+  glFinish();
+  cout<<endl<<flush;
+}
+
+
+void GlRenderer::EvalPvsStat(const SimpleRayContainer &viewPoints)
+{
+  mPvsStat.Reset();
+
+  SetupProjection(GetWidth(), GetHeight());
+  
+  cout << "mPvsStatFrames=" << mPvsStatFrames << endl;
+  
+  SimpleRayContainer::const_iterator sit, sit_end = viewPoints.end();
+  int i = 0;
+  
+  for (sit = viewPoints.begin(); sit != sit_end; ++ sit, ++ i) 
+	{
+	  
+	  //cout << "view point: " << (*sit) << endl;;
+	  SimpleRay sray = *sit;
+	  
+	  float err;
+	  
+	  // set frame id for saving the error buffer
+	  mFrame = i;
+	  mViewPoint = sray.mOrigin;
+	  mViewDirection = sray.mDirection;
+	  
+	  if (mPvsErrorBuffer[i].mError > 0.0f) 
+		{
+		  int pvsSize;
+		  
+		  // compute the pixel error
+		  float error = GetPixelError(pvsSize);
+		  
+		  mPvsErrorBuffer[i].mError = error;
+		  mPvsErrorBuffer[i].mPvsSize = pvsSize;
+		  
+		  cout << "(" << i << "," << mPvsErrorBuffer[i].mError <<")";
+		}
+	  
+	  err = mPvsErrorBuffer[i].mError;
+	  
+	  if (err >= 0.0f) 
+		{
+		  if (err > mPvsStat.maxError)
+			mPvsStat.maxError = err;
+		  
+		  mPvsStat.sumError += err;
+			mPvsStat.sumPvsSize += mPvsErrorBuffer[i].mPvsSize;
+			
+			if (err == 0.0f)
+			  ++ mPvsStat.errorFreeFrames;
+			
+			++ mPvsStat.frames;
+		}
+	}
+  
+  glFinish();
+  cout << endl << flush;
+}
+
+
+
+bool
+GlRenderer::ValidViewPoint()
+{
+	//cout<<"VV4 ";
+	if (!mDetectEmptyViewSpace)
+		return true;
+	//cout << "vp: " << mViewPoint << " dir: " << mViewDirection << endl;
+
+	OcclusionQuery *query = mOcclusionQueries[0];
+
+	// now check whether any backfacing polygon would pass the depth test
+	SetupCamera();
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+	glEnable( GL_CULL_FACE );
+	glCullFace(GL_BACK);
+
+	//cout<<"VV1 ";
+	RenderScene();
+
+	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+	glDepthMask(GL_FALSE);
+	glDisable( GL_CULL_FACE );
+
+	query->BeginQuery();
+
+	//  cout<<"VV2 ";
+	RenderScene();
+	//  cout<<"VV3 ";
+
+	query->EndQuery();
+
+	// at this point, if possible, go and do some other computation
+	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+	glDepthMask(GL_TRUE);
+	glEnable( GL_CULL_FACE );
+
+	//  int wait = 0;
+	//  while (!query.ResultAvailable()) {
+	//	wait++;
+	//  }
+
+	// reenable other state
+	unsigned int pixelCount = query->GetQueryResult();
+	//  cout<<"VV4 ";
+
+	//cout<<"count: " << pixelCount<<endl;
+
+	if (pixelCount > 0)
+	{
+		return false; // backfacing polygon found -> not a valid viewspace sample
+	}
+	return true;
+}
+
+
+float GlRenderer::GetPixelError(int &pvsSize)
+{
+  return -1.0f;
+}
+
+
+void GlRenderer::RenderViewPoint()
+{
+	mWireFrame = true;
+	glPushMatrix();
+	glTranslatef(mViewPoint.x, mViewPoint.y, mViewPoint.z);
+	glScalef(5.0f,5.0f,5.0f);
+	glPushAttrib(GL_CURRENT_BIT);
+	glColor3f(1.0f, 0.0f, 0.0f);
+	gluSphere((::GLUquadric *)mSphere,
+		1e-3*Magnitude(mViewCellsManager->GetViewSpaceBox().Size()), 6, 6);
+	glPopAttrib();
+	glPopMatrix();
+	mWireFrame = false;
+}
+
+
+void GlRenderer::EnableDrawArrays()
+{
+	glEnableClientState(GL_VERTEX_ARRAY);
+	glEnableClientState(GL_NORMAL_ARRAY);
+}
+
+
+void GlRenderer::DisableDrawArrays()
+{
+	glDisableClientState(GL_VERTEX_ARRAY);
+	glDisableClientState(GL_NORMAL_ARRAY);
+}
+
+
+#if 0
+
+void GlRenderer::RenderKdLeaf(KdLeaf *leaf)
+{
+	int bufferSize = 0;
+
+	// count #new triangles
+	for (size_t i = 0; i < leaf->mObjects.size(); ++ i)
+	{
+		TriangleIntersectable *obj = static_cast<TriangleIntersectable *>(leaf->mObjects[i]);
+
+		// check if already rendered
+		if (!obj->Mailed())
+			bufferSize += 3;
+		//else cout << obj->mMailbox << " " << obj->sMailId << " ";
+	}
+
+	Vector3 *vertices = new Vector3[bufferSize];
+	Vector3 *normals = new Vector3[bufferSize];
+
+	int j = 0;
+
+	for (size_t i = 0; i < leaf->mObjects.size(); ++ i)
+	{
+		TriangleIntersectable *obj = static_cast<TriangleIntersectable *>(leaf->mObjects[i]);
+
+		// check if already rendered
+		if (obj->Mailed())
+			continue;
+
+		obj->Mail();
+
+		Triangle3 tri = obj->GetItem();
+
+		vertices[j * 3 + 0] = tri.mVertices[0];
+		vertices[j * 3 + 1] = tri.mVertices[1];
+		vertices[j * 3 + 2] = tri.mVertices[2];
+
+		Vector3 n = tri.GetNormal();
+
+		normals[j * 3 + 0] = n;
+		normals[j * 3 + 1] = n;
+		normals[j * 3 + 2] = n;
+
+		++ j;
+	}
+
+	glVertexPointer(3, GL_FLOAT, 0, vertices);
+	glNormalPointer(GL_FLOAT, 0, normals);
+
+	glDrawArrays(GL_TRIANGLES, 0, bufferSize);
+
+	DEL_PTR(vertices);
+	DEL_PTR(normals);
+}
+
+#else
+
+void GlRenderer::RenderKdLeaf(KdLeaf *leaf)
+{
+	if (!leaf->mIndexBufferSize)
+		return;
+
+	size_t offset = mObjects.size() * 3;
+	char *arrayPtr = mUseVbos ? NULL : (char *)mData;
+	
+	glVertexPointer(3, GL_FLOAT, 0, (char *)arrayPtr);
+	glNormalPointer(GL_FLOAT, 0, (char *)arrayPtr + offset * sizeof(Vector3));
+	
+	glDrawElements(GL_TRIANGLES, leaf->mIndexBufferSize, GL_UNSIGNED_INT, mIndices + leaf->mIndexBufferStart);
+}
+
+#endif
+
+void GlRenderer::CreateVertexArrays()
+{
+	mData = new Vector3[mObjects.size() * 6];
+	mIndices = new unsigned int[mObjects.size() * 3];
+
+	size_t offset = mObjects.size() * 3;
+
+	for (size_t i = 0; i < mObjects.size(); ++ i)
+	{
+		TriangleIntersectable *obj = static_cast<TriangleIntersectable *>(mObjects[i]);
+
+		Triangle3 tri = obj->GetItem();
+		const Vector3 n = tri.GetNormal();
+
+		mData[i * 3 + 0] = tri.mVertices[0];
+		mData[i * 3 + 1] = tri.mVertices[1];
+		mData[i * 3 + 2] = tri.mVertices[2];
+
+		mData[offset + i * 3 + 0] = n;
+		mData[offset + i * 3 + 1] = n;
+		mData[offset + i * 3 + 2] = n;
+	}
+
+	if (mUseVbos)
+	{
+		EnableDrawArrays();
+
+		glGenBuffersARB(1, &mVboId);
+		glBindBufferARB(GL_ARRAY_BUFFER_ARB, mVboId);
+
+		glVertexPointer(3, GL_FLOAT, 0, (char *)NULL);
+		glNormalPointer(GL_FLOAT, 0, (char *)NULL + offset * sizeof(Vector3));
+
+		glBufferDataARB(GL_ARRAY_BUFFER_ARB, mObjects.size() * 6 * sizeof(Vector3), mData, GL_STATIC_DRAW_ARB);
+		glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+
+		DisableDrawArrays();
+
+		delete [] mData;
+	}
+
+	cout << "\n******** created vertex buffer objects **********" << endl;	
+}
+
+
+void GlRenderer::DeleteVbos()
+{
+	glDeleteBuffersARB(1, &mVboId);
+
+/*
+	KdLeafContainer leaves;
+	mKdTree->CollectLeaves(leaves);
+
+	KdLeafContainer::const_iterator kit, kit_end = leaves.end();
+
+	for (kit = leaves.begin(); kit != kit_end; ++ kit)
+	{
+		KdLeaf *leaf = *kit;
+
+		if (leaf->mVboId == -1)
+		{
+			// delete old vbo
+			glDeleteBuffersARB(1, &leaf->mVboId);
+			leaf->mVboId = -1;
+		}
+	}
+*/
+}
+
+
+
+}
