Index: trunk/VUT/OcclusionCullingSceneManager/src/OgreOcclusionCullingSceneManager.cpp
===================================================================
--- trunk/VUT/OcclusionCullingSceneManager/src/OgreOcclusionCullingSceneManager.cpp	(revision 21)
+++ trunk/VUT/OcclusionCullingSceneManager/src/OgreOcclusionCullingSceneManager.cpp	(revision 22)
@@ -13,33 +13,39 @@
 	OcclusionCullingSceneManager::OcclusionCullingSceneManager(): 
 	mFrameID(1), mDistanceQueue(NULL), mVisibilityThreshold(0), mCurrentTestIdx(0),
-	mIsQueryMode(false)
+	mQueryMode(MODE_RENDER), mNumSceneNodes(0)
 	{		
 	}
-
+	//-----------------------------------------------------------------------
 	void OcclusionCullingSceneManager::_findVisibleObjects(Camera* cam, bool onlyShadowCasters)
 	{
 		// empty because we have to find in _renderVisibleObjects
 	}
-
+	//-----------------------------------------------------------------------
+	OcclusionCullingSceneManager::~OcclusionCullingSceneManager()
+	{		
+		deleteQueries();
+		SceneManager::~SceneManager();
+	}
 	//-----------------------------------------------------------------------
 	void OcclusionCullingSceneManager::_renderVisibleObjects(void)
 	{
 		mDistanceQueue = new PriorityQueue(myless<SceneNode *>(mCameraInProgress));
+		
 		mDistanceQueue->push(mSceneRoot);
 		//renderZPass();
-		renderCullFrustum();
+		//renderCullFrustum();
+		renderCoherentWithQueue();
 		delete mDistanceQueue;
-		//mDestRenderSystem->_setDepthBufferParams(true, false, CMPF_LESS);
-		//SceneManager::_renderVisibleObjects();
-		//mDestRenderSystem->_setDepthBufferParams();
-        //mDistanceQueue.push(mSceneRoot);
-		//Preprocess();
-		
-		//renderCullFrustum();
-
-		//mFrameID ++;
-		//ResetQueries();
-	}
-
+
+		/*mDestRenderSystem->_setDepthBufferParams(true, false, CMPF_LESS);
+		  SceneManager::_renderVisibleObjects();
+		  mDestRenderSystem->_setDepthBufferParams();
+          mDistanceQueue.push(mSceneRoot);
+		  Preprocess();
+		  //ResetQueries();
+		*/
+		
+		mFrameID ++;
+	}
 	//-----------------------------------------------------------------------
 	void OcclusionCullingSceneManager::renderZPass()
@@ -47,5 +53,64 @@
 		traverseNode(mSceneRoot);
 	}
-
+	//-----------------------------------------------------------------------
+	void OcclusionCullingSceneManager::renderCoherentWithQueue()
+	{
+		QueryQueue queryQueue;
+
+		//-- PART 1: process finished occlusion queries
+		while(!mDistanceQueue->empty() || !queryQueue.empty())
+		{
+			while(!queryQueue.empty() && 
+				  (queryQueue.front()->getOcclusionQuery()->resultAvailable() || mDistanceQueue->empty()))
+			{
+				SceneNode *node = queryQueue.front();
+				queryQueue.pop();
+			
+				// wait until result available
+				unsigned int visiblePixels;
+				node->getOcclusionQuery()->pullOcclusionQuery(&visiblePixels);
+
+				if(visiblePixels > mVisibilityThreshold)
+				{
+					pullUpVisibility(node);
+					traverseNode(node);
+				}
+			}	
+
+			//-- PART 2: hierarchical traversal
+			if(!mDistanceQueue->empty())
+			{
+				SceneNode *node = mDistanceQueue->top();
+
+				mDistanceQueue->pop();
+	
+				if(mCameraInProgress->isVisible(node->_getWorldAABB()))
+				{
+					// identify previously visible nodes
+					bool wasVisible = node->isNodeVisible() && (node->lastVisited() == mFrameID - 1);
+					
+					// identify nodes that we cannot skip queries for
+					bool leafOrWasInvisible = !wasVisible || isLeaf(node);
+
+					// reset node's visibility classification 
+					node->setVisible(false);
+
+					// update node's visited flag
+					node->setLastVisited(mFrameID);
+				
+					// skip testing previously visible interior nodes
+					if(leafOrWasInvisible)
+					{
+						issueOcclusionQuery(node, wasVisible);
+						queryQueue.push(node);
+					}
+					
+					// always traverse a node if it was visible
+					if(wasVisible)
+						traverseNode(node);
+				}
+			}
+		}
+	}
 	//-----------------------------------------------------------------------
 	void OcclusionCullingSceneManager::renderCullFrustum()
@@ -67,10 +132,6 @@
 				traverseNode(node);
 			}
-			//else
-			//MessageBox( NULL, "myplugin registered", "this is my plugin", MB_OK | MB_ICONERROR | MB_TASKMODAL);
-		}
-	}
-	
-	
+		}
+	}	
 	//-----------------------------------------------------------------------
 	void OcclusionCullingSceneManager::renderStopAndWait()
@@ -81,6 +142,7 @@
 			mDistanceQueue->pop();
 		
-			// interesting for the visualization, so rest and set
+			// interesting for the visualization
 			//node->SetVisible(false);
+			node->setLastVisited(15);
 
 			if(mCameraInProgress->isVisible(node->_getWorldAABB()))
@@ -100,5 +162,5 @@
 		}
 	}
