Index: GTP/trunk/App/Demos/Vis/CHC_revisited/Geometry.h
===================================================================
--- GTP/trunk/App/Demos/Vis/CHC_revisited/Geometry.h	(revision 2756)
+++ GTP/trunk/App/Demos/Vis/CHC_revisited/Geometry.h	(revision 2773)
@@ -10,4 +10,6 @@
 {
 
+class RenderState;
+
 /** Represents drawable geometry consisting of triangles
 */
@@ -20,7 +22,7 @@
 	/** Render the geometry
 	*/
-	void Render();
+	void Render(RenderState *state);
 
-	int CountTriangles() const { return mNumVertices / 3; }
+	int GetNumTriangles() const { return mNumVertices / 3; }
 
 	inline bool HasTexture() const { return mTexCoords != NULL; }
Index: GTP/trunk/App/Demos/Vis/CHC_revisited/RenderTraverser.cpp
===================================================================
--- GTP/trunk/App/Demos/Vis/CHC_revisited/RenderTraverser.cpp	(revision 2772)
+++ GTP/trunk/App/Demos/Vis/CHC_revisited/RenderTraverser.cpp	(revision 2773)
@@ -5,4 +5,5 @@
 #include "SceneEntity.h"
 #include "RenderState.h"
+#include "Geometry.h"
 
 
@@ -16,14 +17,17 @@
 void TraversalStatistics::Reset()
 {
-	// reset statistics
 	mNumTraversedNodes = 0;
 	mNumQueryCulledNodes = 0;
 	mNumFrustumCulledNodes = 0;
+	
 	mNumRenderedGeometry = 0;
 	mNumRenderedTriangles = 0;
+	mNumRenderedNodes = 0;
+
 	mNumPreviouslyVisibleNodeQueries = 0;
 	mNumIssuedQueries = 0;
+	mNumStateChanges = 0;
+
 	mRenderTime = 0;
-	mNumStateChanges = 0;
 }
 
@@ -83,20 +87,24 @@
 	if (node->GetLastRenderedFrame() != mFrameId)
 	{
-		//cout << "big error!!" << endl;
+		if (mUseRenderQueue && mRenderState->SetState(RenderState::RENDER))
+			++ mStats.mNumStateChanges;
+
 		node->SetLastRenderedFrame(mFrameId);
 
-		if (mUseRenderQueue)
+		int geometrySize;
+		SceneEntity **entities = mBvh->GetGeometry(node, geometrySize);
+
+		mStats.mNumRenderedGeometry += geometrySize;
+		++ mStats.mNumRenderedNodes;
+		
+		for (int i = 0; i < geometrySize; ++ i)
 		{
-			int geometrySize;
-			SceneEntity **geom = mBvh->GetGeometry(node, geometrySize);
-			mRenderQueue.Enqueue(geom, geometrySize);
-			mStats.mNumRenderedGeometry += geometrySize;
-		}
-		else
-		{
-			if (mRenderState->SetState(RenderState::RENDER))
-				++ mStats.mNumStateChanges;
-
-			mStats.mNumRenderedGeometry += mBvh->Render(node, mRenderState);
+			SceneEntity *ent = entities[i];
+			mStats.mNumRenderedTriangles += ent->GetGeometry()->GetNumTriangles();
+
+			if (mUseRenderQueue)
+				mRenderQueue.Enqueue(ent);
+			else
+				ent->Render(mRenderState);
 		}		
 	}
@@ -114,44 +122,4 @@
 	mRenderState = state;
 	mRenderQueue.SetRenderState(state);
-}
-
-
-OcclusionQuery *RenderTraverser::IssueOcclusionQuery(BvhNode *node, bool wasVisible)
-{
-	++ mStats.mNumIssuedQueries;
-
-	if (mUseRenderQueue && (mRenderState->GetMode() == RenderState::RENDER))
-	{
-		mRenderQueue.Render();
-		mRenderQueue.Clear();
-	}
-
-	OcclusionQuery *query = mQueryHandler.RequestQuery();
-
-	query->SetNode(node);
-
-	query->BeginQuery();
-
-	if (wasVisible)
-		++ mStats.mNumPreviouslyVisibleNodeQueries;
-
-	// if this node is a previous visible leaf:
-	// leaves will be rendered anyway => we can also test with the real geometry 
-	if (wasVisible && mUseOptimization)
-	{
-		RenderNode(node);
-	}
-	else
-	{
-		// change to query mode and render box
-		if (mRenderState->SetState(RenderState::QUERY))
-			++ mStats.mNumStateChanges;
-
-		mBvh->RenderBoundingBox(node);
-	}
-
-	query->EndQuery();
-
-	return query;
 }
 
