Index: trunk/VUT/OcclusionCullingSceneManager/src/OgreOcclusionCullingTerrainSceneTraverser.cpp
===================================================================
--- trunk/VUT/OcclusionCullingSceneManager/src/OgreOcclusionCullingTerrainSceneTraverser.cpp	(revision 35)
+++ trunk/VUT/OcclusionCullingSceneManager/src/OgreOcclusionCullingTerrainSceneTraverser.cpp	(revision 35)
@@ -0,0 +1,416 @@
+#include "OgreOcclusionCullingSceneTraverser.h"
+#include "OgreMath.h"
+#include "OgreIteratorWrappers.h"
+#include "OgreCamera.h"
+#include "OgreHardwareOcclusionQuery.h"
+//#include "OgreWireBoundingBox.h"
+#include "OgreSolidHalfBoundingBox.h"
+
+
+#include <windows.h>
+
+namespace Ogre {
+	
+	//-----------------------------------------------------------------------
+	OcclusionCullingSceneTraverser::OcclusionCullingSceneTraverser(SceneManager *sm, RenderSystem *rsys): 
+	mFrameId(1), mDistanceQueue(NULL), mVisibilityThreshold(0), mCurrentTestIdx(0),
+	mQueryMode(MODE_RENDER), mNumSceneNodes(0), mCurrentAlgorithm(RENDER_COHERENT),
+	mNumTraversedNodes(0), mNumQueryCulledNodes(0), mNumFrustumCulledNodes(0), 
+	mNumRenderedGeometry(0), mSceneManager(sm), mRenderSystem(rsys)
+	{		
+		mHalfBoundingBox[0] = mHalfBoundingBox[1] = 0;
+	}
+	//-----------------------------------------------------------------------
+	OcclusionCullingSceneTraverser::~OcclusionCullingSceneTraverser()
+	{		
+		if(mHalfBoundingBox[0]) delete mHalfBoundingBox[0];
+		if(mHalfBoundingBox[1]) delete mHalfBoundingBox[1];
+
+		deleteQueries();
+		//SceneManager::~SceneManager();
+	}
+	//-----------------------------------------------------------------------
+	void OcclusionCullingSceneTraverser::renderScene( Camera *cam, SceneNode *root )
+	{
+		mNumTraversedNodes = 0;
+		mNumQueryCulledNodes = 0;
+		mNumFrustumCulledNodes = 0;
+		mNumRenderedGeometry = 0;
+		
+		mDistanceQueue = new PriorityQueue(myless<SceneNode *>(cam));
+		mDistanceQueue->push(root);
+		mCurrentTestIdx = 0;
+
+		mCurrentAlgorithm = RENDER_CULL_FRUSTUM;
+		switch(mCurrentAlgorithm)
+		{
+			case RENDER_CULL_FRUSTUM:
+				renderCullFrustum(cam);
+		        break;
+			case RENDER_STOP_AND_WAIT:
+				renderStopAndWait(cam);
+				break;
+			case RENDER_COHERENT:
+				renderCoherentWithQueue(cam);
+				break;
+			default:
+				renderCullFrustum(cam);
+				break;
+		}	
+		
+		delete mDistanceQueue;
+
+		mFrameId ++;
+	}
+	//-----------------------------------------------------------------------
+	void OcclusionCullingSceneTraverser::renderCoherentWithQueue(Camera *cam)
+	{
+		QueryQueue queryQueue;
+
+		//-- PART 1: process finished occlusion queries
+		while(!mDistanceQueue->empty() || !queryQueue.empty())
+		{
+			while(!queryQueue.empty() && 
+				  ((queryQueue.front().second)->resultAvailable() || mDistanceQueue->empty()))
+			{
+				SceneNode *node = queryQueue.front().first;
+				HardwareOcclusionQuery *query = queryQueue.front().second;
+
+				queryQueue.pop();
+			
+				// wait until result available
+				unsigned int visiblePixels;
+				query->pullOcclusionQuery(&visiblePixels);
+
+				if(visiblePixels > mVisibilityThreshold)
+				{
+					pullUpVisibility(node);
+					traverseNode(cam, node);
+				}
+				else
+				{
+					mNumQueryCulledNodes ++;
+				}
+			}	
+
+			//-- PART 2: hierarchical traversal
+			if(!mDistanceQueue->empty())
+			{
+				SceneNode *node = mDistanceQueue->top();
+				mDistanceQueue->pop();
+	
+				if(cam->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->setNodeVisible(false);
+
+					// update node's visited flag
+					node->setLastVisited(mFrameId);
+				
+					// skip testing previously visible interior nodes
+					if(leafOrWasInvisible)
+					{
+						HardwareOcclusionQuery *query = issueOcclusionQuery(node, wasVisible);
+						queryQueue.push(query_pair(node, query));
+					}
+					
+					// always traverse a node if it was visible
+					if(wasVisible)
+					{
+						traverseNode(cam, node);
+					}
+				}
+				else
+				{
+					mNumFrustumCulledNodes ++;
+				}
+			}
+		}
+	}
+	//-----------------------------------------------------------------------
+	void OcclusionCullingSceneTraverser::renderCullFrustum(Camera *cam)
+	{
+		while(!mDistanceQueue->empty())
+		{
+			SceneNode *node = mDistanceQueue->top();
+			mDistanceQueue->pop();
+	
+			// interesting for visualization purpose
+			node->setNodeVisible(false);
+				
+			if(!cam->isVisible(node->_getWorldAABB()))
+			{
+				// update node's visited flag 
+				node->setLastVisited(mFrameId);
+				node->setNodeVisible(true);
+				traverseNode(cam, node);
+			}
+			//else
+				if(cam->isVisible(node->_getWorldAABB()))
+				{
+					mNumQueryCulledNodes ++;
+				}else
+			{			
+				mNumFrustumCulledNodes ++;
+			}
+		}
+	}	
+	//-----------------------------------------------------------------------
+	void OcclusionCullingSceneTraverser::renderStopAndWait(Camera *cam)
+	{
+		while(!mDistanceQueue->empty())
+		{
+			SceneNode *node = mDistanceQueue->top();
+			mDistanceQueue->pop();
+		
+			// interesting for the visualization
+			node->setNodeVisible(false);
+			node->setLastVisited(mFrameId);
+
+			if(cam->isVisible(node->_getWorldAABB()))
+			{
+				HardwareOcclusionQuery *query = issueOcclusionQuery(node, false);
+				
+				unsigned int visiblePixels;
+				// wait if result not available
+				query->pullOcclusionQuery(&visiblePixels);
+				
+				// node visible
+				if(visiblePixels > mVisibilityThreshold)
+				{
+					traverseNode(cam, node);
+				}
+				else
+				{
+					mNumQueryCulledNodes ++;
+				}
+			}
+			else
+			{
+				mNumFrustumCulledNodes ++;
+			}
+		}
+	}
+	//-----------------------------------------------------------------------
+	HardwareOcclusionQuery *OcclusionCullingSceneTraverser::issueOcclusionQuery( SceneNode *node, bool wasVisible )
+	{
+		// change state so the bounding box gets not actually rendered on the screen
+		setRenderingMode(MODE_QUERY);
+
+		// get next available test id
+		HardwareOcclusionQuery *query = mOcclusionQueries[mCurrentTestIdx++];
+		
+		query->beginOcclusionQuery();
+				
+		renderBoundingBox(node);
+
+		query->endOcclusionQuery();
+
+		return query;
+	}
+	//-----------------------------------------------------------------------
+	void OcclusionCullingSceneTraverser::setRenderingMode( int mode )
+	{	
+		// avoid unnecessary state changes
+		if(mode != mQueryMode)
+		{
+			bool enabled = (mode == MODE_RENDER);
+			
+			mRenderSystem->_setColourBufferWriteEnabled(enabled, 
+				enabled, enabled, enabled);
+			mRenderSystem->_setDepthBufferWriteEnabled(enabled);
+			mRenderSystem->setLightingEnabled(enabled);
+
+			mQueryMode = mode;
+		}
+	}
+	//-----------------------------------------------------------------------
+	void OcclusionCullingSceneTraverser::traverseNode( Camera *cam, SceneNode *node )
+	{
+		mNumTraversedNodes ++;
+		
+		if(node->numAttachedObjects() > 0)
+		{
+			renderSceneNode(cam, node);
+		}
+
+		// internal node: add children to priority queue for further processing
+		Node::ChildNodeIterator it = node->getChildIterator();
+					
+		while (it.hasMoreElements())			
+		{ 
+			SceneNode* sceneChild = static_cast<SceneNode*>(it.getNext());
+			mDistanceQueue->push(sceneChild);
+		}
+	}
+	//-----------------------------------------------------------------------
+	void OcclusionCullingSceneTraverser::renderSceneNode( Camera *cam, SceneNode *node )
+	{
+		setRenderingMode(MODE_RENDER);
+		
+		//HACK (too slow)
+		mSceneManager->_renderSceneNode(cam, node);
+		//MessageBox( NULL, "myplugin registered", "this is my plugin", MB_OK | MB_ICONERROR | MB_TASKMODAL);
+	}
+	//-----------------------------------------------------------------------
+	void OcclusionCullingSceneTraverser::preprocess( void )
+	{
+		//-- initialise occlusion queries.
+		deleteQueries();
+		
+		for(unsigned int i=0; i < mNumSceneNodes; i++)
+		{
+			mOcclusionQueries.push_back(mRenderSystem->createHardwareOcclusionQuery());
+		}	
+	}
+	//-----------------------------------------------------------------------
+	void OcclusionCullingSceneTraverser::setSceneManager( SceneManager *sm )
+	{
+		mSceneManager = sm;
+	}
+	//-----------------------------------------------------------------------
+	void OcclusionCullingSceneTraverser::setRenderSystem( RenderSystem *rsys )
+	{
+		mRenderSystem = rsys;
+	}
+	//-----------------------------------------------------------------------
+	/*unsigned int OcclusionCullingSceneManager::countSceneNodes(SceneNode *node)
+	{
+		unsigned int result = 1;
+		
+		Node::ChildNodeIterator it = node->getChildIterator();
+		
+		while (it.hasMoreElements())
+		{ 
+			SceneNode* sceneChild = static_cast<SceneNode*>(it.getNext());
+			result += countSceneNodes(sceneChild);
+        }
+
+		return result;
+	}*/
+	//-----------------------------------------------------------------------
+	bool OcclusionCullingSceneTraverser::isLeaf( SceneNode *node )
+	{
+		return (node->numChildren() == 0);
+	}
+	//-----------------------------------------------------------------------
+	void OcclusionCullingSceneTraverser::pullUpVisibility( SceneNode *node )
+	{
+		while(node && !node->isNodeVisible())
+		{
+			node->setNodeVisible(true);
+			node = static_cast<SceneNode *>(node->getParent());
+		}
+	}
+	//-----------------------------------------------------------------------
+	void OcclusionCullingSceneTraverser::deleteQueries( void )
+	{
+		for(unsigned int i=0; i < mNumSceneNodes; i++)
+			delete mOcclusionQueries[i];
+
+		mOcclusionQueries.clear();
+	}
+	//-----------------------------------------------------------------------
+	void OcclusionCullingSceneTraverser::renderBoundingBox( SceneNode *node )
+	{
+		// Render two halfes of the bounding box (using triangle fans)
+		for(int half = 0; half < 2; half ++)
+		{
+			SolidHalfBoundingBox *box = getSolidHalfBoundingBox(half);
+			
+			box->setupBoundingBox(node->_getWorldAABB());
+
+			static RenderOperation ro;
+			mSceneManager->useRenderableViewProjMode(box);
+			box->getRenderOperation(ro);
+			ro.srcRenderable = box; 
+			mRenderSystem->_render(ro);
+
+			//mSceneManager->renderSingleObject(getSolidHalfBoundingBox(half), 
+			//	getSolidHalfBoundingBox(half)->getTechnique()->getPass(0), false);
+		}
+	}
+	//-----------------------------------------------------------------------
+	SolidHalfBoundingBox *OcclusionCullingSceneTraverser::getSolidHalfBoundingBox( int half )
+	{
+		if(!mHalfBoundingBox[half])
+			mHalfBoundingBox[half] = new SolidHalfBoundingBox(half == 1);
+
+		return mHalfBoundingBox[half];	
+	}
+	//-----------------------------------------------------------------------
+	bool OcclusionCullingSceneTraverser::setOption( const String & key, const void * val )
+	{
+		if ( key == "Algorithm" )
+		{
+			mCurrentAlgorithm = * static_cast < const int * > ( val );
+			return true;
+		}
+		if ( key == "Threshold" )
+		{
+			mVisibilityThreshold = * static_cast < const int * > ( val );
+			return true;
+		}
+
+		return false;
+	}
+	//-----------------------------------------------------------------------
+	bool OcclusionCullingSceneTraverser::getOption( const String & key, void *val )
+	{
+		if ( key == "Algorithm" )
+		{
+			* static_cast < int * > ( val ) = mCurrentAlgorithm;
+			return true;
+		}
+		if ( key == "Threshold" )
+		{
+			* static_cast < unsigned int * > ( val ) = mVisibilityThreshold;
+			return true;
+		}
+		if ( key == "NumSceneNodes" )
+		{
+			* static_cast < unsigned int * > ( val ) = mNumSceneNodes;
+			return true;
+		}
+		if ( key == "NumTraversedNodes" )
+		{
+			* static_cast < unsigned int * > ( val ) = mNumTraversedNodes;
+			return true;
+		}
+		if ( key == "NumQueryCulledNodes" )
+		{
+			* static_cast < unsigned int * > ( val ) = mNumQueryCulledNodes;
+			return true;
+		}
+		if ( key == "NumFrustumCulledNodes" )
+		{
+			* static_cast < unsigned int * > ( val ) = mNumFrustumCulledNodes;
+			return true;
+		}
+		return false;
+	}
+	//-----------------------------------------------------------------------
+	bool OcclusionCullingSceneTraverser::getOptionKeys( StringVector & refKeys )
+	{
+		refKeys.push_back( "Algorithm" );
+		refKeys.push_back( "Threshold" );
+		refKeys.push_back( "NumSceneNodes" );
+		refKeys.push_back( "NumTraversedNodes" );
+		refKeys.push_back( "NumQueryCulledNodes" );
+		refKeys.push_back( "NumFrustumCulledNodes" );
+		//refKeys.push_back( "mNumRenderedGeometry" );
+
+		return true;
+	}
+	//-----------------------------------------------------------------------
+	void OcclusionCullingSceneTraverser::setNumSceneNodes(int num)
+	{
+		mNumSceneNodes = num;
+	}
+}	