-
+	//-----------------------------------------------------------------------
 	void OcclusionCullingSceneManager::issueOcclusionQuery(SceneNode *node, bool wasVisible)
 	{
@@ -107,41 +169,43 @@
 	
 		// change state so the bounding box gets not actually rendered on the screen
-		switchMode(false);
-		node->_addBoundingBoxToQueue(getRenderQueue());
+		setRenderingMode(MODE_QUERY);
+		//HACK: too slow
+        node->_addBoundingBoxToQueue(getRenderQueue());
 		SceneManager::_renderVisibleObjects();
 		getRenderQueue()->clear();
-		switchMode(true);
-
+		/* static RenderOperation ro;
+		   node->getRenderOperation(ro);
+		   ro.srcRenderable = node; 
+		   mDestRenderSystem->_render(ro); */
+		
 		mOcclusionQueries[mCurrentTestIdx++]->endOcclusionQuery();
 	}
 
-
-	//-----------------------------------------------------------------------
-	void OcclusionCullingSceneManager::switchMode(bool switch2QueryMode)
+	//-----------------------------------------------------------------------
+	void OcclusionCullingSceneManager::setRenderingMode(int mode)
 	{	
-		// boolean used to avoid unnecessary state changes
-		if(switch2QueryMode != mIsQueryMode)
-		{
-			mDestRenderSystem->_setColourBufferWriteEnabled(switch2QueryMode, 
-				switch2QueryMode, switch2QueryMode, switch2QueryMode);
-			mDestRenderSystem->_setDepthBufferWriteEnabled(switch2QueryMode);
-			mDestRenderSystem->setLightingEnabled(switch2QueryMode);
-			mIsQueryMode = switch2QueryMode;
-		}
-	}
-	
-
+		// avoid unnecessary state changes
+		if(mode != mQueryMode)
+		{
+			bool enabled = (mode == MODE_RENDER);
+
+			mDestRenderSystem->_setColourBufferWriteEnabled(enabled, 
+				enabled, enabled, enabled);
+			mDestRenderSystem->_setDepthBufferWriteEnabled(enabled);
+			mDestRenderSystem->setLightingEnabled(enabled);
+			mQueryMode = mode;
+		}
+	}
 	//-----------------------------------------------------------------------
 	void OcclusionCullingSceneManager::traverseNode(SceneNode *node)
 	{
-		if(node->numChildren() == 0) // reached leaf
-		{
-			renderSceneNode(node);
+		if(isLeaf(node)) // reached leaf
+		{
+			render(node);
 		}
 		else // internal node: add children to priority queue for further processing
 		{
 			Node::ChildNodeIterator it = node->getChildIterator();
-			char str[100]; sprintf(str, "number of children: %d", node->numChildren());
-		
+					
 			while (it.hasMoreElements())
 			{ 
@@ -151,17 +215,11 @@
 			}
 		 }
-
-		 /*
-		 static RenderOperation ro;
-		 node->getRenderOperation(ro);
-		 ro.srcRenderable = node; 
-		 mDestRenderSystem->_render(ro);
-		 Pass pass();
-		 renderSingleObject(node, &pass, true);
-		 */
-	}
-
-	void OcclusionCullingSceneManager::renderSceneNode(SceneNode *node)
-	{
+	}
+	//-----------------------------------------------------------------------
+	void OcclusionCullingSceneManager::render(SceneNode *node)
+	{
+		setRenderingMode(MODE_RENDER);
+
+		//HACK (too slow)
 		node->_findVisibleObjects(mCameraInProgress, getRenderQueue(), false, 
 								  mDisplayNodes, false);
@@ -169,3 +227,67 @@
 		getRenderQueue()->clear();
 	}
+	//-----------------------------------------------------------------------
+	void OcclusionCullingSceneManager::_updateSceneGraph(Camera* cam)
+	{
+		int numnodes = countSceneNodes(mSceneRoot);
+		//char str[100]; sprintf(str, "number: %d", mNumSceneNodes);
+		//MessageBox( NULL, str, "this is my plugin", MB_OK | MB_ICONERROR | MB_TASKMODAL);
+		
+		//-- initialise occlusion queries.
+		if(numnodes != mNumSceneNodes)
+		{
+			mNumSceneNodes = numnodes;
+
+			deleteQueries();
+
+			for(int i=0; i < mNumSceneNodes; i++)
+			{
+				HardwareOcclusionQuery *hw = mDestRenderSystem->createHardwareOcclusionQuery();
+				mOcclusionQueries.push_back(hw);
+			}
+		}
+
+		SceneManager::_updateSceneGraph(cam);
+	}
+	//-----------------------------------------------------------------------
+	int OcclusionCullingSceneManager::countSceneNodes(SceneNode *node)
+	{
+		int num = 1;
+		if(isLeaf(node))
+		{
+			return num;
+		}
+
+		Node::ChildNodeIterator it = node->getChildIterator();
+		
+		while (it.hasMoreElements())
+		{ 
+			SceneNode* sceneChild = static_cast<SceneNode*>(it.getNext());
+			num += countSceneNodes(sceneChild);
+        }
+
+		return num;
+	}
+	//-----------------------------------------------------------------------
+	int OcclusionCullingSceneManager::isLeaf(SceneNode *node)
+	{
+		return (node->numChildren() == 0);
+	}
+	//-----------------------------------------------------------------------
+	void OcclusionCullingSceneManager::pullUpVisibility(SceneNode *node)
+	{
+		while(node && !node->isNodeVisible())
+		{
+			node->setNodeVisible(true);
+			node = static_cast<SceneNode *>(node->getParent());
+		}
+	}
+	//-----------------------------------------------------------------------
+	void OcclusionCullingSceneManager::deleteQueries()
+	{
+		for(int i=0; i < mNumSceneNodes; i++)
+			delete mOcclusionQueries[i];
+
+		mOcclusionQueries.clear();
+	}
 }	