@@ -213,3 +181,51 @@
 
 
-}
+
+
+OcclusionQuery *RenderTraverser::IssueOcclusionQuery(BvhNode *node, bool wasVisible)
+{
+	OcclusionQuery *query = mQueryHandler.RequestQuery();
+	query->AddNode(node);
+
+	IssueOcclusionQuery(*query, wasVisible);
+
+	return query;
+}
+
+
+void RenderTraverser::IssueOcclusionQuery(const OcclusionQuery &query, bool wasVisible)
+{
+	++ mStats.mNumIssuedQueries;
+
+	if (mUseRenderQueue && (mRenderState->GetMode() == RenderState::RENDER))
+	{
+		mRenderQueue.Render();
+		mRenderQueue.Clear();
+	}
+
+	query.BeginQuery();
+
+	if (wasVisible)
+		++ mStats.mNumPreviouslyVisibleNodeQueries;
+
+	// if this node is a previous visible leaf:
+	// leaves will be rendered anyway => we can also test with the real geometry 
+	if (wasVisible && mUseOptimization)
+	{
+		for (size_t i = 0; i < query.GetNodes().size(); ++ i)
+			RenderNode(query.GetNodes()[i]);
+	}
+	else
+	{
+		// change to query mode and render box
+		if (mRenderState->SetState(RenderState::QUERY))
+			++ mStats.mNumStateChanges;
+
+		mBvh->RenderBoundingBoxes(query.GetNodes(), mRenderState);
+	}
+
+	query.EndQuery();
+}
+
+
+}
Index: GTP/trunk/App/Demos/Vis/CHC_revisited/OcclusionQuery.cpp
===================================================================
--- GTP/trunk/App/Demos/Vis/CHC_revisited/OcclusionQuery.cpp	(revision 2764)
+++ GTP/trunk/App/Demos/Vis/CHC_revisited/OcclusionQuery.cpp	(revision 2773)
@@ -18,12 +18,4 @@
 
 
-OcclusionQuery::OcclusionQuery(unsigned int idx):
-mQueryId(idx)
-{
-	// reverse for multiequeries with 32 nodes
-	mNodes.reserve(32);
-}
-
-
 OcclusionQuery::~OcclusionQuery()
 {
@@ -32,5 +24,5 @@
 
 
-void OcclusionQuery::BeginQuery()
+void OcclusionQuery::BeginQuery() const
 {
 	glBeginQueryARB(GL_SAMPLES_PASSED_ARB, mQueryId);
@@ -38,5 +30,5 @@
 
 
-void OcclusionQuery::EndQuery()
+void OcclusionQuery::EndQuery() const
 {
 	glEndQueryARB(GL_SAMPLES_PASSED_ARB);
@@ -87,4 +79,5 @@
 	{
 		query = mOcclusionQueries[mCurrentQueryIdx];
+		query->Reset();
 	}
 
Index: GTP/trunk/App/Demos/Vis/CHC_revisited/Geometry.cpp
===================================================================
--- GTP/trunk/App/Demos/Vis/CHC_revisited/Geometry.cpp	(revision 2756)
+++ GTP/trunk/App/Demos/Vis/CHC_revisited/Geometry.cpp	(revision 2773)
@@ -2,4 +2,5 @@
 #include "Triangle3.h"
 #include "glInterface.h"
+#include "RenderState.h"
 
 
@@ -67,13 +68,17 @@
 
 
-void Geometry::Render()
+void Geometry::Render(RenderState *state)
 {
-	glBindBufferARB(GL_ARRAY_BUFFER_ARB, mVboId);
+	if (state->GetCurrentVboId() != mVboId)
+	{
+		glBindBufferARB(GL_ARRAY_BUFFER_ARB, mVboId);
+		glVertexPointer(3, GL_FLOAT, 0, (char *)NULL);	
+		glNormalPointer(GL_FLOAT, 0, (char *)NULL + mNumVertices * sizeof(Vector3));
 
-	glVertexPointer(3, GL_FLOAT, 0, (char *)NULL);	
-	glNormalPointer(GL_FLOAT, 0, (char *)NULL + mNumVertices * sizeof(Vector3));
+		if (mTexCoords)
+			glTexCoordPointer(2, GL_FLOAT, 0, (char *)NULL + 2 * mNumVertices * sizeof(Vector3));
 
-	if (mTexCoords)
-		glTexCoordPointer(2, GL_FLOAT, 0, (char *)NULL + 2 * mNumVertices * sizeof(Vector3));
+		state->SetCurrentVboId(mVboId);
+	}
 
 	// don't render first degenerate index
Index: GTP/trunk/App/Demos/Vis/CHC_revisited/BvhLoader.cpp
===================================================================
--- GTP/trunk/App/Demos/Vis/CHC_revisited/BvhLoader.cpp	(revision 2763)
+++ GTP/trunk/App/Demos/Vis/CHC_revisited/BvhLoader.cpp	(revision 2773)
@@ -105,5 +105,5 @@
 	bvh->ComputeIds();
 	// specify bounds for occlusion tests
-	//bvh->RecomputeBounds();
+	bvh->RecomputeBounds();
 	// compute and print stats
 	bvh->ComputeBvhStats();
Index: GTP/trunk/App/Demos/Vis/CHC_revisited/RenderState.cpp
===================================================================
--- GTP/trunk/App/Demos/Vis/CHC_revisited/RenderState.cpp	(revision 2769)
+++ GTP/trunk/App/Demos/Vis/CHC_revisited/RenderState.cpp	(revision 2773)
@@ -12,5 +12,7 @@
 */
 RenderState::RenderState():
-mAlphaTestEnabled(false), mTexturesEnabled(false), mMode(RENDER) 
+mAlphaTestEnabled(false), 
+mTexturesEnabled(false), 
+mMode(RENDER) 
 {
 	Reset(); 
@@ -32,16 +34,4 @@
 		glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
 		glDepthMask(GL_FALSE);
-
-
-		/////////
-		//-- handle vbo
-
-		/*glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
-
-		if (Bvh::sCurrentVboId != -1)
-			glBindBufferARB(GL_ARRAY_BUFFER_ARB, Bvh::sCurrentVboId);
-		else
-			glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
-		*/
 
 		SetState(false, false);
@@ -92,4 +82,5 @@
 void RenderState::Reset()
 {
+	mCurrentVboId = -1;
 	SetState(false, false);
 	SetState(RENDER);
Index: GTP/trunk/App/Demos/Vis/CHC_revisited/RenderQueue.cpp
===================================================================
--- GTP/trunk/App/Demos/Vis/CHC_revisited/RenderQueue.cpp	(revision 2771)
+++ GTP/trunk/App/Demos/Vis/CHC_revisited/RenderQueue.cpp	(revision 2773)
@@ -39,8 +39,7 @@
 
 
-void RenderQueue::Enqueue(SceneEntity **entities, int size)
+void RenderQueue::Enqueue(SceneEntity *entity)
 {
-	for (int i = 0; i < size; ++ i)
-		mEntities.push_back(entities[i]);
+	mEntities.push_back(entity);
 }
 	
Index: GTP/trunk/App/Demos/Vis/CHC_revisited/Bvh.h
===================================================================
--- GTP/trunk/App/Demos/Vis/CHC_revisited/Bvh.h	(revision 2772)
+++ GTP/trunk/App/Demos/Vis/CHC_revisited/Bvh.h	(revision 2773)
@@ -105,8 +105,8 @@
 		successfully tested invisible.
 	*/
-	inline void IncTimesInvisible();
-	
-	inline int GetTimesInvisible() const;
-	inline void SetTimesInvisible(int t);
+	inline void IncTimesTestedInvisible();
+	
+	inline int GetTimesTestedInvisible() const;
+	inline void SetTimesTestedInvisible(int t);
 	
 	inline int GetTurnedVisibleFrame() const;
@@ -246,5 +246,5 @@
 
 
-void BvhNode::IncTimesInvisible() 
+void BvhNode::IncTimesTestedInvisible() 
 { 
 	++ mVisibility.mTimesInvisible; 
@@ -252,5 +252,5 @@
 
 
-int BvhNode::GetTimesInvisible() const 
+int BvhNode::GetTimesTestedInvisible() const 
 { 
 	return mVisibility.mTimesInvisible; 
@@ -258,5 +258,5 @@
 
 
-void BvhNode::SetTimesInvisible(const int t) 
+void BvhNode::SetTimesTestedInvisible(const int t) 
 { 
 	mVisibility.mTimesInvisible = t; 
@@ -465,9 +465,9 @@
 	/** Renders the bounding box of this node (Or the tigher bounding boxes of some subnodes).
 	*/
-	void RenderBoundingBox(BvhNode *node);
+	void RenderBoundingBox(BvhNode *node, RenderState *state);
 	/** Renders bounding boxes of the collection of nodes.
 		@returns #rendered boxes
 	*/
-	int RenderBoundingBoxes(const BvhNodeContainer &nodes);
+	int RenderBoundingBoxes(const BvhNodeContainer &nodes, RenderState *state);
 
 	/** Returns the bounding box of this bvh.
@@ -533,8 +533,5 @@
 	/** Returns stats.
 	*/
-	const BvhStats &GetBvhStats() const {return mBvhStats;}
-	/** Renders the geometry contained in this node.
-	*/
-	int Render(BvhNode *node, RenderState *state);
+	const BvhStats &GetBvhStats() const { return mBvhStats; }
 	/** Returns number of 'virtual' nodes in the hierarchy, i.e.
 		the number of nodes actually used for traversal.
@@ -550,9 +547,10 @@
 	*/
 	Bvh();
-
 	/** Protected constructor taking scene geometry into account
 	*/
 	const Bvh(const SceneEntityContainer &entities);
-	
+	/** Called by the constructor. Initializes important members.
+	*/
+	void Init();
 
 	/////////////
@@ -568,5 +566,5 @@
 
 	int PrepareBoundingBoxesWithDrawArrays(const BvhNodeContainer &nodes);
-	void RenderBoundingBoxesWithDrawArrays(int numNodes);
+	void RenderBoundingBoxesWithDrawArrays(int numNodes, RenderState *state);
 
 	/** Create the indices that each node needs to use vbo rendering.
@@ -644,5 +642,5 @@
 	//////////////
 
-	static unsigned int sCurrentVboId;
+	unsigned int mVboId;
 };
 
Index: GTP/trunk/App/Demos/Vis/CHC_revisited/OcclusionQuery.h
===================================================================
--- GTP/trunk/App/Demos/Vis/CHC_revisited/OcclusionQuery.h	(revision 2772)
+++ GTP/trunk/App/Demos/Vis/CHC_revisited/OcclusionQuery.h	(revision 2773)
@@ -17,5 +17,6 @@
 {
 public:
-	
+	/** constructor requesting an opengl occlusion query.
+	*/
 	OcclusionQuery();
 
@@ -26,7 +27,7 @@
 	unsigned int GetQueryResult() const;
 	
-	void BeginQuery();
+	void BeginQuery() const;
 	
-	void EndQuery();
+	void EndQuery() const;
 	
 	unsigned int GetQueryId() const;
@@ -34,5 +35,7 @@
 	*/
 	inline BvhNode *GetFrontNode() const { return mNodes[0]; }
-	/** Reset the contents of this query.
+	inline const BvhNodeContainer &GetNodes() const { return mNodes; }
+
+	/** Reset the list of nodes associated with this query.
 	*/
 	inline void Reset() { mNodes.clear(); }
@@ -40,18 +43,14 @@
 	*/
 	inline void AddNode(BvhNode *node) { mNodes.push_back(node); }
-	/** Convenience method that sets up a single node query.
+	/** Returns the size of the multiquery.
 	*/
-	inline void SetNode(BvhNode *node) { Reset(); AddNode(node); }
+	inline int GetSize() const { return (int)mNodes.size();}
 
-	
 protected:
 
-	OcclusionQuery(unsigned int id);
-	
 	
 	///////
 	//-- members
 
-	//float mPFail;
 	/// all nodes that are tested with the same query
 	BvhNodeContainer mNodes; 
Index: GTP/trunk/App/Demos/Vis/CHC_revisited/CHCPlusPlusTraverser.h
===================================================================
--- GTP/trunk/App/Demos/Vis/CHC_revisited/CHCPlusPlusTraverser.h	(revision 2772)
+++ GTP/trunk/App/Demos/Vis/CHC_revisited/CHCPlusPlusTraverser.h	(revision 2773)
@@ -7,4 +7,22 @@
 namespace CHCDemo
 {
+
+class OcclusionQuery;
+
+
+/** Class predicting the visiblity of nodes.
+*/
+class VisibilityPredictor
+{
+public:
+	/** Predicts the probability of a node to stay visible / invisible.
+	    The probability could be taken from a measured or analytic function.
+	*/
+	float GetProbability(BvhNode *node) const 
+	{ 
+		return 0.98f - 0.68f * exp(-(float)node->GetTimesTestedInvisible()); 
+	}
+};
+
 
 /** Class implementing traversal using the CHC++ algorithm.
@@ -22,7 +40,12 @@
 	*/
 	virtual void Traverse();
-
+	/** Queries nodes nodes tested invisible in previous frames.
+	*/
 	void QueryPreviouslyInvisibleNodes(BvhNode *node);
-
+	/** Computes the next multiquery.
+	*/
+	OcclusionQuery *GetNextMultiQuery(BvhNodeQueue &iqueue);
+	/** Issues batched multiqueries.
+	*/
 	void IssueMultiQueries();
 	/** Handles the result of an occlusion query.
@@ -38,4 +61,6 @@
 	BvhNodeQueue mIQueue;
 	BvhNodeQueue mVQueue;
+
+	VisibilityPredictor mVisibilityPredictor;
 };
 
Index: GTP/trunk/App/Demos/Vis/CHC_revisited/Bvh.cpp
===================================================================
--- GTP/trunk/App/Demos/Vis/CHC_revisited/Bvh.cpp	(revision 2771)
+++ GTP/trunk/App/Demos/Vis/CHC_revisited/Bvh.cpp	(revision 2773)
@@ -12,4 +12,6 @@
 #include "SceneEntity.h"
 #include "Geometry.h"
+#include "RenderState.h"
+
 
 namespace CHCDemo
@@ -17,7 +19,4 @@
 
 #define INVALID_TEST ((unsigned int)-1)
-
-const static bool useVbos = true;
-unsigned int Bvh::sCurrentVboId = -1;
 
 using namespace std;
@@ -122,28 +121,14 @@
 
 
-Bvh::Bvh():
-mCamera(NULL), 
-mRoot(NULL), 
-mVertices(NULL),
-mIndices(NULL),
-mTestIndices(NULL),
-mCurrentIndicesPtr(0),
-mNumNodes(0),
-mMaxDepthForTestingChildren(4),
-mAreaRatioThreshold(1.4f)
-{}
-
-
-Bvh::Bvh(const SceneEntityContainer &entities):
-mCamera(NULL), 
-mRoot(NULL), 
-mVertices(NULL),
-mIndices(NULL),
-mTestIndices(NULL),
-mCurrentIndicesPtr(0),
-mNumNodes(0),
-mMaxDepthForTestingChildren(4),
-mAreaRatioThreshold(1.4f)
-{
+Bvh::Bvh()
+{
+	Init();
+}
+
+
+Bvh::Bvh(const SceneEntityContainer &entities)
+{
+	Init();
+
 	mGeometrySize = entities.size();
 	mGeometry = new SceneEntity*[mGeometrySize];
@@ -172,4 +157,19 @@
 
 	if (mRoot) delete mRoot;
+}
+
+
+void Bvh::Init()
+{
+	mCamera = NULL;
+	mRoot = NULL;
+	mVertices = NULL;
+	mIndices = NULL;
+	mTestIndices = NULL;
+	mCurrentIndicesPtr = 0;
+	mNumNodes = 0;
+	mMaxDepthForTestingChildren = 4;
+	mAreaRatioThreshold = 1.4f;
+	mVboId = -1;
 }
 
@@ -366,18 +366,18 @@
 
 
-void Bvh::RenderBoundingBox(BvhNode *node)
-{
-	RenderBoundingBoxImmediate(node->GetBox());
-	/**static BvhNodeContainer dummy(1);
+void Bvh::RenderBoundingBox(BvhNode *node, RenderState *state)
+{
+	//RenderBoundingBoxImmediate(node->GetBox());
+	static BvhNodeContainer dummy(1);
 	dummy[0] = node;
-	RenderBoundingBoxes(dummy);*/
-}
-
-
-
-int Bvh::RenderBoundingBoxes(const BvhNodeContainer &nodes)
+	RenderBoundingBoxes(dummy, state);
+}
+
+
+
+int Bvh::RenderBoundingBoxes(const BvhNodeContainer &nodes, RenderState *state)
 {
 	int renderedBoxes = PrepareBoundingBoxesWithDrawArrays(nodes);
-	RenderBoundingBoxesWithDrawArrays(renderedBoxes);
+	RenderBoundingBoxesWithDrawArrays(renderedBoxes, state);
 
 	return renderedBoxes;
@@ -395,5 +395,5 @@
 	}
 
-	if (sCurrentVboId == -1)
+	if (mVboId == -1)
 	{	
 		// prepare the vbo 
@@ -428,17 +428,20 @@
 
 
-void Bvh::RenderBoundingBoxesWithDrawArrays(int numNodes)
+void Bvh::RenderBoundingBoxesWithDrawArrays(int numNodes, RenderState *state)
 {
 	//////
 	//-- Rendering the vbo
-	if (useVbos)
+
+	if (state->GetCurrentVboId() != mVboId)
+	{
+		glBindBufferARB(GL_ARRAY_BUFFER_ARB, mVboId);
 		// set the vertex pointer to the vertex buffer
-		glVertexPointer(3, GL_FLOAT, 0, (char *)NULL);		
-	else
-		glVertexPointer(3, GL_FLOAT, 0, mVertices);
+		glVertexPointer(3, GL_FLOAT, 0, (char *)NULL);	
+
+		state->SetCurrentVboId(mVboId);
+	}
 
 	// we do use the last or the first index (they are generate and only used to connect strips)
-	const int numElements = numNodes * sNumIndicesPerBox - 1;
-
+	int numElements = numNodes * sNumIndicesPerBox - 1;
 	// don't render first degenerate index
 	glDrawElements(GL_TRIANGLE_STRIP, numElements, GL_UNSIGNED_INT, mIndices + 1); 
@@ -559,29 +562,19 @@
 	}
 
-	if (useVbos)
-	{
-		glGenBuffersARB(1, &sCurrentVboId);
-		glBindBufferARB(GL_ARRAY_BUFFER_ARB, sCurrentVboId);
-		glVertexPointer(3, GL_FLOAT, 0, (char *)NULL);
-	
-		glBufferDataARB(GL_ARRAY_BUFFER_ARB, 
-			            bufferSize * sizeof(Vector3), 
-			            mVertices, 
-						GL_STATIC_DRAW_ARB);
-
-		//glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
-
-		// data handled by graphics driver from now on
-		DEL_PTR(mVertices);
-
-		cout << "***** created vbos *********" << endl;
-	}
-	else
-	{
-		sCurrentVboId = 0;
-        glVertexPointer(3, GL_FLOAT, 0, mVertices);
-
-		cout << "******* created vertex arrays ********" << endl;
-	}
+	glGenBuffersARB(1, &mVboId);
+	glBindBufferARB(GL_ARRAY_BUFFER_ARB, mVboId);
+	glVertexPointer(3, GL_FLOAT, 0, (char *)NULL);
+	
+	glBufferDataARB(GL_ARRAY_BUFFER_ARB, 
+		            bufferSize * sizeof(Vector3), 
+		            mVertices, 
+					GL_STATIC_DRAW_ARB);
+
+	//glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+
+	// data handled by graphics driver from now on
+	DEL_PTR(mVertices);
+
+	cout << "***** created vbos for tighter bounds *********" << endl;
 }
 
@@ -713,5 +706,5 @@
 	
 	for (int i = leaf->mFirst; i <= leaf->mLast; ++ i)
-		triangleCount += mGeometry[i]->GetGeometry()->CountTriangles();
+		triangleCount += mGeometry[i]->GetGeometry()->GetNumTriangles();
 	
 	return triangleCount;
@@ -729,8 +722,9 @@
 		nodeStack.pop();
 
-		if (node->IsLeaf()) 
+		if (node->IsVirtualLeaf()) 
 		{
 			BvhLeaf *leaf = static_cast<BvhLeaf *>(node);
 
+			mBvhStats.mTriangles += CountTriangles(leaf);
 			mBvhStats.mLeafSA += leaf->mBox.SurfaceArea();
 			mBvhStats.mLeafVol += leaf->mBox.GetVolume();
@@ -771,5 +765,5 @@
 
 	for (int i = node->mFirst; i <= node->mLast; ++ i)
-		numTriangles += mGeometry[i]->GetGeometry()->CountTriangles();
+		numTriangles += mGeometry[i]->GetGeometry()->GetNumTriangles();
 	
 	return numTriangles;
@@ -799,18 +793,4 @@
 		node->mNumLeaves = f->mNumLeaves + b->mNumLeaves;
 	}
-}
-
-
-int Bvh::Render(BvhNode *node, RenderState *state)
-{
-	int renderedTriangles = 0;
-
-	for (int i = node->mFirst; i <= node->mLast; ++ i)
-	{
-		renderedTriangles += mGeometry[i]->GetGeometry()->CountTriangles();
-		mGeometry[i]->Render(state);
-	}
-
-	return renderedTriangles;
 }
 
Index: GTP/trunk/App/Demos/Vis/CHC_revisited/RenderState.h
===================================================================
--- GTP/trunk/App/Demos/Vis/CHC_revisited/RenderState.h	(revision 2769)
+++ GTP/trunk/App/Demos/Vis/CHC_revisited/RenderState.h	(revision 2773)
@@ -41,4 +41,10 @@
 	*/
 	void Reset();
+	/** Stores the current vbo id.
+	*/
+	inline void SetCurrentVboId(int id) { mCurrentVboId = id; }
+	/** Returns the current vbo id.
+	*/
+	inline int GetCurrentVboId() { return mCurrentVboId; }
 
 protected:
@@ -48,4 +54,6 @@
 
 	Mode mMode;
+
+	int mCurrentVboId;
 };
 
Index: GTP/trunk/App/Demos/Vis/CHC_revisited/RenderQueue.h
===================================================================
--- GTP/trunk/App/Demos/Vis/CHC_revisited/RenderQueue.h	(revision 2771)
+++ GTP/trunk/App/Demos/Vis/CHC_revisited/RenderQueue.h	(revision 2773)
@@ -23,7 +23,7 @@
 	*/
 	RenderQueue(RenderState *state);
-	/** Enqueues a number of entities
+	/** Enqueues an entity
 	*/
-	void Enqueue(SceneEntity **entities, int size);
+	void Enqueue(SceneEntity *entity);
 	/** Renders the contents of the render queue.
 	*/
Index: GTP/trunk/App/Demos/Vis/CHC_revisited/SceneEntity.cpp
===================================================================
--- GTP/trunk/App/Demos/Vis/CHC_revisited/SceneEntity.cpp	(revision 2769)
+++ GTP/trunk/App/Demos/Vis/CHC_revisited/SceneEntity.cpp	(revision 2773)
@@ -26,5 +26,5 @@
 		glPushMatrix();
 		glMultMatrixf((float *)mTransform->x);
-		mGeometry->Render();
+		mGeometry->Render(state);
 
 		glPopMatrix();
@@ -32,5 +32,5 @@
 	else
 	{
-		mGeometry->Render();
+		mGeometry->Render(state);
 	}
 }
Index: GTP/trunk/App/Demos/Vis/CHC_revisited/chcdemo.cpp
===================================================================
--- GTP/trunk/App/Demos/Vis/CHC_revisited/chcdemo.cpp	(revision 2771)
+++ GTP/trunk/App/Demos/Vis/CHC_revisited/chcdemo.cpp	(revision 2773)
@@ -62,4 +62,7 @@
 
 int renderedObjects = 0;
+int renderedNodes = 0;
+int renderedTriangles = 0;
+
 int issuedQueries = 0;
 int traversedNodes = 0;
@@ -869,4 +872,7 @@
 
 		renderedObjects = traverser->GetStats().mNumRenderedGeometry;
+		renderedNodes = traverser->GetStats().mNumRenderedNodes;
+		renderedTriangles = traverser->GetStats().mNumRenderedTriangles;
+
 		traversedNodes = traverser->GetStats().mNumTraversedNodes;
 		frustumCulledNodes = traverser->GetStats().mNumFrustumCulledNodes;
@@ -881,18 +887,16 @@
 	string str2;
 
-	int dummy = 0;
-	CalcDecimalPoint(str, dummy);
-	CalcDecimalPoint(str2, traverser->GetStats().mNumRenderedTriangles);
-
-	sprintf_s(msg3, "rendered objects: %6d (of %6d), rendered triangles: %s (of %s)", 
-			  renderedObjects, sceneEntities.size(), str.c_str(), str2.c_str()); 
-
-	sprintf_s(msg4, "nodes: %5d, traversed: %5d, frustum culled: %5d, query culled: %5d, issued queries: %5d, state changes: %5d",
-			  bvh->GetNumVirtualNodes(), traversedNodes, frustumCulledNodes,
-			  queryCulledNodes, issuedQueries, stateChanges);
+	CalcDecimalPoint(str, renderedTriangles);
+	CalcDecimalPoint(str2, bvh->GetBvhStats().mTriangles);
+
+	sprintf_s(msg3, "rendered nodes: %6d (of %6d), rendered triangles: %s (of %s)", 
+			  renderedNodes, bvh->GetNumVirtualNodes(), str.c_str(), str2.c_str()); 
+
+	sprintf_s(msg4, "traversed: %5d, frustum culled: %5d, query culled: %5d, issued queries: %5d, state changes: %5d",
+			  traversedNodes, frustumCulledNodes, queryCulledNodes, issuedQueries, stateChanges);
 
 	sprintf_s(msg5, "fps: %6.1f", fps);
 
-	cout << "previously visible node queries: " << traverser->GetStats().mNumPreviouslyVisibleNodeQueries << endl;
+	//cout << "previously visible node queries: " << traverser->GetStats().mNumPreviouslyVisibleNodeQueries << endl;
 
 	begin2D();
@@ -906,5 +910,5 @@
 		glColor3f(1.0f, 1.0f, 1.0f);
 		
-		Output(800, 30, msg[renderMode]);
+		Output(850, 30, msg[renderMode]);
 
 		if(showStatistics)
Index: GTP/trunk/App/Demos/Vis/CHC_revisited/CHCPlusPlusTraverser.cpp
===================================================================
--- GTP/trunk/App/Demos/Vis/CHC_revisited/CHCPlusPlusTraverser.cpp	(revision 2772)
+++ GTP/trunk/App/Demos/Vis/CHC_revisited/CHCPlusPlusTraverser.cpp	(revision 2773)
@@ -16,7 +16,5 @@
 {
 	// wait until result available
-	int visiblePixels = query->GetQueryResult();
-
-	int visible = visiblePixels > mVisibilityThreshold;
+	const int visible = query->GetQueryResult() > mVisibilityThreshold;
 
 	BvhNode *node = query->GetFrontNode();
@@ -26,5 +24,9 @@
 		// node was previously invisible
 		if (!node->IsVisible())
+		{
+			// reset flag
+			node->SetTimesTestedInvisible(0);
 			node->SetAssumedVisibleFrameId(mFrameId + mAssumedVisibleFrames);
+		}
 		else
 			// randomize first invokation
@@ -36,4 +38,5 @@
 	else
 	{
+		node->IncTimesTestedInvisible();
 		++ mStats.mNumQueryCulledNodes;
 	}
@@ -58,4 +61,5 @@
 				
 				OcclusionQuery *query = IssueOcclusionQuery(node, true);
+
 				mQueryQueue.push(query);
 				resultAvailable = mQueryQueue.front()->ResultAvailable();
@@ -94,4 +98,8 @@
 					// identify nodes that we cannot skip queries for
 					const bool testFeasible = (!wasVisible || (node->IsVirtualLeaf() && (node->GetAssumedVisibleFrameId() <= mFrameId)));
+
+					// node was not recently tested => reset flag 
+					if (node->GetLastVisitedFrame() != mFrameId - 1)
+						node->SetTimesTestedInvisible(0);
 
 					// update node's visited flag
@@ -176,4 +184,42 @@
 
 
+OcclusionQuery * CHCPlusPlusTraverser::GetNextMultiQuery(BvhNodeQueue &iqueue)
+{
+	OcclusionQuery *query = mQueryHandler.RequestQuery();
+
+	float pFail = 1.0f; 
+	float maxBatchVal = 0.0f;
+	float newPBatch = 1.0f;
+	float newBatchVal;
+
+	// issue next query
+	while (!iqueue.empty())
+	{
+		BvhNode *node = iqueue.front();
+		newPBatch *= mVisibilityPredictor.GetProbability(node);
+
+		if (query->GetNodes().empty())
+			newBatchVal = 1.0f;
+		else
+		{
+			int newSize = query->GetSize() + 1;
+			newBatchVal = newSize / (1.0f + (1.0f - newPBatch) * newSize);
+		}
+
+		if (newBatchVal <= maxBatchVal)
+			break;
+
+		iqueue.pop();
+		query->AddNode(node);
+
+		maxBatchVal = newBatchVal;
+	}
+
+	IssueOcclusionQuery(*query, false);
+
+	return query;
+}
+
+
 void CHCPlusPlusTraverser::IssueMultiQueries()
 {
@@ -191,6 +237,7 @@
 		BvhNode *node = mIQueue.front();
 		mIQueue.pop();
-
-		OcclusionQuery *query = IssueOcclusionQuery(node, false);
+		OcclusionQuery *query = GetNextMultiQuery(mIQueue);
+		//OcclusionQuery *query = IssueOcclusionQuery(node);
+
 		mQueryQueue.push(query);
 	}
Index: GTP/trunk/App/Demos/Vis/CHC_revisited/RenderTraverser.h
===================================================================
--- GTP/trunk/App/Demos/Vis/CHC_revisited/RenderTraverser.h	(revision 2771)
+++ GTP/trunk/App/Demos/Vis/CHC_revisited/RenderTraverser.h	(revision 2773)
@@ -30,10 +30,13 @@
 	int mNumQueryCulledNodes;
 	int mNumFrustumCulledNodes;
+	
 	int mNumRenderedGeometry;
 	int mNumRenderedTriangles;
+	int mNumRenderedNodes;
+
 	int mNumIssuedQueries;
 	int mNumStateChanges;
 	int mNumPreviouslyVisibleNodeQueries;
-
+	
 	long mRenderTime;
 };
@@ -114,7 +117,10 @@
 	*/
 	void TraverseNode(BvhNode *node);
-	/** Issues occlusion query for specified node
+	/** Issues occlusion query for a single node
 	*/
 	OcclusionQuery *IssueOcclusionQuery(BvhNode *node, bool wasVisible);
+	/** Issue multiquery.
+	*/
+	void IssueOcclusionQuery(const OcclusionQuery &query, bool wasVisible);
 	/** Retunrs true if the current bvh node intersects the near plane.
 	*/
