Index: /GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TestCullingTerrainApplication.dsw
===================================================================
--- /GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TestCullingTerrainApplication.dsw	(revision 639)
+++ /GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TestCullingTerrainApplication.dsw	(revision 639)
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "Demo_TestCullingTerrain"=.\TestCullingTerrainApplication.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
Index: /GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TestCullingTerrain.vcproj
===================================================================
--- /GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TestCullingTerrain.vcproj	(revision 639)
+++ /GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TestCullingTerrain.vcproj	(revision 639)
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="7.10"
+	Name="TestCullingTerrain"
+	ProjectGUID="{248F19A6-2FE0-4F5D-8928-E0EA10609887}"
+	Keyword="Win32Proj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory=".\bin\$(ConfigurationName)"
+			IntermediateDirectory=".\obj\$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="2"
+			ReferencesPath="">
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="&quot;$(OGRE_PATH)\Dependencies\include&quot;;&quot;$(OGRE_PATH)\OgreMain\include&quot;;&quot;$(OGRE_PATH)\Samples\Common\include&quot;;&quot;$(OGRE_PATH)\Dependencies\include\CEGUI&quot;;&quot;$(OGRE_PATH)\PlugIns\OctreeSceneManager\include&quot;;&quot;$(OGRE_ADDONS_PATH)\dotsceneoctree\PlugIns\DotSceneManager\include&quot;;&quot;$(OGRE_PATH)\Samples\Common\CEGUIRenderer\include&quot;;..\..\GtpVisibility\include;..\..\Ogre\include;..\include"
+				PreprocessorDefinitions="_WINDOWS;_STLP_USE_DYNAMIC_LIB;OGRE_LIBRARY_IMPORTS;_DEBUG;WIN32;_STLP_DEBUG;PLUGIN_TERRAIN_IMPORTS;GTP_VISIBILITY_MODIFIED_OGRE"
+				MinimalRebuild="TRUE"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				RuntimeTypeInfo="TRUE"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="TRUE"
+				DebugInformationFormat="4"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="Plugin_OctreeSceneManager.lib Plugin_VisibilitySceneManager.lib OGREMain_d.LIB CEGUIBase_d.lib OgreGUIRenderer_d.lib Plugin_DotSceneManager.lib"
+				OutputFile="$(OGRE_PATH)/Samples/Common/bin/Debug/TestCullingTerrain.exe"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;$(OGRE_PATH)\Dependencies\Lib\$(ConfigurationName)&quot;;&quot;$(OGRE_PATH)\OgreMain\Lib\$(ConfigurationName)&quot;;&quot;$(OGRE_PATH)\PlugIns\OctreeSceneManager\bin\$(ConfigurationName)&quot;;&quot;$(OGRE_PATH)\Samples\Common\CEGUIRenderer\lib&quot;;&quot;..\..\Ogre\lib\$(ConfigurationName)&quot;"
+				GenerateDebugInformation="TRUE"
+				ProgramDatabaseFile="$(OutDir)/TestCullingTerrain.pdb"
+				SubSystem="2"
+				ImportLibrary=""
+				TargetMachine="1"/>
+			<Tool
+				Name="VCMIDLTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"/>
+			<Tool
+				Name="VCWebDeploymentTool"/>
+			<Tool
+				Name="VCManagedWrapperGeneratorTool"/>
+			<Tool
+				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory=".\bin\$(ConfigurationName)"
+			IntermediateDirectory=".\obj\$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;$(OGRE_PATH)\Dependencies\include&quot;;&quot;$(OGRE_PATH)\OgreMain\include&quot;;&quot;$(OGRE_PATH)\Samples\Common\include&quot;;&quot;$(OGRE_PATH)\Dependencies\include\CEGUI&quot;;&quot;$(OGRE_PATH)\PlugIns\OctreeSceneManager\include&quot;;&quot;$(OGRE_PATH)\Samples\Common\CEGUIRenderer\include&quot;;..\..\Ogre\include;..\..\GtpVisibility\include;..\include"
+				PreprocessorDefinitions="_WINDOWS;_STLP_USE_DYNAMIC_LIB;OGRE_LIBRARY_IMPORTS;_RELEASE;WIN32;_STLP_RELEASE;GTP_VISIBILITY_MODIFIED_OGRE"
+				RuntimeLibrary="2"
+				RuntimeTypeInfo="TRUE"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="TRUE"
+				DebugInformationFormat="3"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="OGREMain.LIB CEGUIBase.lib OgreGUIRenderer.lib Plugin_OctreeSceneManager.lib Plugin_VisibilitySceneManager.lib"
+				OutputFile="$(OGRE_PATH)/Samples/Common/bin/Release/TestCullingTerrain.exe"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;$(OGRE_PATH)\Dependencies\Lib\$(ConfigurationName)&quot;;&quot;$(OGRE_PATH)\OgreMain\Lib\$(ConfigurationName)&quot;;&quot;$(OGRE_PATH)\PlugIns\OctreeSceneManager\bin\$(ConfigurationName)&quot;;&quot;$(OGRE_PATH)\Samples\Common\CEGUIRenderer\lib&quot;;&quot;..\..\Ogre\lib\$(ConfigurationName)&quot;"
+				GenerateDebugInformation="TRUE"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"/>
+			<Tool
+				Name="VCMIDLTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"/>
+			<Tool
+				Name="VCWebDeploymentTool"/>
+			<Tool
+				Name="VCManagedWrapperGeneratorTool"/>
+			<Tool
+				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+			<File
+				RelativePath=".\TerrainFrameListener.cpp">
+			</File>
+			<File
+				RelativePath=".\TestCullingTerrainApplication.cpp">
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+			<File
+				RelativePath=".\TerrainFrameListener.h">
+			</File>
+			<File
+				RelativePath=".\TestCullingTerrainApplication.h">
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
Index: /GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TerrainFrameListener.cpp
===================================================================
--- /GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TerrainFrameListener.cpp	(revision 639)
+++ /GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TerrainFrameListener.cpp	(revision 639)
@@ -0,0 +1,1623 @@
+#include <OgreNoMemoryMacros.h>
+#include <CEGUI/CEGUI.h>
+#include <../CEGUIRenderer/include/OgreCEGUIRenderer.h>
+#include <../CEGUIRenderer/include/OgreCEGUIResourceProvider.h>
+#include <../CEGUIRenderer/include/OgreCEGUITexture.h>
+#include <OgreMemoryMacros.h>
+#include "TerrainFrameListener.h"
+#include "OgrePlatformQueryManager.h"
+#include "OgreVisibilityTerrainSceneManager.h"
+#include "VisibilityInfo.h"
+#include "OgreOcclusionQueriesQueryManager.h"
+#include "TestCullingTerrainApplication.h"
+
+
+//-- captions for overlays
+String TerrainFrameListener::msAlgorithmCaptions[] = 
+{
+	"Coherent Hierarchical Culling",
+	"View Frustum Culling", 
+	"Stop and Wait Culling"
+};
+
+String TerrainFrameListener::msQueryTypeCaptions[] = 
+{
+	"from camera", 
+	"from viewpoint"
+};
+
+String TerrainFrameListener::msQueryRelativeVisCaptions[] = 
+{
+	"visible pixels", 
+	"relative visibility"
+};
+
+String TerrainFrameListener::msQueryMethodCaptions[] = 
+{
+	"occlusion queries", 
+	"item buffer"
+};
+
+Real TerrainFrameListener::msObjectTerrainOffsets[] = 
+{
+	0,
+	-0.1,
+	//7,
+	0
+};
+
+Real TerrainFrameListener::msObjectScales[] = 
+{
+	0.07,
+	0.03,
+	//0.1,
+	0.03
+};
+
+String TerrainFrameListener::msObjectCaptions[] =
+{
+	"robot",
+	//"athene",
+	"natFX_Tree1_LOD2",
+	//"tree2",
+	//"HongKong_Tower",
+	"ninja"
+	//"ogrehead"
+};
+
+// output file for frame info
+const char* frames_out_filename = "frame.out";
+// output file for object positions / orientations
+const char* objects_out_filename = "objects.out";
+	
+std::ofstream video_out("video.lst");
+
+//-----------------------------------------------------------------------
+TerrainFrameListener::TerrainFrameListener(RenderWindow* win, Camera* cam, 
+									   SceneManager *sceneManager, 
+									   CEGUI::Renderer *renderer,
+									   TerrainContentGenerator *sceneGenerator,
+									   Camera *vizCamera,
+									   SceneNode *camNode,
+									   Light *sunLight,
+									   TestCullingTerrainApplication *app): 
+mCamera(cam),
+mWindow(win),
+mNumScreenShots(0),
+mTimeDelay(0),
+mSceneDetailIndex(0),
+mMoveScale(0.0f),
+mRotScale(0.0f),
+mTranslateVector(Vector3::ZERO),
+mAniso(1),
+mFiltering(TFO_BILINEAR), 
+mGUIRenderer(renderer), 
+mSceneMgr(sceneManager),
+mCurrentObject(NULL),
+mTerrainContentGenerator(sceneGenerator),
+mVisibilityThreshold(0),
+mAssumedVisibility(0),
+mCurrentAlgorithm(GtpVisibility::VisibilityEnvironment::COHERENT_HIERARCHICAL_CULLING),
+//mCurrentAlgorithm(GtpVisibility::VisibilityEnvironment::FRUSTUM_CULLING),
+mNodeVizMode(NODEVIZ_NONE),
+mVizCameraHeight(Real(2500.0)),
+mCamNode(camNode),
+mAppState(WALKTHROUGH),
+mCurrentFrame(0),
+mReplayTimeElapsed(0),
+mRotateSpeed(72),
+mMoveSpeed(50),
+mVizCamera(vizCamera),
+mStatsOn(true),
+mShutdownRequested(false), 
+mLMouseDown(false),
+mRMouseDown(false),
+mShowOctree(false),
+mUseDepthPass(false),
+mTestGeometryForVisibleLeaves(false),
+mShowVisualization(false),
+mCullCamera(false),
+mRecordFrames(false),
+mShowShadows(false),
+mShowHelp(false),
+mDisplayCameraDetails(false),
+mVisualizeCulledNodes(false),
+mSunLight(sunLight),
+mShiftPressed(false),
+mShowQueryStats(false),
+mQueryManager(NULL),
+mVisibilityManager(NULL),
+mDelayedQueriesIssued(0.0),
+mDelayedTraversedNodes(0.0),
+mCurrentObjectType(0),
+mApplication(app),
+mUseAnimation(false),
+mDeleteObjects(false),
+mUseItemBuffer(false),
+mItemBufferMode(GtpVisibility::QueryManager::PATCH_VISIBILITY),
+mRecordVideo(false),
+mPureRenderTimeFps(0.0),
+mNumVideoFrames(0),
+mDemoFps(0),
+mUseDemoFps(false),
+mUseArbQueries(false),
+mUseBufferedInputMouse(false)
+{
+	//mInputDevice = PlatformManager::getSingleton().createInputReader();
+	//mInputDevice->initialise(win, true, true);
+
+	mEventProcessor = new EventProcessor();
+	
+	mEventProcessor->initialise(win);
+	mEventProcessor->startProcessingEvents();
+	mEventProcessor->addMouseListener(this);
+	mEventProcessor->addMouseMotionListener(this);
+	mEventProcessor->addKeyListener(this);
+
+	mInputDevice = mEventProcessor->getInputReader();	
+
+	mInputDevice->setBufferedInput(true, mUseBufferedInputMouse);
+
+	// create ray query executor, used to place objects in terrain
+	mRayQueryExecutor = new RayQueryExecutor(mSceneMgr);
+	
+	//-- overlays
+	mDebugOverlay = OverlayManager::getSingleton().getByName("Core/DebugOverlay");
+	mHelpOverlay = OverlayManager::getSingleton().getByName("Example/Visibility/HelpOverlay"); 
+	mQueryOverlay = OverlayManager::getSingleton().getByName("Example/Visibility/QueryOverlay"); 
+	mCullStatsOverlay = OverlayManager::getSingleton().getByName("Example/Visibility/CullStatsOverlay"); 
+
+	initVisStatsOverlay(); // visibility stats overlay
+	initHelpOverlay();     // help overlay
+	initQueryOverlay();    // visibility query stats overlay
+
+	// show stats overlays
+	showStats(true);
+	
+	// set culling algorithm type
+	setAlgorithm(mCurrentAlgorithm);
+
+	// set scene manager options
+	setTestGeometryForVisibleLeaves(mTestGeometryForVisibleLeaves);
+
+	mSceneMgr->setOption("UseDepthPass", &mUseDepthPass);
+	
+	mSceneMgr->setOption("ShowOctree", &mShowOctree);
+	mSceneMgr->setOption("CullCamera", &mCullCamera);
+	mSceneMgr->setOption("PrepareVisualization", &mShowVisualization);
+
+	setObjectType(mCurrentObjectType);
+
+	// initialise timer
+	mTimer = Root::getSingleton().getTimer();
+	mTimeFrameEnded = mTimeFrameStarted = mTimer->getMilliseconds();
+		
+	//if (mSceneMgr->getSceneNode("robot Entity1Node")->getAttachedObject(0)->getMovableType() == "Entity")
+	//	Ogre::LogManager::getSingleton().logMessage("found entity");
+	
+	// arb or nv queries
+	//mSceneMgr->setOption("UseArbQueries", &mUseArbQueries);
+	
+	// reset statistics
+	mWalkthroughStats.Reset();
+} 
+//-----------------------------------------------------------------------
+TerrainFrameListener::~TerrainFrameListener()
+{
+	OGRE_DELETE(mRayQueryExecutor);
+	OGRE_DELETE(mEventProcessor);
+	OGRE_DELETE(mQueryManager);
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::mouseMoved(MouseEvent *e)
+{
+	// Update CEGUI with the mouse motion
+    CEGUI::System::getSingleton().injectMouseMove(e->getRelX() * 
+		mGUIRenderer->getWidth(), e->getRelY() * mGUIRenderer->getHeight());
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::mousePressed(MouseEvent* e)
+{
+	// Left mouse button down
+	if (e->getButtonID() & InputEvent::BUTTON0_MASK)
+	{
+		CEGUI::MouseCursor::getSingleton().hide();
+
+		// Setup the ray scene query
+		Ray mouseRay = mCamera->getCameraToViewportRay(e->getX(), e->getY());
+		 
+		//Vector3 queryResult; mRayQueryExecutor->executeRayQuery(&queryResult, mouseRay);
+		Real val = Math::RangeRandom(0, 360); // random rotation
+
+		// get results, create a node/entity on the position
+		mCurrentObject = 
+			mTerrainContentGenerator->GenerateSceneObject(mouseRay.getOrigin(), 
+														  Vector3(val, 0, 0), 
+														  msObjectCaptions[mCurrentObjectType]);
+		
+		mLMouseDown = true; 
+	}
+	// Right mouse button down
+	/*else if (e->getButtonID() & InputEvent::BUTTON1_MASK)
+	{
+         CEGUI::MouseCursor::getSingleton().hide();
+         mRMouseDown = true;
+	}*/
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::mouseDragDropped(MouseEvent* e)
+{
+	// Left mouse button up
+    if (e->getButtonID() & InputEvent::BUTTON0_MASK)
+    {
+		CEGUI::MouseCursor::getSingleton().show();
+		
+	    mLMouseDown = false;
+    }
+    // Right mouse button up
+    else if (e->getButtonID() & InputEvent::BUTTON1_MASK)
+    {
+        CEGUI::MouseCursor::getSingleton().show();
+
+		mRMouseDown = false;
+    }
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::mouseReleased(MouseEvent* e)
+{
+    // Left mouse button up
+    if (e->getButtonID() & InputEvent::BUTTON0_MASK)
+    {
+		CEGUI::MouseCursor::getSingleton().show();
+		
+		// start animation: only robot has animation phases
+		if (mCurrentObject && (mCurrentObjectType == TestCullingTerrainApplication::ROBOT))
+		{
+			// HACK: not neccesary the last element
+			Entity *ent = mTerrainContentGenerator->GetGeneratedEntities()->back();
+			EntityState *entState = new EntityState(ent, EntityState::MOVING, Math::RangeRandom(0.5, 1.5));
+			mApplication->getEntityStates().push_back(entState);
+		}
+
+	    mLMouseDown = false;
+    }
+    // Right mouse button up
+    else if (e->getButtonID() & InputEvent::BUTTON1_MASK)
+    {
+        CEGUI::MouseCursor::getSingleton().show(); 
+
+        mRMouseDown = false;
+    }
+} 
+//-----------------------------------------------------------------------
+void TerrainFrameListener::mouseDragged(MouseEvent *e)
+{
+	// If we are dragging the left mouse button.	 	 
+	if (mLMouseDown)
+    {
+		if (!mCurrentObject)
+			return;
+
+		Vector3 queryResult;
+		Ray mouseRay = mCamera->getCameraToViewportRay(e->getX(), e->getY());
+
+		if (mRayQueryExecutor->executeRayQuery(&queryResult, mouseRay))
+		{
+			// apply offset so object is ON terrain
+			queryResult.y += msObjectTerrainOffsets[mCurrentObjectType];
+			mCurrentObject->setPosition(queryResult);
+		}
+	}
+}
+//-----------------------------------------------------------------------
+bool TerrainFrameListener::frameStarted(const FrameEvent &evt)
+{
+	if (mWindow->isClosed())
+	{
+        return false;
+	}
+	
+	if (mDeleteObjects)
+	{
+		mApplication->deleteEntityStates();
+		mTerrainContentGenerator->RemoveGeneratedObjects();
+		mDeleteObjects = false;
+	}
+
+	if (mUseAnimation) // update animations
+	{
+		mApplication->updateAnimations(evt.timeSinceLastFrame);
+	}
+
+	if (mDisplayCameraDetails)  // Print camera details
+    {       
+        mWindow->setDebugText("P: " + StringConverter::toString(mCamera->getDerivedPosition()) + 
+			" " + "O: " + StringConverter::toString(mCamera->getDerivedOrientation()));
+    }
+
+	//-- setup what is needed for immediate mouse/key movement
+	if (mTimeDelay >= 0) 
+	{
+		mTimeDelay -= evt.timeSinceLastFrame;
+	}
+	
+	// If this is the first frame, pick a speed
+	if (evt.timeSinceLastFrame == 0)
+	{
+		mMoveScale = 1;
+		mRotScale = 0.1;
+	}
+	// Otherwise scale movement units by time passed since last frame
+	else
+	{
+		// Move about 100 units per second,
+		mMoveScale = mMoveSpeed * evt.timeSinceLastFrame;
+		// Take about 10 seconds for full rotation
+		mRotScale = mRotateSpeed * evt.timeSinceLastFrame;
+	}
+
+	mRotX = 0;
+	mRotY = 0;
+	mTranslateVector = Vector3::ZERO;
+
+	if (!processUnbufferedKeyInput(evt))
+	{
+		return false;
+	}
+	if (!mUseBufferedInputMouse)
+	{
+		if (!processUnbufferedMouseInput(evt))
+		{	
+			return false;	
+		}
+	}
+
+	//-- set parameters for visualization
+	if (mShowVisualization)
+	{
+		// important for visualization => draw octree bounding boxes
+		mSceneMgr->setOption("ShowOctree", &mShowVisualization);
+		
+		//-- setup visualization camera
+
+		mVizCamera->setPosition(0, 0, 0);
+		mVizCamera->setOrientation(Quaternion::IDENTITY);
+
+		Vector3 camPos = mCamNode->getPosition();
+		mVizCamera->setPosition(camPos.x, mVizCameraHeight, camPos.z);
+
+		// point down -Z axis
+		mVizCamera->pitch(Radian(Degree(270.0)));
+
+		// rotation arounnd X axis
+		mVizCamera->yaw(Math::ATan2(-mCamera->getDerivedDirection().x, 
+			-mCamera->getDerivedDirection().z));
+		
+		// move by a constant so view plane is on bottom of viewport
+		mVizCamera->moveRelative(Vector3(0, 800, 0));
+	}
+	else
+	{
+		// frame start time
+		mTimeFrameStarted = mTimer->getMilliseconds();
+		//Ogre::LogManager::getSingleton().logMessage("Frame started");
+	}
+
+	//-- set application state
+	switch (mAppState)
+	{
+	case REPLAY:
+		/// set the current camera data to loaded frame information 
+		setCurrentFrameInfo(evt.timeSinceLastFrame);
+		// HACK for demo
+		//addFrameInfo(mSavedFrameInfo, mCamNode, evt.timeSinceLastFrame);
+		break;
+	case WALKTHROUGH:
+		//-- recording the camera settings per frame
+		if (mRecordFrames)
+		{
+			addFrameInfo(mFrameInfo, mCamNode, evt.timeSinceLastFrame);
+			// print recording message
+			mWindow->setDebugText("Recording frame " + 
+				StringConverter::toString(mFrameInfo.size() - 1));
+		}	
+		// move camera according to input
+		moveCamera();
+
+		// clamp camera so we always walk along the terrain
+		mApplication->Clamp2Terrain(mCamNode, 5);
+		break;
+
+	default:
+		break;
+	};	
+
+	return true;
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::applyVisibilityQuery(bool fromPoint, bool relativeVisibility, 
+												bool useItemBuffer)
+{
+	// TODO: change this (does not work with other scene manager plugins)
+	VisibilityTerrainSceneManager *sm = 
+		dynamic_cast<VisibilityTerrainSceneManager *>(mSceneMgr);
+
+	int itemBufferMode = useItemBuffer ? mItemBufferMode : 0;
+	
+	int queryModes = 0;
+	queryModes |= GtpVisibility::QueryManager::PATCH_VISIBILITY; 
+	queryModes |= GtpVisibility::QueryManager::GEOMETRY_VISIBILITY;
+	queryModes |= GtpVisibility::QueryManager::NODE_VISIBILITY;
+	
+	mQueryManager = new OcclusionQueriesQueryManager(sm->GetHierarchyInterface(),
+			mWindow->getViewport(0), queryModes, itemBufferMode);
+
+	//mQueryManager = new PlatformQueryManager(sm->GetHierarchyInterface(),	mWindow->getViewport(0), false);
+	
+	sm->GetVisibilityManager()->SetQueryManager(mQueryManager);
+
+	GtpVisibility::NodeInfoContainer visibleNodes;
+	GtpVisibility::MeshInfoContainer visibleGeometry;
+	GtpVisibility::PatchInfoContainer visiblePatches;
+
+
+	if (fromPoint)
+	{
+		mQueryManager->
+			ComputeFromPointVisibility(mCamNode->getPosition(), &visibleNodes, 
+									   &visibleGeometry, &visiblePatches, relativeVisibility);
+	}
+	else
+	{
+		mQueryManager->ComputeCameraVisibility(*mCamera,
+			    &visibleNodes, &visibleGeometry, &visiblePatches, relativeVisibility);
+	}
+		
+	std::stringstream d; 
+	d << "Query mode: " << queryModes << ", "
+	  << msQueryTypeCaptions[fromPoint ?  1 : 0].c_str() << " "
+	  << msQueryRelativeVisCaptions[relativeVisibility ? 1 : 0].c_str() << " "
+      << msQueryMethodCaptions[useItemBuffer ? 1 : 0].c_str();
+	LogManager::getSingleton().logMessage(d.str());
+
+
+	float averageNodeVis = 0, averageGeometryVis = 0, averagePatchVis = 0;
+	int geomSize = 0, nodesSize = 0, patchSize = 0;
+
+	GtpVisibility::MeshInfoContainer::iterator geomIt, geomIt_end = visibleGeometry.end();
+
+	for (geomIt = visibleGeometry.begin(); geomIt != geomIt_end; ++geomIt)
+	{
+		// add if not 0
+		if ((*geomIt).GetVisiblePixels())
+		{
+			float vis = relativeVisibility ? 
+				(*geomIt).ComputeRelativeVisibility() : (float)(*geomIt).GetVisiblePixels();
+	
+			averageGeometryVis += vis;
+			++ geomSize;
+			
+			std::stringstream d; 
+			d << "Geometry " << geomSize << " id: " << (*geomIt).GetSource()->getSubEntity(0)->getId() 
+			  << " visibility: "  << (*geomIt).GetVisiblePixels() << ", " << (*geomIt).GetProjectedPixels();
+			LogManager::getSingleton().logMessage(d.str());
+		}
+	}
+
+	GtpVisibility::NodeInfoContainer::iterator nodesIt, nodesIt_end = visibleNodes.end();
+
+	for (nodesIt = visibleNodes.begin(); nodesIt != nodesIt_end; ++nodesIt)
+	{
+		// add if not 0
+		if ((*nodesIt).GetVisiblePixels())
+		{
+			float vis = relativeVisibility ? 
+				(*nodesIt).ComputeRelativeVisibility() : (float)(*nodesIt).GetVisiblePixels();
+		
+			averageNodeVis += vis;
+			++ nodesSize;
+
+			std::stringstream d; d << "Node visibility: " << vis;
+			LogManager::getSingleton().logMessage(d.str());
+		}	
+	}
+
+	GtpVisibility::PatchInfoContainer::iterator patchIt, patchIt_end = visiblePatches.end();
+
+	for (patchIt = visiblePatches.begin(); patchIt != patchIt_end; ++ patchIt)
+	{
+		// add if not 0
+		if ((*patchIt).GetVisiblePixels())
+		{
+			float vis = relativeVisibility ? 
+				(*patchIt).ComputeRelativeVisibility() : (float)(*patchIt).GetVisiblePixels();
+		
+			averagePatchVis += vis;
+			++ patchSize;
+
+			std::stringstream d; d << "Patch visibility: " << vis;
+			LogManager::getSingleton().logMessage(d.str());
+		}	
+	}
+
+	if (nodesSize)
+		averageNodeVis /= (float)nodesSize;
+	if (geomSize)
+		averageGeometryVis /= (float)geomSize;
+	if (patchSize)
+		averagePatchVis /= (float)patchSize;
+
+	//-- update visibility queries stats
+    try 
+	{
+		char str[100];
+		
+		sprintf(str, ": %s, %s, %s", 
+				msQueryTypeCaptions[fromPoint ?  1 : 0].c_str(),
+				msQueryRelativeVisCaptions[relativeVisibility ? 1 : 0].c_str(),
+				msQueryMethodCaptions[useItemBuffer ? 1 : 0].c_str());
+
+		mQueryTypeInfo->setCaption(str);
+
+		sprintf(str, ": %d", (int)nodesSize); 
+		mQueryVisibleNodesInfo->setCaption(str);
+	
+		sprintf(str,": %d", (int)geomSize); 
+		mQueryVisibleGeometryInfo->setCaption(str);
+		
+		sprintf(str,": %d", (int)patchSize); 
+		mQueryVisiblePatchInfo->setCaption(str);
+
+		sprintf(str,": %3.3f", averageNodeVis); 
+		mQueryNodeVisibilityInfo->setCaption(str);
+
+		sprintf(str,": %3.3f", averageGeometryVis); 
+		mQueryGeometryVisibilityInfo->setCaption(str);
+
+		sprintf(str,": %3.3f", averagePatchVis); 
+		mQueryPatchVisibilityInfo->setCaption(str);
+	}
+	catch (...)
+	{
+		// ignore
+	}
+
+	// show the results
+	if (!mShowQueryStats && !mShowHelp)
+	{
+		mQueryOverlay->show();
+		mShowQueryStats = true;
+	}
+
+	delete mQueryManager;
+}
+
+
+bool TerrainFrameListener::processUnbufferedMouseInput(const FrameEvent& evt)
+{
+	/* Rotation factors, may not be used if the second mouse button is pressed. */
+
+    /* If the second mouse button is pressed, then the mouse movement results in 
+       sliding the camera, otherwise we rotate. */
+    if (mInputDevice->getMouseButton(1))
+    {
+		mTranslateVector.x += mInputDevice->getMouseRelativeX() * 0.13;
+		mTranslateVector.y -= mInputDevice->getMouseRelativeY() * 0.13;
+	}
+	else
+	{
+		mRotX = Degree(-mInputDevice->getMouseRelativeX() * 0.13);
+		mRotY = Degree(-mInputDevice->getMouseRelativeY() * 0.13);
+	}
+
+	return true;
+}
+//-----------------------------------------------------------------------
+bool TerrainFrameListener::frameEnded(const FrameEvent& evt)
+{
+	if (mShutdownRequested)
+		return false;
+
+	// timer end time
+	if (!mShowVisualization)
+	{
+		mTimeFrameEnded = mTimer->getMilliseconds();
+		//Ogre::LogManager::getSingleton().logMessage("Frame ended");
+	}
+
+    updateStats();
+
+	if (mRecordVideo) // record current frame
+	{
+		//Ogre::LogManager::getSingleton().logMessage("taking video frame");
+		takeVideoFrame(video_out);
+		//Ogre::LogManager::getSingleton().logMessage("finished");
+	}
+	//-- IMPORTANT: must be set, otherwise terrain is not rendered correctly
+	mSceneMgr->endFrame();
+
+	if (mTimeDelay <= 0) // simulates approx. one second
+		mTimeDelay = 1.0;
+
+	return true;
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::moveCamera()
+{
+	// move node rather than camera so orientation is right in the visualization
+	mCamNode->yaw(mRotX, Ogre::Node::TS_WORLD);
+	//mCamNode->rotate(Vector3(0,1,0), mRotX, Ogre::Node::TS_WORLD);
+	mCamNode->pitch(mRotY);
+
+	mCamNode->translate(mCamNode->getLocalAxes(), mTranslateVector);
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::writeFrames()
+{
+	std::ofstream ofstr(frames_out_filename);
+	
+	std::vector<frame_info>::const_iterator it, it_end;
+
+	it_end = mFrameInfo.end();
+	for (it = mFrameInfo.begin(); it < it_end; ++it)
+	{
+		ofstr << StringConverter::toString((*it).position) << " " 
+			  << StringConverter::toString((*it).orientation) << " "
+			  << StringConverter::toString((*it).timeElapsed) << " "
+			  << StringConverter::toString((*it).fps) << "\n";
+	}
+	ofstr.close();
+}
+// quick hack
+void TerrainFrameListener::writeNewFrameInfo()
+{
+	std::ofstream ofstr("newframe.out");
+	
+	std::vector<frame_info>::const_iterator it, it_end;
+
+	it_end = mSavedFrameInfo.end();
+	for (it = mSavedFrameInfo.begin(); it < it_end; ++it)
+	{
+		ofstr << StringConverter::toString((*it).position) << " " 
+			  << StringConverter::toString((*it).orientation) << " "
+			  << StringConverter::toString((*it).timeElapsed) << " "
+			  << StringConverter::toString((*it).fps) << "\n";
+	}
+	ofstr.close();
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::loadFrames()
+{
+	std::ifstream ifstr(frames_out_filename);
+	char line[256];
+	frame_info info;
+
+	// reset current values
+	mFrameInfo.clear();
+	mCurrentFrame = 0;
+	
+	while (!ifstr.eof()) 
+	{
+		ifstr.getline(line, 256);
+		sscanf(line, "%f %f %f %f %f %f %f %f %f", &info.position.x, &info.position.y, &info.position.z,
+			   &info.orientation.w, &info.orientation.x, &info.orientation.y, &info.orientation.z,
+			   &info.timeElapsed, &info.fps);
+		
+		mFrameInfo.push_back(info);
+		
+		// std::stringstream d; d << StringConverter::toString(info.position) << " " << StringConverter::toString(info.orientation);
+		// LogManager::getSingleton().logMessage(d.str());
+	}
+	ifstr.close();
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::nextAppState()
+{
+	mCurrentFrame = 0;
+	int lastState = mAppState;
+
+	// transition to the next state
+	mAppState = (mAppState + 1) % STATE_NUM;
+
+	// if last state was replay state
+	if (lastState == REPLAY)
+	{
+        // reset debug text
+		mWindow->setDebugText("");
+				
+		// hack for producing demo
+		writeNewFrameInfo();
+		mSavedFrameInfo.clear();
+
+		std::stringstream d;
+		mWalkthroughStats.Print(d, msAlgorithmCaptions[mCurrentAlgorithm]);
+ 		
+		LogManager::getSingleton().logMessage(d.str());
+	}
+	
+	// replay recorded walkthrough
+	if (mAppState == REPLAY)
+	{
+		// no recording during replay
+		mRecordFrames = false; mWindow->setDebugText("");
+
+		// load recorded walkthrough from disk
+		if (mFrameInfo.size() == 0)
+		{
+			loadFrames();
+		}
+		
+		// if there are no recorded frames => set next state
+		if (mFrameInfo.size() == 0) 
+		{
+			nextAppState();
+		}
+		else // replay
+		{
+			mWindow->setDebugText("Replay");
+			
+			// reset, because we measure fps stats during walkthrough (warning: average fps broken)
+			mWindow->resetStatistics();
+			mWalkthroughStats.Reset();
+
+			//-- initialise frame data
+			mReplayTimeElapsed = 0;
+
+			mCamNode->setPosition(mFrameInfo[0].position);
+			mCamNode->setOrientation(mFrameInfo[0].orientation);
+		}
+	}
+
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::toggleRecord()
+{
+	mRecordFrames = !mRecordFrames;
+
+	if (mRecordFrames) 
+	{
+		// starting new recording => clear old frame info
+		mFrameInfo.clear();
+	}
+	else
+	{
+		writeFrames(); // write frame info to file
+		mWindow->setDebugText("");
+	}
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::changeThreshold(int incr)
+{
+	mVisibilityThreshold += incr; 
+
+	if (mVisibilityThreshold < 0)
+	{
+		mVisibilityThreshold = 0;
+	}
+
+	char str[100]; sprintf(str,": %d", mVisibilityThreshold);
+
+	mSceneMgr->setOption("Threshold", &mVisibilityThreshold); 
+	mThresholdInfo->setCaption(str);
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::changeAssumedVisibility(int incr)
+{
+	mAssumedVisibility += incr; 
+
+	if (mAssumedVisibility < 0) 
+	{	
+		mAssumedVisibility = 0;
+	}
+
+	char str[100]; sprintf(str,": %d", mAssumedVisibility);
+
+	mSceneMgr->setOption("AssumedVisibility", &mAssumedVisibility); 
+	mAssumedVisibilityInfo->setCaption(str);
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::zoomVizCamera(int zoom)
+{
+	mVizCameraHeight += zoom; 
+	if(mVizCameraHeight < 0) mVizCameraHeight = 0;
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::nextAlgorithm()
+{
+	mCurrentAlgorithm = (mCurrentAlgorithm + 1) % 
+		GtpVisibility::VisibilityEnvironment::NUM_CULLING_MANAGERS;
+	setAlgorithm(mCurrentAlgorithm);
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::setObjectType(int objectType)
+{
+	if (mCurrentObjectType >= 3) // TODO: define a constant
+		mCurrentObjectType = 0;
+
+	// parameters for new object
+	mTerrainContentGenerator->SetOffset(msObjectTerrainOffsets[mCurrentObjectType]);
+	Real scale = msObjectScales[mCurrentObjectType];
+	mTerrainContentGenerator->SetScale(Vector3(scale, scale, scale));
+
+	mCurrentObjectTypeInfo->setCaption(": " + msObjectCaptions[mCurrentObjectType]);
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::setAlgorithm(int algorithm)
+{
+	mAlgorithmInfo->setCaption(": " + msAlgorithmCaptions[mCurrentAlgorithm]);
+	mSceneMgr->setOption("Algorithm", &mCurrentAlgorithm);
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::updateStats()
+{
+	unsigned int opt = 0;
+	char str[100];
+	
+	static String currFpsString = "Current FPS: ";
+	static String avgFpsString = "Average FPS: ";
+	static String bestFpsString = "Best FPS: ";
+	static String worstFpsString = "Worst FPS: ";
+	static String trisString = "Triangle Count: ";
+
+	int currentFps = mWindow->getStatistics().lastFPS;
+	
+	// HACK for demo: use precomputed FPS
+	if (mUseDemoFps)
+		currentFps = mDemoFps;
+#if 0
+	// HACK: take pure rendering time, only measures the render call
+	long pureRenderTime = mTimeFrameEnded - mTimeFrameStarted;
+
+	if (pureRenderTime)
+	{
+		mPureRenderTimeFps = 1000.0 / (float) pureRenderTime;
+	}
+	currentFps = mPureRenderRenderTimeFps;
+	//std::stringstream d; d << "Pure render time fps: " << mPureRenderTimeFps << "\n";
+	//Ogre::LogManager::getSingleton().logMessage(d.str());
+#endif
+	
+	unsigned int nodeInfo[3];
+    mSceneMgr->getOption("NumRenderedNodes", nodeInfo);
+	mSceneMgr->getOption("NumQueryCulledNodes", nodeInfo+1);
+	mSceneMgr->getOption("NumFrustumCulledNodes", nodeInfo+2);
+
+
+	mWalkthroughStats.UpdateFrame(currentFps, mWindow->getBestFPS(), mWindow->getWorstFPS(),
+								  (int)mWindow->getTriangleCount(), nodeInfo[0], nodeInfo[1], nodeInfo[2]);
+
+	// HACK: compute average fps ourselfs, because ogre avg. fps is wrong
+	// TODO: update only once per second
+	float avgFps = (float)mWalkthroughStats.mAccFps / (float)(mWalkthroughStats.mFrameCount);
+	
+
+	// update stats when necessary
+    try 
+	{
+		OverlayElement* guiAvg = OverlayManager::getSingleton().getOverlayElement("Core/AverageFps");
+		OverlayElement* guiCurr = OverlayManager::getSingleton().getOverlayElement("Core/CurrFps");
+		OverlayElement* guiBest = OverlayManager::getSingleton().getOverlayElement("Core/BestFps");
+		OverlayElement* guiWorst = OverlayManager::getSingleton().getOverlayElement("Core/WorstFps");
+
+		const RenderTarget::FrameStats& stats = mWindow->getStatistics();
+
+		// HACK: take newly computed avg. fps instead of Ogre avg fps and update only once per second
+		if (mTimeDelay < 0) 
+		{		
+			guiAvg->setCaption(avgFpsString + StringConverter::toString(avgFps) + " ms");
+			//guiCurr->setCaption(currFpsString + StringConverter::toString(currentFps));
+		}
+		//guiAvg->setCaption(avgFps + StringConverter::toString(stats.avgFPS));
+		guiCurr->setCaption(currFpsString + StringConverter::toString(currentFps));
+		
+		//std::stringstream d; d << "frame rate :" << stats.lastFPS;
+		//Ogre::LogManager::getSingleton().logMessage(d.str());
+
+		guiBest->setCaption(bestFpsString + StringConverter::toString(stats.bestFPS)
+			+" "+StringConverter::toString(stats.bestFrameTime) + " ms");
+		guiWorst->setCaption(worstFpsString + StringConverter::toString(stats.worstFPS)
+			+" "+StringConverter::toString(stats.worstFrameTime) + " ms");
+
+		OverlayElement* guiTris = OverlayManager::getSingleton().getOverlayElement("Core/NumTris");
+        guiTris->setCaption(trisString + StringConverter::toString(stats.triangleCount));
+		
+		//LogManager::getSingleton().logMessage(StringConverter::toString(stats.triangleCount));
+
+		OverlayElement* guiDbg = OverlayManager::getSingleton().getOverlayElement("Core/DebugText");
+		guiDbg->setCaption(mWindow->getDebugText());
+
+
+		//-- culling stats
+		mSceneMgr->getOption("NumFrustumCulledNodes", &opt); sprintf(str,": %d", opt); 
+		mFrustumCulledNodesInfo->setCaption(str);
+
+		mSceneMgr->getOption("NumQueryCulledNodes", &opt); sprintf(str,": %d", opt); 
+		mQueryCulledNodesInfo->setCaption(str);
+	
+		mSceneMgr->getOption("NumHierarchyNodes", &opt); sprintf(str,": %d", opt); 
+		mHierarchyNodesInfo->setCaption(str);
+
+		mSceneMgr->getOption("NumRenderedNodes", &opt); sprintf(str,": %d", opt); 
+		mRenderedNodesInfo->setCaption(str);
+
+		sprintf(str,": %d", mTerrainContentGenerator->GetObjectCount()); 
+		mObjectsCountInfo->setCaption(str);
+
+		// take old value into account in order to create no sudden changes
+		mSceneMgr->getOption("NumQueriesIssued", &opt); 
+		mDelayedQueriesIssued = mDelayedQueriesIssued * 0.8 + (float)opt * 0.2;
+		sprintf(str,": %d", (int)mDelayedQueriesIssued); 
+		mQueriesIssuedInfo->setCaption(str);
+
+		mSceneMgr->getOption("NumTraversedNodes", &opt); 
+		mDelayedTraversedNodes = mDelayedTraversedNodes * 0.8 + (float)opt * 0.2;
+		sprintf(str,": %d", (int)mDelayedTraversedNodes); 
+		mTraversedNodesInfo->setCaption(str);
+
+	}
+	catch (...)
+	{
+		// ignore
+	}
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::setTestGeometryForVisibleLeaves(bool testGeometryForVisibleLeaves)
+{
+	mSceneMgr->setOption("TestGeometryForVisibleLeaves", &mTestGeometryForVisibleLeaves);
+	
+	/* disable optimization which tests geometry instead of aabb
+	 * for "delayed" rendering of transparents (i.e., render transparents after all the solids)
+	 * because otherwise visible transparents could be skipped
+	 */
+	bool delayedRendering = !mTestGeometryForVisibleLeaves;
+
+	mSceneMgr->setOption("DelayRenderTransparents", &delayedRendering);
+
+	if (mTestGeometryForVisibleLeaves)
+	{
+		mTestGeometryForVisibleLeavesInfo->setCaption(": true");
+	}
+	else
+	{
+		mTestGeometryForVisibleLeavesInfo->setCaption(": false");
+	}
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::toggleShowOctree()
+{
+	mShowOctree = !mShowOctree;
+
+	mSceneMgr->setOption("ShowOctree", &mShowOctree);
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::toggleUseDepthPass()
+{
+	mUseDepthPass = !mUseDepthPass;
+
+	mSceneMgr->setOption("UseDepthPass", &mUseDepthPass);
+	
+	if (mUseDepthPass)
+	{
+		mUseDepthPassInfo->setCaption(": true");
+	}
+	else
+	{
+		mUseDepthPassInfo->setCaption(": false");
+	}
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::toggleUseArbQueries()
+{
+	mUseArbQueries = !mUseArbQueries;
+
+	mSceneMgr->setOption("UseArbQueries", &mUseArbQueries);
+	
+	if (mUseArbQueries)
+	{
+		mUseArbQueriesInfo->setCaption(": ARB");
+	}
+	else
+	{
+		mUseArbQueriesInfo->setCaption(": NV");
+	}
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::toggleShowViz()
+{
+	mVisualizeCulledNodes = mShowVisualization = !mShowVisualization;
+	
+	// create viewport with priority VIZ_VIEWPORT_Z_ORDER: 
+	// will be rendered over standard viewport
+	if (mShowVisualization)
+	{	
+		Viewport *vizvp = mWindow->addViewport(mVizCamera, 
+			VIZ_VIEWPORT_Z_ORDER, 0.6, 0.6, 0.4, 0.4); 
+				
+		vizvp->setBackgroundColour(ColourValue(0.0, 0.3, 0.2, 1));
+
+		vizvp->setOverlaysEnabled(false);
+		// Alter the camera aspect ratio to match the viewport
+        mVizCamera->setAspectRatio(Real(vizvp->getActualWidth()) / 
+								   Real(vizvp->getActualHeight()));
+		
+		mSceneMgr->setOption("VisualizeCulledNodes", &mVisualizeCulledNodes);
+		//vizvp->setClearEveryFrame(false);
+
+		// Create a skyplane (for visualization background)
+		/*
+		Plane plane;
+		plane.d = -1000;
+		plane.normal = Vector3::UNIT_Y;
+		mSceneMgr->setSkyPlane(true, plane, "Examples/TransparentTest", 4000, 75, false);
+		*/
+	}
+	else
+	{
+		// remove visualization viewport
+		mWindow->removeViewport(VIZ_VIEWPORT_Z_ORDER);
+
+		// octree bounding boxes are shown for visualization purpose, reset now
+		mSceneMgr->setOption("ShowOctree", &mShowOctree);
+	}
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::toggleShowShadows()
+{
+	mShowShadows = !mShowShadows;
+
+	mSunLight->setCastShadows(mShowShadows);
+
+	if (mShowShadows)
+	{
+		mSceneMgr->setShadowTechnique(SHADOWTYPE_TEXTURE_MODULATIVE);
+		//mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_MODULATIVE);
+		//mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_ADDITIVE);		
+	}
+	else
+	{
+		mSceneMgr->setShadowTechnique(SHADOWTYPE_NONE);
+	}
+
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::nextNodeVizMode()
+{
+	mNodeVizMode = (mNodeVizMode + 1) % NODEVIZ_MODES_NUM;
+
+	bool renderNodesForViz = (mNodeVizMode == NODEVIZ_RENDER_NODES) || 
+		(mNodeVizMode == NODEVIZ_RENDER_NODES_AND_CONTENT);
+	bool renderNodesContentForViz = (mNodeVizMode == NODEVIZ_RENDER_NODES_AND_CONTENT);
+	//bool renderNodesContentForViz = mNodeVizMode == NODEVIZ_RENDER_GEOMETRY;
+
+	mSceneMgr->setOption("RenderNodesForViz", &renderNodesForViz);
+	mSceneMgr->setOption("RenderNodesContentForViz", &renderNodesContentForViz);
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::keyPressed(KeyEvent* e)
+{
+	// hide exact visibility query overlay
+	if (mShowQueryStats)
+	{
+		mQueryOverlay->hide();
+		mShowQueryStats = false;
+	}
+
+	switch(e->getKey())
+	{
+	case KC_ESCAPE:
+		mShutdownRequested = true;
+		e->consume();
+		return;
+
+	case KC_SPACE:
+		nextAlgorithm();
+		break;
+	
+    case KC_F:
+		nextFilter();
+		break;
+	case KC_R:
+		nextSceneDetailLevel();
+		break;
+	case KC_P:
+		toggleDisplayCameraDetails();
+		break;
+	case KC_G:
+		mTestGeometryForVisibleLeaves = !mTestGeometryForVisibleLeaves;
+		setTestGeometryForVisibleLeaves(mTestGeometryForVisibleLeaves);
+		break;
+	case KC_T:
+		toggleShowOctree();
+		break;
+	case KC_X:
+		toggleUseDepthPass();
+		break;
+	case KC_H:
+		toggleShowShadows();
+		break;
+
+	case KC_I:
+		mUseItemBuffer = !mUseItemBuffer;
+		break;
+
+	case KC_C:
+
+		if (mItemBufferMode != GtpVisibility::QueryManager::GEOMETRY_VISIBILITY)
+			mItemBufferMode = GtpVisibility::QueryManager::GEOMETRY_VISIBILITY;
+		else
+			mItemBufferMode = GtpVisibility::QueryManager::PATCH_VISIBILITY;
+
+		break;
+
+	case KC_SUBTRACT:
+		changeThreshold(-10);
+		break;
+	case KC_ADD:
+		changeThreshold(10);
+		break;
+
+	//-- visualization
+	case KC_1:
+		toggleShowViz();
+		break;
+	case KC_2:
+		nextNodeVizMode();
+		break;
+
+	case KC_F1:
+		toggleShowHelp();
+		break;
+	case KC_F2:
+		mStatsOn = !mStatsOn;
+		showStats(mStatsOn);
+		break;
+	case KC_F3:
+		nextAppState();
+		break;
+	case KC_F4:
+		toggleRecord();
+		break;
+	case KC_F5:
+		applyVisibilityQuery(false, mShiftPressed, mUseItemBuffer);
+		break;
+	case KC_F6:
+		applyVisibilityQuery(true, mShiftPressed, mUseItemBuffer);
+		break;
+	
+	case KC_F7:
+		setObjectType(++mCurrentObjectType);
+		break;
+	case KC_F8:
+		mApplication->generateScene(500, mCurrentObjectType);
+		break;
+	case KC_F9:
+		mUseAnimation = !mUseAnimation;
+		break;
+
+	case KC_F10:
+		mRecordVideo = !mRecordVideo;
+			
+	case KC_F11:
+		takeScreenshot();
+		break;
+	case KC_F12:
+		mTerrainContentGenerator->WriteObjects(objects_out_filename);
+		break;
+
+	case KC_8:
+		changeAssumedVisibility(-1);
+		break;
+	case KC_9:
+		changeAssumedVisibility(1);
+		break;
+	case KC_LSHIFT:
+		mShiftPressed = true;
+		break;
+	case KC_DELETE:
+		mDeleteObjects = true;
+		break;
+	case KC_M: // hack
+		mUseDemoFps = !mUseDemoFps;
+		break;
+	case KC_Q:
+		toggleUseArbQueries();
+		break;
+	case KC_O:
+		switchMouseMode();
+		break;
+	//KEY_PRESSED(KC_F3, 0.3, writeFrames());
+	//KEY_PRESSED(KC_F4, 0.3, loadFrames());
+	default:
+		break;
+	}
+
+	CEGUI::System::getSingleton().injectKeyDown(e->getKey());
+	CEGUI::System::getSingleton().injectChar(e->getKeyChar());
+	e->consume();
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::keyReleased(KeyEvent* e)
+{
+	if (e->getKey() == KC_LSHIFT)
+	{
+		mShiftPressed = false;
+	}
+	
+	CEGUI::System::getSingleton().injectKeyUp(e->getKey());
+	e->consume();
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::keyClicked(KeyEvent* e) 
+{
+	// Do nothing
+	e->consume();
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::addFrameInfo(FrameInfoContainer &frameInfos, SceneNode *camNode, Real timeElapsed)
+{
+	frame_info info;
+
+	info.orientation = mCamNode->getOrientation();
+	info.position = mCamNode->getPosition();
+	info.timeElapsed = timeElapsed;
+	info.fps = mWindow->getStatistics().lastFPS;
+
+	frameInfos.push_back(info);
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::setCurrentFrameInfo(Real timeElapsed)
+{
+	//-- find current frame relative to elapsed frame time		
+	mReplayTimeElapsed -= timeElapsed;
+	
+	while ((mReplayTimeElapsed <= 0) && (mCurrentFrame < (int)mFrameInfo.size() - 1))
+	{
+		mReplayTimeElapsed += mFrameInfo[mCurrentFrame ++].timeElapsed;
+	}
+
+
+	// TODO: crashes here if recording / replaying on the same time!!
+	frame_info new_frame = mFrameInfo[mCurrentFrame]; 
+	frame_info old_frame = mFrameInfo[mCurrentFrame - 1];
+		
+	//-- interpolate frames
+	Real factor = 1;
+
+	if (old_frame.timeElapsed > 0)
+	{
+		factor = mReplayTimeElapsed / old_frame.timeElapsed;
+	}
+
+	Vector3 camPos = old_frame.position + factor 
+		* (new_frame.position - old_frame.position);
+
+	// interpolate the orientation
+	Quaternion camOrienation = Quaternion::Slerp(factor, old_frame.orientation, 
+		new_frame.orientation, true);
+
+	// HACK: interpolate fps
+	mDemoFps = old_frame.fps + factor * (new_frame.fps -old_frame.fps);
+
+	mCamNode->setPosition(camPos);
+	mCamNode->setOrientation(camOrienation);
+	
+	// stop replaying after one full walkthrough
+	if (mCurrentFrame == (int)mFrameInfo.size() - 1)
+	{
+		nextAppState();
+	}
+}
+//-----------------------------------------------------------------------    
+bool TerrainFrameListener::processUnbufferedKeyInput(const FrameEvent& evt)
+{
+	bool cursorPressed = false;
+	
+	/* Move camera forward by keypress. */
+    if (mInputDevice->isKeyDown(KC_UP) || mInputDevice->isKeyDown(KC_W))
+	{
+		mTranslateVector.z = -mMoveScale;
+		cursorPressed = true;
+	}
+    /* Move camera backward by keypress. */
+    if (mInputDevice->isKeyDown(KC_DOWN) || mInputDevice->isKeyDown(KC_S))
+    {
+		mTranslateVector.z = mMoveScale;
+		cursorPressed = true;
+    }
+
+	if (mInputDevice->isKeyDown(KC_A))
+	{
+		mTranslateVector.x -= mMoveScale;
+		mTranslateVector.y += mMoveScale;
+
+		cursorPressed = true;
+	}
+
+	if (mInputDevice->isKeyDown(KC_D))
+	{
+		mTranslateVector.x += mMoveScale;
+		mTranslateVector.y -= mMoveScale;
+
+		cursorPressed = true;
+	}
+
+    if (mInputDevice->isKeyDown(KC_RIGHT))
+    {
+        mCamNode->yaw(-mRotScale);
+		cursorPressed = true;
+    }
+
+    if (mInputDevice->isKeyDown(KC_LEFT))
+    {
+        mCamNode->yaw(mRotScale);
+		cursorPressed = true;
+    }
+	// visualization camera
+	if (mInputDevice->isKeyDown(KC_3))
+	{
+		zoomVizCamera(50);
+	}
+	if (mInputDevice->isKeyDown(KC_4))
+	{
+		zoomVizCamera(-50);
+	}
+
+	// show the results
+	if (cursorPressed && mShowQueryStats)
+	{
+		mQueryOverlay->hide();
+		mShowQueryStats = false;
+	}
+
+    // Return true to continue rendering
+    return true;
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::nextFilter()
+{
+	switch (mFiltering)
+	{
+	case TFO_BILINEAR:
+		mFiltering = TFO_TRILINEAR;
+		mAniso = 1;
+		break;
+	case TFO_TRILINEAR:
+		mFiltering = TFO_ANISOTROPIC;
+		mAniso = 8;
+		break;
+	case TFO_ANISOTROPIC:
+		mFiltering = TFO_BILINEAR;
+		mAniso = 1;
+		break;
+	default:
+		break;
+	}
+
+    MaterialManager::getSingleton().setDefaultTextureFiltering(mFiltering);
+    MaterialManager::getSingleton().setDefaultAnisotropy(mAniso);
+
+	// reload stats
+    showStats(mStatsOn);
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::nextSceneDetailLevel()
+{
+	mSceneDetailIndex = (mSceneDetailIndex + 1) % 3;
+	switch (mSceneDetailIndex) 
+	{
+		case 0: 
+			mCamera->setDetailLevel(SDL_SOLID); 
+			break;
+		case 1: 
+			mCamera->setDetailLevel(SDL_WIREFRAME); 
+			break;
+		case 2: 
+			mCamera->setDetailLevel(SDL_POINTS); 
+			break;
+	}
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::takeVideoFrame(std::ofstream &ofstr)
+{
+	char name[50];
+
+	sprintf(name, "frame_%05d.tga", ++mNumVideoFrames);
+    mWindow->writeContentsToFile(name);
+    //mWindow->setDebugText(String("Wrote ") + name);
+
+	ofstr << name << "\n";
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::takeScreenshot()
+{
+	char name[50];
+
+	sprintf(name, "screenshot_%05d.png", ++mNumScreenShots);
+    mWindow->writeContentsToFile(name);
+    //mWindow->setDebugText(String("Wrote ") + name);
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::toggleDisplayCameraDetails()
+{
+	mDisplayCameraDetails = !mDisplayCameraDetails;
+        
+    if (!mDisplayCameraDetails)
+	{
+		mWindow->setDebugText("");
+	}
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::showStats(bool show)
+{
+	if (mDebugOverlay && mCullStatsOverlay)
+	{
+		if (show)
+		{
+			mDebugOverlay->show();
+			mCullStatsOverlay->show();
+		}
+		else
+		{
+			mDebugOverlay->hide();
+			mCullStatsOverlay->hide();
+		}
+	}
+}
+
+//-----------------------------------------------------------------------
+void TerrainFrameListener::toggleShowHelp()
+{
+	mShowHelp = !mShowHelp;
+
+	if (mShowHelp)
+	{
+		mHelpOverlay->show();
+	}
+	else
+	{
+		mHelpOverlay->hide();
+	}
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::initOverlayElement(OverlayElement **elInfo, String ext, 
+											  String name, int top, String caption)
+{
+	OverlayElement *el = 
+		OverlayManager::getSingleton().getOverlayElement(ext + name);
+
+	(*elInfo) = OverlayManager::getSingleton().getOverlayElement(ext + name + "Info");
+	(*elInfo)->setCaption(caption);
+
+	el->setTop(top);
+	(*elInfo)->setTop(top);
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::initHelpOverlayElement(String name, int top)
+{
+	OverlayElement *el = OverlayManager::getSingleton().getOverlayElement(
+		"Example/Visibility/Help/" + name);
+
+	el->setTop(top);
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::initHelpOverlay()
+{
+	const int vert_space = 15;
+	int top = 30;
+
+	initHelpOverlayElement("ShowHelp", top); top += vert_space;
+	initHelpOverlayElement("Stats", top); top += vert_space;
+	initHelpOverlayElement("AppState", top); top += vert_space;
+	initHelpOverlayElement("Recorded", top); top += vert_space;
+	initHelpOverlayElement("Animation", top); top += vert_space;
+	initHelpOverlayElement("Video", top); top += vert_space;
+	initHelpOverlayElement("Screenshots", top); top += vert_space;
+	initHelpOverlayElement("WriteOut", top); top += vert_space;
+
+
+	top +=vert_space;
+	initHelpOverlayElement("SceneDetail", top); top += vert_space;
+	initHelpOverlayElement("DisplayCameraDetails", top); top += vert_space;
+	initHelpOverlayElement("DisplayOctree", top); top += vert_space;
+	initHelpOverlayElement("UseShadows", top); top += vert_space;
+	initHelpOverlayElement("Filter", top); top += vert_space;
+
+	//-- visualization
+	top += vert_space;
+	initHelpOverlayElement("VizSection", top); top += vert_space;
+	initHelpOverlayElement("Viz", top); top += vert_space;
+	initHelpOverlayElement("NextVizMode", top); top += vert_space;
+	initHelpOverlayElement("ZoomViz", top); top += vert_space;
+
+
+	//-- visibility queries
+	top += vert_space;
+	initHelpOverlayElement("VisQuery", top); top += vert_space;
+	initHelpOverlayElement("FromCameraQuery", top); top += vert_space;
+	initHelpOverlayElement("FromPointQuery", top); top += vert_space;
+	initHelpOverlayElement("QueryType", top); top += vert_space;
+	initHelpOverlayElement("QueryTarget", top); top += vert_space;
+
+	//-- object generation
+	top += vert_space;
+	initHelpOverlayElement("SceneObjects", top); top += vert_space;
+	initHelpOverlayElement("PlaceObjects", top); top += vert_space;
+	initHelpOverlayElement("GenerateObjects", top); top += vert_space;
+	initHelpOverlayElement("RemoveObjects", top); top += vert_space;
+	initHelpOverlayElement("DropObject", top); top += vert_space;
+
+	OverlayElement *helpPanel = OverlayManager::getSingleton().getOverlayElement(
+		"Example/Visibility/Help/HelpPanel");
+
+	helpPanel->setHeight(top + 10);
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::initVisStatsOverlay()
+{
+	const int border_height = 10;
+	const int vert_space = 15;
+
+	//-- visibility culling stats overlay
+	int top = border_height;
+
+	String ext = "Example/Visibility/";
+	
+	initOverlayElement(&mAlgorithmInfo, ext, "Algorithm", top,
+		": " + msAlgorithmCaptions[mCurrentAlgorithm]); top += vert_space;
+
+	initOverlayElement(&mThresholdInfo, ext, "Threshold", top, ": 0"); top += vert_space;
+	initOverlayElement(&mTestGeometryForVisibleLeavesInfo, ext, 
+		"TestGeometryForVisibleLeaves", top, ": true"); top += vert_space;
+	initOverlayElement(&mUseDepthPassInfo, ext, "UseDepthPass", top, ": false"); top += vert_space;
+	initOverlayElement(&mAssumedVisibilityInfo, ext, "AssumedVisibility", top, ": 0"); top += vert_space;
+	initOverlayElement(&mCurrentObjectTypeInfo, ext, "CurrentObjectType", top, ": "); top += vert_space;
+	initOverlayElement(&mUseArbQueriesInfo, ext, "UseArbQueries", top, ": NV"); top += vert_space;
+	//initOverlayElement(&mHelpInfo, ext, "Help", top, ": "); top += vert_space;
+
+	OverlayElement *optionsPanel = OverlayManager::getSingleton().
+		getOverlayElement("Example/Visibility/VisibilityPanel");
+
+	optionsPanel->setHeight(top + border_height);
+
+	top = border_height;
+	//ext = "Example/Visibility/";
+	initOverlayElement(&mFrustumCulledNodesInfo, ext, "FrustumCulledNodes", top, ": 0"); top += vert_space;
+	initOverlayElement(&mQueryCulledNodesInfo, ext, "QueryCulledNodes", top, ": 0"); top += vert_space;
+	initOverlayElement(&mTraversedNodesInfo, ext, "TraversedNodes", top, ": 0"); top += vert_space;
+	initOverlayElement(&mHierarchyNodesInfo, ext, "HierarchyNodes", top, ": 0"); top += vert_space;
+	initOverlayElement(&mRenderedNodesInfo, ext, "RenderedNodes", top, ": 0"); top += vert_space;
+	initOverlayElement(&mObjectsCountInfo, ext, "ObjectsCount", top, ": 0"); top += vert_space;
+	initOverlayElement(&mQueriesIssuedInfo, ext, "QueriesIssued", top, ": 0"); top += vert_space;
+
+	OverlayElement *visPanel = OverlayManager::getSingleton().
+		getOverlayElement("Example/Visibility/VisibilityStatsPanel");
+
+	visPanel->setHeight(top + border_height);
+}
+//-----------------------------------------------------------------------
+void TerrainFrameListener::initQueryOverlay()
+{
+	const int border_height = 10;
+	const int vert_space = 15;
+
+	//-- visibility culling stats overlay
+	int top = border_height + 25;
+
+	String ext = "Example/Visibility/Query/";
+	    
+	initOverlayElement(&mQueryTypeInfo , ext, "QueryType", top,	": 0"); top += vert_space;
+	
+	initOverlayElement(&mQueryVisibleNodesInfo , ext, "VisibleNodes", top,	": 0"); top += vert_space;
+	initOverlayElement(&mQueryVisibleGeometryInfo , ext, "VisibleGeometry", top,	": 0"); top += vert_space;
+	initOverlayElement(&mQueryVisiblePatchInfo , ext, "VisiblePatches", top,	": 0"); top += vert_space;
+	
+	initOverlayElement(&mQueryNodeVisibilityInfo , ext, "NodeVisibility", top,	": 0"); top += vert_space;
+	initOverlayElement(&mQueryGeometryVisibilityInfo , ext, "GeometryVisibility", top,	": 0"); top += vert_space;
+	initOverlayElement(&mQueryPatchVisibilityInfo , ext, "PatchVisibility", top,	": 0"); top += vert_space;
+
+
+	OverlayElement *queryPanel = OverlayManager::getSingleton().
+		getOverlayElement("Example/Visibility/Query/QueryPanel");
+
+	queryPanel->setHeight(top + border_height);
+}
Index: /GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TestCullingTerrainApplication.cpp
===================================================================
--- /GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TestCullingTerrainApplication.cpp	(revision 639)
+++ /GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TestCullingTerrainApplication.cpp	(revision 639)
@@ -0,0 +1,470 @@
+#include <OgreNoMemoryMacros.h>
+#include <CEGUI/CEGUI.h>
+#include <../CEGUIRenderer/include/OgreCEGUIRenderer.h>
+#include <../CEGUIRenderer/include/OgreCEGUIResourceProvider.h>
+#include <../CEGUIRenderer/include/OgreCEGUITexture.h>
+#include <OgreMemoryMacros.h>
+
+#include <Ogre.h>
+
+//#include "OgreReferenceAppLayer.h"
+//#include "OgreRefAppWorld.h"
+#include "TestCullingTerrainApplication.h"
+#include "TerrainFrameListener.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+
+/**********************************************/
+/*             EntityState implementation     */
+/**********************************************/
+
+
+Vector3 EntityState::msMinPos = Vector3::ZERO;
+Vector3 EntityState::msMaxPos = Vector3::ZERO;
+
+EntityState::EntityState(Entity *ent, State entityState, Real speed):
+mEntity(ent), mState(entityState), mAnimationSpeed(speed)
+{
+	switch(entityState)
+	{
+	case MOVING:
+		mAnimationState = mEntity->getAnimationState("Walk");
+		break;
+	case WAITING:
+		mAnimationState = mEntity->getAnimationState("Idle");
+		break;
+	case STOP:
+		mAnimationState = NULL;
+		break;
+	default:
+		break;
+	}
+	// enable animation state
+	if (mAnimationState)
+	{
+		mAnimationState->setLoop(true);
+		mAnimationState->setEnabled(true);
+	}
+	mTimeElapsed = Math::RangeRandom(1, 5);
+}
+//-----------------------------------------------------------------------
+EntityState::~EntityState()
+{
+	mAnimationState = NULL;
+	mEntity = NULL;
+}
+//-----------------------------------------------------------------------
+Entity *EntityState::GetEntity()
+{
+	return mEntity;
+}
+//-----------------------------------------------------------------------
+EntityState::State EntityState::GetState()
+{
+	return mState;
+}
+//-----------------------------------------------------------------------
+void EntityState::update(Real timeSinceLastFrame)
+{
+	mTimeElapsed -= timeSinceLastFrame * mAnimationSpeed;
+
+	if (!mEntity || !mAnimationState)
+		return;
+	
+	if (mState == MOVING) // toggle between moving (longer) and waiting (short)
+	{
+		SceneNode *parent = mEntity->getParentSceneNode();
+		
+		if (!parent)
+			return;
+
+		if (mTimeElapsed <= 0) // toggle animation state
+		{
+			if (mAnimationState->getAnimationName() == "Idle")
+			{
+				SetAnimationState("Walk", true);
+				
+				mTimeElapsed = walk_duration; // walk for mTimeElapsed units
+
+				// choose random rotation
+				Radian rnd = Radian(Math::UnitRandom() * Math::PI * rotate_factor);
+
+				//mEntity->getParentSceneNode()->rotate();
+				parent->yaw(rnd);						
+			}
+			else 
+			{
+				SetAnimationState("Idle", true);
+				mTimeElapsed = wait_duration; // wait for mTimeElapsed seconds
+			}
+		}
+
+		if (mAnimationState->getAnimationName() == "Walk") // move forward
+		{
+			// store old position, just in case we get out of bounds
+			Vector3 oldPos = parent->getPosition();
+			parent->translate(parent->getLocalAxes(), Vector3(move_factor * mAnimationSpeed, 0, 0));
+
+			// HACK: if out of bounds => reset to old position and set animationstate to idle
+			if (OutOfBounds(parent)) 
+			{
+				parent->setPosition(oldPos);
+				SetAnimationState("Idle", true);
+				
+				mTimeElapsed = wait_duration;
+			}
+		}
+	}
+		
+	// add time to drive animation
+	mAnimationState->addTime(timeSinceLastFrame * mAnimationSpeed);
+}
+//-----------------------------------------------------------------------
+void EntityState::SetAnimationState(String stateStr, bool loop)
+{
+	if (!mEntity)
+		return;
+
+	mAnimationState = mEntity->getAnimationState(stateStr);
+	mAnimationState->setLoop(loop);
+	mAnimationState->setEnabled(true);
+}
+//-----------------------------------------------------------------------
+bool EntityState::OutOfBounds(SceneNode *node)
+{
+	Vector3 pos = node->getPosition();
+
+	if ((pos > msMinPos) && (pos < msMaxPos))
+		return false;
+
+	return true;
+}
+
+
+
+/*********************************************************/
+/*      TestCullingTerrainApplication implementation     */
+/*********************************************************/
+
+
+TestCullingTerrainApplication::TestCullingTerrainApplication():
+mTerrainContentGenerator(NULL), mRayQueryExecutor(NULL)
+{
+}
+//-----------------------------------------------------------------------
+TestCullingTerrainApplication::~TestCullingTerrainApplication()
+{
+	OGRE_DELETE(mTerrainContentGenerator);
+	OGRE_DELETE(mRayQueryExecutor);
+
+	deleteEntityStates();
+}
+//-----------------------------------------------------------------------
+void TestCullingTerrainApplication::deleteEntityStates()
+{
+	for (int i = 0; i < (int)mEntityStates.size(); ++i)
+	{
+		OGRE_DELETE(mEntityStates[i]);
+	}
+
+	mEntityStates.clear();
+}
+//-----------------------------------------------------------------------
+void TestCullingTerrainApplication::createCamera()
+{
+	// create the camera
+	mCamera = mSceneMgr->createCamera("PlayerCam");
+	
+	/** set a nice viewpoint
+	*	we use a camera node here and apply all transformations on it instead
+	*	of applying all transformations directly to the camera
+	*	because then the camera is displayed correctly in the visualization
+	*/
+	mCamNode = mSceneMgr->getRootSceneNode()->
+		createChildSceneNode("CamNode1", Vector3(707, 5000, 528));
+	//mCamera->setPosition(707, 5000, 528);
+	mCamNode->setOrientation(Quaternion(-0.3486, 0.0122, 0.9365, 0.0329));
+	mCamNode->attachObject(mCamera);
+
+	//-- create visualization camera
+	mVizCamera = mSceneMgr->createCamera("VizCam");
+	mVizCamera->setPosition(mCamNode->getPosition());
+
+	mVizCamera->setNearClipDistance(1);
+	mCamera->setNearClipDistance(1);
+
+	// infinite far plane?
+	if (mRoot->getRenderSystem()->getCapabilities()->hasCapability(RSC_INFINITE_FAR_PLANE))
+	{
+		mVizCamera->setFarClipDistance(0);
+		mCamera->setFarClipDistance(0);
+	}
+	else
+	{
+		 mVizCamera->setFarClipDistance(20000);
+		 mCamera->setFarClipDistance(20000);
+	}	
+}
+
+//-----------------------------------------------------------------------
+bool TestCullingTerrainApplication::setup()
+{
+	bool carryOn = ExampleApplication::setup();
+
+	if (carryOn)
+		createRenderTargetListener();
+
+	return carryOn;
+}
+//-----------------------------------------------------------------------
+void TestCullingTerrainApplication::createRenderTargetListener()
+{
+	mWindow->addListener(new VisualizationRenderTargetListener(mSceneMgr));
+}
+//-----------------------------------------------------------------------
+void TestCullingTerrainApplication::createScene()
+{
+	Real scale = 3;
+	mSceneMgr->setOption("NodeVizScale", &scale);
+
+	// Set ambient light
+	mAmbientLight = ColourValue(0.5, 0.5, 0.5);
+	mSceneMgr->setAmbientLight(mAmbientLight);
+	
+	//-- create light
+	mSunLight = mSceneMgr->createLight("SunLight");
+	mSunLight->setType(Light::LT_DIRECTIONAL);
+	//mSunLight->setType(Light::LT_SPOTLIGHT);
+	//mSunLight->setSpotlightRange(Degree(30), Degree(50));
+
+    mSunLight->setPosition(707, 2000, 500);
+	mSunLight->setCastShadows(true);
+
+	// set light angle not too small over the surface, otherwise shadows textures will be broken
+	Vector3 dir(0.5, 1, 0.5);
+	dir.normalise();
+	mSunLight->setDirection(dir);
+	//mSunLight->setDirection(Vector3::NEGATIVE_UNIT_Y);
+	mSunLight->setDiffuseColour(1, 1, 1);
+	mSunLight->setSpecularColour(1, 1, 1);
+
+	// -- Fog
+	// NB it's VERY important to set this before calling setWorldGeometry 
+	// because the vertex program picked will be different
+	ColourValue fadeColour(0.93, 0.86, 0.76);
+	mWindow->getViewport(0)->setBackgroundColour(fadeColour);
+	//mSceneMgr->setFog( FOG_LINEAR, fadeColour, .001, 500, 1000);
+	
+	// Create a skybox
+	mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox", 5000, true);
+	
+	std::string terrain_cfg("terrain.cfg");
+#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
+	terrain_cfg = mResourcePath + terrain_cfg;
+#endif
+	mSceneMgr->setWorldGeometry(terrain_cfg);
+	
+
+	//-- CEGUI setup
+	setupGui();
+
+	/* // occluder plane to test visibility
+	Plane plane; plane.normal = Vector3::UNIT_Y;	plane.d = -60;
+	MeshManager::getSingleton().createPlane("Myplane",
+		ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane,
+		5000,5000,100,100,true,1,5,5,Vector3::UNIT_Z);
+	Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
+	pPlaneEnt->setMaterialName("Examples/Rockwall");
+	pPlaneEnt->setCastShadows(true);
+	mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);	*/
+
+	// Use 512x512 texture in GL since we can't go higher than the window res
+	mSceneMgr->setShadowTextureSettings(512, 2);
+
+	mSceneMgr->setShadowColour(ColourValue(0.5, 0.5, 0.5));
+   
+
+	//-- terrain content setup
+
+	// HACK: necessary to call once before the content creation for
+	// terrain initialisation
+	mSceneMgr->_renderScene(mCamera, mWindow->getViewport(0), true);
+
+	// ray query executor: needed to clamp to terrain
+	mRayQueryExecutor = new RayQueryExecutor(mSceneMgr);
+
+	mTerrainMinPos = EntityState::msMinPos = Vector3(0, 0, 0);
+	mTerrainMaxPos = EntityState::msMaxPos = Vector3(5000, 5000, 5000);
+
+	mTerrainContentGenerator = new TerrainContentGenerator(mSceneMgr);
+	
+	// if no objects in file, we generate new objects
+	if (!mTerrainContentGenerator->LoadObjects("objects.out"))
+	{
+		// the objects are generated randomly distributed over the terrain
+		generateScene(1000, 0); // create soldiers, trees, ninjas
+		generateScene(500, 1);
+		generateScene(100, 2);
+	}
+}
+//-----------------------------------------------------------------------
+void  TestCullingTerrainApplication::generateScene(int num, int objectType)
+{
+	float val = TerrainFrameListener::msObjectScales[objectType];
+	Vector3 scale(val, val, val); 
+	const float maxHeight = 75;
+	
+	// In order to provide much occlusion,
+	// height is restricted to maxHeight => no objects are created on peaks
+	mTerrainContentGenerator->SetMinPos(Vector3(mTerrainMinPos));
+	mTerrainContentGenerator->SetMaxPos(Vector3(mTerrainMaxPos.x, maxHeight, mTerrainMaxPos.z));
+	
+	//std::stringstream d; d << "objscale: " << scale[0];
+	//Ogre::LogManager::getSingleton().logMessage(d.str());
+	
+	mTerrainContentGenerator->SetScale(scale);
+	mTerrainContentGenerator->SetOffset(TerrainFrameListener::msObjectTerrainOffsets[objectType]);
+	mTerrainContentGenerator->GenerateScene(num, TerrainFrameListener::msObjectCaptions[objectType]);
+
+	if (objectType != 0) // from our objects, only robot has animation phases
+		return;
+
+	EntityList *entList = mTerrainContentGenerator->GetGeneratedEntities();
+
+	//-- add animation state for new robots (located at the end of the list)
+	for (int i = (int)entList->size() - num; i < (int)entList->size(); ++i)
+	{
+		mEntityStates.push_back(new EntityState((*entList)[i], 
+			EntityState::WAITING, Math::RangeRandom(0.5, 1.5)));
+	}
+
+	// release limitations on height => it is possible for the user to put single 
+	// objects on peaks of the terrain (will be only few, not relevant for occlusion)
+	mTerrainContentGenerator->SetMaxPos(mTerrainMaxPos);
+}
+//-----------------------------------------------------------------------
+void TestCullingTerrainApplication::updateAnimations(Real timeSinceLastFrame)
+{
+	for (int i = 0; i < (int)mEntityStates.size(); ++i)
+	{
+		SceneNode *sn = mEntityStates[i]->GetEntity()->getParentSceneNode();
+
+		mEntityStates[i]->update(timeSinceLastFrame);
+
+		if (mEntityStates[i]->GetState() == EntityState::MOVING)
+		{
+			Clamp2Terrain(sn, 0); //sn->setNodeVisible(false);
+		}
+	}
+}
+//-----------------------------------------------------------------------
+EntityStates  &TestCullingTerrainApplication::getEntityStates()
+{
+	return mEntityStates;
+}
+//-----------------------------------------------------------------------
+void TestCullingTerrainApplication::setupGui()
+{
+	 mGUIRenderer = new CEGUI::OgreCEGUIRenderer(mWindow, Ogre::RENDER_QUEUE_OVERLAY, 
+		 false, 3000, ST_EXTERIOR_CLOSE);
+     mGUISystem = new CEGUI::System(mGUIRenderer);
+
+	 // Mouse
+     CEGUI::SchemeManager::getSingleton().loadScheme((CEGUI::utf8*)"TaharezLook.scheme");
+     CEGUI::MouseCursor::getSingleton().setImage("TaharezLook", "MouseArrow");
+	 mGUISystem->setDefaultMouseCursor((CEGUI::utf8*)"TaharezLook", 
+									   (CEGUI::utf8*)"MouseArrow");
+
+	 CEGUI::MouseCursor::getSingleton().hide();
+}
+//-----------------------------------------------------------------------
+void TestCullingTerrainApplication::createFrameListener()
+{
+	mTerrainFrameListener = new TerrainFrameListener(mWindow, mCamera, mSceneMgr, 
+		mGUIRenderer, mTerrainContentGenerator, mVizCamera, mCamNode, mSunLight, this);
+	
+	mRoot->addFrameListener(mTerrainFrameListener);
+}
+//-----------------------------------------------------------------------
+void TestCullingTerrainApplication::chooseSceneManager()
+{
+	mSceneMgr = mRoot->getSceneManager(ST_EXTERIOR_CLOSE);
+}
+//-----------------------------------------------------------------------
+bool TestCullingTerrainApplication::Clamp2Terrain(SceneNode *node, int terrainOffs)
+{
+	// clamp scene node to terrain
+	Vector3 pos = node->getPosition();
+	Vector3 queryResult;
+
+	if (mRayQueryExecutor->executeRayQuery(&queryResult, 
+			Vector3(pos.x, MAX_HEIGHT, pos.z), Vector3::NEGATIVE_UNIT_Y))
+	{
+        node->setPosition(pos.x, queryResult.y + terrainOffs, pos.z);
+		return true;
+	}
+
+	return false;
+}
+
+
+/**************************************************************/
+/*      VisualizationRenderTargetListener implementation      */
+/**************************************************************/
+//-----------------------------------------------------------------------
+VisualizationRenderTargetListener::VisualizationRenderTargetListener(SceneManager *sceneMgr)
+:RenderTargetListener(), mSceneMgr(sceneMgr)
+{
+}
+//-----------------------------------------------------------------------
+void VisualizationRenderTargetListener::preViewportUpdate(const RenderTargetViewportEvent &evt)
+{
+	// visualization viewport
+	const bool showViz = evt.source->getZOrder() == VIZ_VIEWPORT_Z_ORDER;
+	const bool nShowViz = !showViz;
+
+	mSavedShadowTechnique = mSceneMgr->getShadowTechnique();
+	mSavedAmbientLight = mSceneMgr->getAmbientLight();
+
+	// -- ambient light must be full for visualization, shadows disabled
+    if (showViz)
+	{
+		mSceneMgr->setAmbientLight(ColourValue(1, 1, 1));
+		mSceneMgr->setShadowTechnique(SHADOWTYPE_NONE);
+	}
+	
+    mSceneMgr->setOption("PrepareVisualization", &showViz);
+	mSceneMgr->setOption("SkyBoxEnabled", &nShowViz);
+	//mSceneMgr->setOption("SkyPlaneEnabled", &showViz);
+	
+	RenderTargetListener::preViewportUpdate(evt);
+}
+//-----------------------------------------------------------------------
+void VisualizationRenderTargetListener::postRenderTargetUpdate(const RenderTargetEvent &evt)
+{
+	// reset values
+	mSceneMgr->setShadowTechnique(mSavedShadowTechnique);
+	mSceneMgr->setAmbientLight(mSavedAmbientLight);
+	
+	RenderTargetListener::postRenderTargetUpdate(evt);
+}
+//-----------------------------------------------------------------------
+INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
+{
+    // Create application object
+    TestCullingTerrainApplication app;
+
+	try 
+	{
+        app.go();
+    } 
+	catch( Ogre::Exception& e ) 
+	{
+        MessageBox( NULL, e.getFullDescription().c_str(), 
+			"An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
+    }	
+
+    return 0;
+}
Index: /GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TerrainFrameListener.h
===================================================================
--- /GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TerrainFrameListener.h	(revision 639)
+++ /GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TerrainFrameListener.h	(revision 639)
@@ -0,0 +1,411 @@
+#ifndef _TerrainFrameListener_H__
+#define _TerrainFrameListener_H__
+
+#include "CEGUIForwardRefs.h"
+#include <Ogre.h>
+#include <OgreKeyEvent.h>
+#include <OgreEventListeners.h>
+#include <OgreStringConverter.h>
+#include <OgreException.h>
+#include "VisibilityEnvironment.h"
+#include "VisibilityManager.h"
+#include "OgreTerrainContentGenerator.h"
+#include "OgrePlatformQueryManager.h"
+
+
+class TestCullingTerrainApplication;
+
+
+using namespace Ogre;
+
+/** Struct storing walktrough statistics
+*/
+struct WalkthroughStats
+{
+public:
+
+	unsigned long mAccFps;
+	unsigned long mBestFps;
+	unsigned long mWorstFps;
+	unsigned long mAccTris;
+	unsigned long mAccQueryCulledNodes;
+	unsigned long mAccFrustumCulledNodes;
+	unsigned long mFrameCount;
+	unsigned long mAccRenderedNodes;
+	
+	WalkthroughStats(): 
+	mAccFps(0), mBestFps(0), mWorstFps(0), mAccTris(0),
+	mAccQueryCulledNodes(0), mAccFrustumCulledNodes(0),
+	mFrameCount(0), mAccRenderedNodes(0)
+	{}
+
+	void Reset()
+	{
+		mAccFps = mBestFps = mWorstFps = mAccTris = mAccQueryCulledNodes = mAccFrustumCulledNodes = mFrameCount = mAccRenderedNodes = 0;
+	}
+
+	void UpdateFrame(int currentFps, int bestFps, int worstFps, int renderedTris, int renderedNodes, int queryCulledNodes, int frustumCulledNodes)
+	{
+		mAccFps += currentFps;
+		mBestFps = bestFps;
+		mWorstFps = worstFps;
+
+		// accumulated #triangles (M)
+		mAccTris += renderedTris / 1000;
+		mAccRenderedNodes += renderedNodes;
+		mAccQueryCulledNodes += queryCulledNodes;
+		mAccFrustumCulledNodes += frustumCulledNodes;
+	
+		++ mFrameCount;
+	}
+
+	void Print(std::ostream &d, const std::string &algorithmName) const
+	{
+		// compuate average fps and triangle count
+		float avgFps = (float)mAccFps / (float)mFrameCount;
+		float avgTris = (float)mAccTris / (float)mFrameCount;
+		float avgFrustumCulledNodes = 0;
+		float avgRenderedNodes = 0;
+		float avgQueryCulledNodes = 0;
+		
+		if (mFrameCount != 0)
+		{
+			avgFrustumCulledNodes = (float)mAccFrustumCulledNodes / (float)mFrameCount;
+			avgQueryCulledNodes  = (float)mAccQueryCulledNodes / (float)mFrameCount;
+			avgRenderedNodes = (float)mAccRenderedNodes / (float) mFrameCount;
+		}
+
+		//-- write out stats for recorded walkthrough
+		d << "Algorithm: " << algorithmName << "\n"
+			<< "avg. FPS: " << avgFps << "\n"
+			<< "best FPS: " << mBestFps << "\n"
+			<< "worst FPS: " << mWorstFps << "\n"
+			<< "avg. #triangles: " << avgTris << " M\n"
+			<< "#frames: " << mFrameCount << "\n"
+			<< "avg. #query culled nodes: " << avgFrustumCulledNodes << "\n"
+			<< "avg. #frustum culled nodes: " << avgQueryCulledNodes << "\n"
+			<< "avg. #rendered nodes: " << avgRenderedNodes << "\n";
+	}
+
+};
+
+/** Frame listener specialised for terrains.
+*/
+class TerrainFrameListener: public FrameListener, public MouseListener, 
+							public MouseMotionListener, public KeyListener
+{
+public:
+	
+   TerrainFrameListener(RenderWindow* win, 
+						Camera* cam, 
+						SceneManager *sceneManager, 
+						CEGUI::Renderer *renderer, 
+						TerrainContentGenerator *contentGenerator, 
+						Camera *vizCamera,
+						SceneNode *camNode, 
+						Light *sunLight,
+						TestCullingTerrainApplication *app);
+
+   ~TerrainFrameListener();
+
+   bool frameStarted(const FrameEvent& evt);
+   bool frameEnded(const FrameEvent& evt);
+     
+
+   /* MouseListener callbacks. */
+   virtual void mouseClicked(MouseEvent* e) { }
+   virtual void mouseEntered(MouseEvent* e) { }
+   virtual void mouseExited(MouseEvent* e)  { }
+
+   // This is when the mouse button goes DOWN.
+   void mousePressed(MouseEvent* e);
+
+   // This is when the mouse button is let UP.
+   void mouseReleased(MouseEvent* e);
+
+   /* MouseMotionListener callbacks */
+   void mouseMoved(MouseEvent *e);
+   
+   // This is when the mouse is clicked, held and dragged.
+   void mouseDragged(MouseEvent *e);
+
+   void mouseDragDropped(MouseEvent *e);
+   void keyPressed(KeyEvent* e);
+
+   void keyReleased(KeyEvent* e);
+   void keyClicked(KeyEvent* e);
+  
+   /** The information about camera position and orienation per frame.
+   */
+   typedef struct
+   {
+	   Vector3 position;
+	   Quaternion orientation;
+	   Real timeElapsed;
+	   Real fps;
+   } frame_info;
+
+   typedef std::vector<frame_info> FrameInfoContainer;
+
+   enum  {WALKTHROUGH, REPLAY, STATE_NUM};
+
+   // visualization modes for scene nodes
+   enum {NODEVIZ_NONE, NODEVIZ_RENDER_NODES, NODEVIZ_RENDER_NODES_AND_CONTENT, NODEVIZ_MODES_NUM};
+   //enum {NODEVIZ_NONE, NODEVIZ_RENDER_GEOMETRY, NODEVIZ_MODES_NUM};
+
+   void zoomVizCamera(int zoom);
+	
+   void addFrameInfo(FrameInfoContainer &frameInfos, SceneNode *camNode, Real timeElapsed);
+   void setCurrentFrameInfo(Real timeElapsed);
+
+   void setAlgorithm(int algorithm);
+
+   void moveCamera();
+
+   void writeFrames();
+   void loadFrames();
+
+	// quick hack
+	void writeNewFrameInfo();
+    
+    bool processUnbufferedKeyInput(const FrameEvent& evt);
+    bool processUnbufferedMouseInput(const FrameEvent& evt);
+
+	void switchMouseMode() 
+	{
+        mUseBufferedInputMouse = !mUseBufferedInputMouse;
+		mInputDevice->setBufferedInput(true, mUseBufferedInputMouse);
+
+		if (!mUseBufferedInputMouse)
+			CEGUI::MouseCursor::getSingleton().hide();
+		else
+			CEGUI::MouseCursor::getSingleton().show();
+	}
+
+	/** Shows the frame / algorithm statistics.
+	*/ 
+    void showStats(bool show);
+
+	/** Updates frame statistics and the frame statistics display.
+	*/
+	void updateStats();
+
+	/** Toggles wether help screen is shown or not.
+	*/
+	void toggleShowHelp();
+	
+	/** Toggles wether shadows are shown or not.
+	*/
+	void toggleShowShadows();
+	void toggleDisplayCameraDetails();
+	/** Takes screenshot of the current scene.
+	*/
+	void takeScreenshot();
+	/** Takes one video frame.
+	*/
+	void takeVideoFrame(std::ofstream &ofstr);
+
+	void nextSceneDetailLevel();
+	void nextFilter();
+	void nextAlgorithm();
+	void nextNodeVizMode();
+	void nextAppState();
+    void changeThreshold(int incr);
+	void changeAssumedVisibility(int incr);
+	void setTestGeometryForVisibleLeaves(bool testGeometryForVisibleLeaves);
+	/** Shows octree hierarchy of the scene.
+	*/
+	void toggleShowOctree();
+	/** Toggles wether we use the initial depth pass.
+	*/
+	void toggleUseDepthPass();
+	/** Toggles wether we use ARB or NV queries.
+	*/
+	void toggleUseArbQueries();
+	/** Toggles wether the visualization is shown.
+	*/
+	void toggleShowViz();
+	/** Toggles wether the frames are recorded.
+	*/
+	void toggleRecord();
+
+	/** Applies visibility query. Collects the visible objects 
+		and their visibility information.
+		@param fromPoint if query should be from point or from camera
+		@param relativeVisibility if query should return number of visible pixels or 
+		the ratio visible / projected pixels.
+		@param useItemBuffer if item buffer should be used or occlusion queries
+	*/
+	void applyVisibilityQuery(bool fromPoint, bool relativeVisibility, bool useItemBuffer);
+
+	/** Shows result from visibility queries.
+	*/
+	void toggleShowQueryStats();
+
+	/** Sets the type of the objects generated in the scene.
+	*/
+	void setObjectType(int objectType);
+
+	static String msAlgorithmCaptions[];
+	static String msQueryTypeCaptions[]; 
+	static String msQueryRelativeVisCaptions[];
+	static String msQueryMethodCaptions[];
+	static Real msObjectTerrainOffsets[]; 
+	static Real msObjectScales[];
+	static String msObjectCaptions[];
+
+protected:
+
+	void initHelpOverlayElement(String name, int top);
+	void initOverlayElement(OverlayElement **elInfo, String ext, String name, 
+							int top, String caption);
+
+	//-- initialise overlays
+	void initHelpOverlay();
+	void initVisStatsOverlay();
+	void initQueryOverlay();
+	
+	SceneManager *mSceneMgr;           // A pointer to the scene manager
+    
+	CEGUI::Renderer *mGUIRenderer;     // cegui renderer
+	
+	int mCurrentAlgorithm;
+	int mVisibilityThreshold;
+	int mAssumedVisibility;
+	/// the current frame number
+	int mCurrentFrame;
+	/// the current application state
+	int mAppState;
+	/// The number of objects on the screen
+	int mObjectCount;            
+	/// visualization mode
+	int mNodeVizMode;
+	/// number of video frames
+	int mNumVideoFrames;
+	/// the newly created object
+	SceneNode *mCurrentObject;    
+
+	WalkthroughStats mWalkthroughStats;
+
+	/// HACK for demo
+	float mDemoFps;
+	bool mUseDemoFps;
+
+	OverlayElement *mAlgorithmInfo;
+	OverlayElement *mThresholdInfo;
+	OverlayElement *mAssumedVisibilityInfo;
+	OverlayElement *mFrustumCulledNodesInfo;
+	OverlayElement *mQueryCulledNodesInfo;
+    OverlayElement *mTraversedNodesInfo;
+	OverlayElement *mHierarchyNodesInfo;
+	OverlayElement *mTestGeometryForVisibleLeavesInfo;
+	OverlayElement *mUseDepthPassInfo;
+	OverlayElement *mUseArbQueriesInfo;
+	OverlayElement *mRenderedNodesInfo;
+	OverlayElement *mObjectsCountInfo;
+	OverlayElement *mQueriesIssuedInfo;
+	OverlayElement *mDelayedQueriesIssuedInfo;
+	OverlayElement *mDelayedTraversedNodesInfo;
+	OverlayElement *mCurrentObjectTypeInfo;
+
+	OverlayElement *mQueryTypeInfo;
+	OverlayElement *mQueryVisibleNodesInfo;
+	OverlayElement *mQueryVisibleGeometryInfo;
+	OverlayElement *mQueryVisiblePatchInfo;
+
+	OverlayElement *mQueryVisiblityInfo;
+	OverlayElement *mQueryNodeVisibilityInfo;
+	OverlayElement *mQueryGeometryVisibilityInfo;
+	OverlayElement *mQueryPatchVisibilityInfo;
+	//OverlayElement *mHelpInfo;
+
+	RayQueryExecutor *mRayQueryExecutor;
+	TerrainContentGenerator *mTerrainContentGenerator;
+
+	bool mTestGeometryForVisibleLeaves;
+	bool mShowOctree;
+	bool mUseDepthPass;
+	bool mUseArbQueries;
+	bool mShowVisualization;
+	bool mCullCamera;
+	bool mRecordFrames;
+	bool mShowShadows;
+	bool mVisualizeCulledNodes;
+	bool mShowHelp;
+	bool mStatsOn;
+	bool mLMouseDown, mRMouseDown;     // True if the mouse buttons are down
+	bool mShutdownRequested;
+	bool mDisplayCameraDetails;
+	bool mUseItemBuffer;
+	bool mUseAnimation;
+	
+	int mItemBufferMode;
+
+	Real mVizCameraHeight;
+
+	Camera *mVizCamera;
+	SceneNode *mCamNode;
+	
+	/// Per frame data stored for a walkthrough
+	FrameInfoContainer mFrameInfo;
+	/// HACK: for demo
+	FrameInfoContainer mSavedFrameInfo;
+	
+	Real mReplayTimeElapsed;
+	//EventProcessor* mEventProcessor;
+    InputReader* mInputDevice;
+    Camera* mCamera;
+
+    Vector3 mTranslateVector;
+    RenderWindow* mWindow;
+   
+	unsigned int mNumScreenShots;
+    int mSceneDetailIndex;
+	int mAniso;
+
+	float mMoveScale;
+    Degree mRotScale;
+
+    // just to stop toggles flipping too fast
+    Real mTimeDelay;
+    Radian mRotX, mRotY;
+    TextureFilterOptions mFiltering;
+  
+	Real mMoveSpeed;
+    Degree mRotateSpeed;
+    
+	Overlay* mDebugOverlay;
+	Overlay* mHelpOverlay;
+	Overlay* mCullStatsOverlay;
+	Overlay* mQueryOverlay;
+
+	Light *mSunLight;
+	GtpVisibility::VisibilityManager *mVisibilityManager;
+	EventProcessor* mEventProcessor;
+	
+	bool mShiftPressed;
+	bool mShowQueryStats;
+	
+	//bool mUseBufferedInputKeys, mUseBufferedInputMouse, mInputTypeSwitchingOn;
+	PlatformQueryManager *mQueryManager;
+
+	float mDelayedQueriesIssued;
+	float mDelayedTraversedNodes;
+
+	int mCurrentObjectType;
+
+	bool mDeleteObjects;
+	bool mRecordVideo;
+
+	Timer *mTimer;
+	long mTimeFrameEnded;
+	long mTimeFrameStarted;
+	float mPureRenderTimeFps;
+	TestCullingTerrainApplication *mApplication;
+
+	bool mUseBufferedInputMouse;
+	Matrix4 rotMatrix;
+};
+
+
+#endif //_TerrainFrameListener_H__
Index: /GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TestCullingTerrainApplication.dsp
===================================================================
--- /GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TestCullingTerrainApplication.dsp	(revision 639)
+++ /GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TestCullingTerrainApplication.dsp	(revision 639)
@@ -0,0 +1,109 @@
+# Microsoft Developer Studio Project File - Name="Demo_TestCullingTerrainApplication" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=Demo_TestCullingTerrainApplication - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "TestCullingTerrainApplication.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "TestCullingTerrainApplication.mak" CFG="Demo_TestCullingTerrainApplication - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "Demo_TestCullingTerrainApplication - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "Demo_TestCullingTerrainApplication - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "Demo_TestCullingTerrainApplication - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "..\bin\Release"
+# PROP BASE Intermediate_Dir "..\obj\Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\bin\Release"
+# PROP Intermediate_Dir "..\obj\Release"
+# PROP Ignore_Export_Lib 1
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /Zi /Od /I "." /I "$(OGRE_PATH)\OgreMain\include" /I "$(OGRE_PATH)\Samples/Common/include" /D "NDEBUG" /D "_MBCS" /D "_WINDOWS" /D "WIN32" /YX /FD /Zm1000 /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib OgreMain.lib /nologo /subsystem:windows /machine:I386 /out:"$(OGRE_PATH)\Samples\Common\Bin\Release\Demo_TestCullingTerrainApplication.exe" /libpath:"$(OGRE_PATH)\OgreMain\lib\release" 
+# SUBTRACT LINK32 /profile /debug
+
+!ELSEIF  "$(CFG)" == "Demo_TestCullingTerrainApplication - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "..\bin\Debug"
+# PROP BASE Intermediate_Dir "..\obj\Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\bin\Debug"
+# PROP Intermediate_Dir "..\obj\Debug"
+# PROP Ignore_Export_Lib 1
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "." /I "$(OGRE_PATH)\OgreMain\include" /I "$(OGRE_PATH)\Samples/Common/include" /D "_MBCS" /D "_WINDOWS" /D "_DEBUG" /D "WIN32" /FD /GZ /Zm1000 /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib OgreMain_d.lib /nologo /subsystem:windows /debug /machine:I386 /nodefaultlib:"LIBCMT" /out:"$(OGRE_PATH)\Samples\Common\Bin\Debug\Demo_TestCullingTerrainApplication.exe" /pdbtype:sept /libpath:"$(OGRE_PATH)\OgreMain\lib\debug" 
+# SUBTRACT LINK32 /verbose
+
+!ENDIF 
+
+# Begin Target
+
+# Name "Demo_TestCullingTerrainApplication - Win32 Release"
+# Name "Demo_TestCullingTerrainApplication - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=TestCullingTerrainApplication.cpp
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
Index: /GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TestCullingTerrainApplication.h
===================================================================
--- /GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TestCullingTerrainApplication.h	(revision 639)
+++ /GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TestCullingTerrainApplication.h	(revision 639)
@@ -0,0 +1,163 @@
+#ifndef _TestCullingTerrainApplication_H__
+#define _TestCullingTerrainApplication_H__
+
+#include "CEGUIForwardRefs.h"
+#include <OgreRenderTargetListener.h>
+#include "ExampleApplication.h"
+
+#include "OgreTerrainContentGenerator.h"
+#include "TerrainFrameListener.h"
+
+#include <OgreEntity.h>
+
+// z order index of visualizaion viewport
+#define VIZ_VIEWPORT_Z_ORDER 10
+
+
+//-- constants for animation
+const float walk_duration = 10.0f;
+const float wait_duration = 2.0f;
+const float rotate_factor = 0.7f;
+const float move_factor = 0.03;
+
+
+/** Rendertarget listener which shows a visualization.
+*/
+class VisualizationRenderTargetListener: public RenderTargetListener
+{
+public:
+	VisualizationRenderTargetListener(SceneManager *sceneMgr);
+
+protected:
+	void preViewportUpdate (const RenderTargetViewportEvent &evt);
+	void postRenderTargetUpdate (const RenderTargetEvent &evt);
+
+	SceneManager *mSceneMgr;
+	
+	ShadowTechnique mSavedShadowTechnique;
+	ColourValue mSavedAmbientLight;
+};
+
+/** Class storing the current state of an entity.
+*/
+class EntityState
+{
+public:
+	enum State {STOP, WAITING, MOVING};
+
+	EntityState(Entity *ent, State entityState, Real speed);
+	~EntityState();
+	/** Update the entity state.
+	*/
+	void update(Real timeSinceLastFrame);
+
+	/** Returns entity.
+	*/
+	Entity *GetEntity();
+
+	/** Returns entity state index.
+	*/
+	EntityState::State GetState();
+
+	static bool OutOfBounds(SceneNode *node);
+
+	static Vector3 msMinPos;
+	static Vector3 msMaxPos;
+
+protected:
+
+	void SetAnimationState(String stateStr, bool loop);
+
+	AnimationState *mAnimationState;
+	Entity *mEntity;
+
+	State mState;
+	Real mAnimationSpeed;
+	Real mTimeElapsed;
+};
+
+typedef std::vector<EntityState *> EntityStates;
+
+class TestCullingTerrainApplication: public ExampleApplication
+{
+public:
+	TestCullingTerrainApplication();
+	~TestCullingTerrainApplication();
+
+	/** Generates a scene using num entities of a type. 
+		@param num the number of objects
+		@parma objectType the type of objects
+	*/
+	void generateScene(int num, int objectType);
+
+	/** Returns the caption of the given id of a scene object type.
+	*/
+	String getCurrentObjectCaption(int id);
+
+	/** Returns state vector of scene entities.
+	*/
+	EntityStates &getEntityStates();
+
+	/** Updates all animations according to time elapsed since last frame.
+	*/
+    void updateAnimations(Real timeSinceLastFrame);
+
+	/** Deletes vector of scene entity states.
+	*/
+	void deleteEntityStates();
+
+	// object types
+	enum {ROBOT, ATHENA, NINJA};
+
+	
+	/** Clamps scene node to terrain.
+		@param sceneNode the node to be clamped
+		@param terrainOffs the offset of the node over the terrain
+		@returns if clamping was successful (i.e., the ray hit the terrain)
+	*/
+	bool Clamp2Terrain(SceneNode *node, int terrainOffs);
+
+protected:
+
+	//-- inherited from ExampleApplication
+	bool setup();
+	void createScene();
+	void createFrameListener();
+	void createCamera();
+	//void createViewports();
+	
+	virtual void createRenderTargetListener();
+
+	std::vector<EntityState *> mEntityStates;
+
+	/** cegui setup 
+	*/
+	void setupGui();
+
+	CEGUI::OgreCEGUIRenderer *mGUIRenderer;
+	CEGUI::System *mGUISystem;
+
+	Vector3 mMinTranslation;
+	Vector3 mMaxTranslation;
+
+	Vector3 mMinAngle;
+	Vector3 mMaxAngle;
+
+	TerrainContentGenerator *mTerrainContentGenerator;
+	
+	Camera *mVizCamera;
+	SceneNode *mCamNode;
+	Light *mSunLight;
+
+	TerrainFrameListener *mTerrainFrameListener;
+	ColourValue mAmbientLight;
+	RayQueryExecutor *mRayQueryExecutor;
+
+	Vector3 mTerrainMinPos;
+	Vector3 mTerrainMaxPos;
+
+private:
+	void chooseSceneManager(void);
+};
+
+#endif // TestCullingTerrainApplication
Index: /GTP/trunk/Lib/Vis/Preprocessing/scripts/default.env
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/scripts/default.env	(revision 612)
+++ /GTP/trunk/Lib/Vis/Preprocessing/scripts/default.env	(revision 639)
@@ -13,7 +13,7 @@
 #;../data/vienna/vienna-plane.x3d
 #	filename ../data/vienna/viewcells-25-sel.x3d
-	filename ../data/atlanta/atlanta2.x3d
+#	filename ../data/atlanta/atlanta2.x3d
 #	filename ../data/soda/soda.dat
-#	filename ../data/soda/soda5.dat
+	filename ../data/soda/soda5.dat
 }
 
@@ -25,5 +25,5 @@
 	type vss
 #	type rss
-	detectEmptyViewSpace true
+	detectEmptyViewSpace false
 }
 
@@ -36,5 +36,5 @@
 	loadInitialSamples  false
 	storeInitialSamples false
-	useViewSpaceBox true
+	useViewSpaceBox false
 #	testBeamSampling true
 }
@@ -181,5 +181,5 @@
 
 	#number of active view cells
-	active 2096
+	active 1024
 	maxStaticMemory	40
 
@@ -288,5 +288,5 @@
 VspBspTree {
 	Construction {
-		samples 300000
+		samples 500000
 		epsilon 0.005
 		randomize false
@@ -331,5 +331,5 @@
 		missTolerance		6
 		
-		maxViewCells		150000
+		maxViewCells		256
 		
 		# used for pvs criterium
@@ -344,5 +344,6 @@
 	useCostHeuristics false
 	splitUseOnlyDrivingAxis false
-	
+	usePolygonSplitIfAvailable false
+
 	Visualization {
 		# x3d visualization of the split planes
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/VspBspTree.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/VspBspTree.h	(revision 612)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/VspBspTree.h	(revision 639)
@@ -310,5 +310,12 @@
 	void CollapseViewCells();
 
+	/** Collects rays stored in the leaves.
+	*/
+	void CollectRays(VssRayContainer &rays);
+
+
 	ViewCellsTree *mViewCellsTree;
+
+
 protected:
 
@@ -502,5 +509,5 @@
 				  RayInfoContainer &rays, 
 			      RayInfoContainer &frontRays, 
-				  RayInfoContainer &backRays);
+				  RayInfoContainer &backRays) const;
 
 
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/Plane3.cpp
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/Plane3.cpp	(revision 256)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/Plane3.cpp	(revision 639)
@@ -31,2 +31,53 @@
   return true;
 }
+
+
+Vector3 Plane3::FindIntersection(const Vector3 &a,						   
+								 const Vector3 &b,
+								 float *t,
+								 bool *coplanar) const 
+{
+    const Vector3 v = b - a; // line from A to B
+    float dv = DotProd(v, mNormal);
+    
+    if (signum(dv) == 0)
+	{
+		if (coplanar) 
+			(*coplanar) = true;	
+
+		if (t) 
+			(*t) = 0;
+
+		return a;
+	}
+	
+	if (coplanar) 
+		(*coplanar) = false;
+
+    float u = - Distance(a) / dv; // TODO: could be done more efficiently
+    
+	if (t) 
+		(*t) = u;
+	
+    return a + u * v;
+}
+
+
+int Plane3::Side(const Vector3 &v, const float threshold) const 
+{
+    return signum(Distance(v), threshold);
+}
+
+
+float Plane3::FindT(const Vector3 &a, const Vector3 &b) const 
+{	  
+	const Vector3 v = b - a; // line from A to B
+	const float dv = DotProd(v, mNormal);
+    
+	// does not intersect or coincident
+
+	if (signum(dv) == 0)
+		return 0;
+	
+	return - Distance(a) / dv; // TODO: could be done more efficiently
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/VspBspTree.cpp
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/VspBspTree.cpp	(revision 612)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/VspBspTree.cpp	(revision 639)
@@ -18,4 +18,6 @@
 #include "Beam.h"
 
+#define USE_FIXEDPOINT_T 0
+
 
 //-- static members
@@ -66,5 +68,5 @@
 mViewCellsManager(NULL),
 mOutOfBoundsCell(NULL),
-mStoreRays(false),
+mStoreRays(true),
 mRenderCostWeight(0.5),
 mUseRandomAxis(false),
@@ -602,5 +604,8 @@
 			RayInfoContainer::const_iterator it, it_end = tData.mRays->end();
 			for (it = tData.mRays->begin(); it != it_end; ++ it)
+			{
+				(*it).mRay->Ref();			
 				leaf->mVssRays.push_back((*it).mRay);
+			}
 		}
 
@@ -1886,4 +1891,21 @@
 
 
+void VspBspTree::CollectRays(VssRayContainer &rays)
+{
+	vector<BspLeaf *> leaves;
+
+	vector<BspLeaf *>::const_iterator lit, lit_end = leaves.end();
+
+	for (lit = leaves.begin(); lit != lit_end; ++ lit)
+	{
+		BspLeaf *leaf = *lit;
+		VssRayContainer::const_iterator rit, rit_end = leaf->mVssRays.end();
+
+		for (rit = leaf->mVssRays.begin(); rit != rit_end; ++ rit)
+			rays.push_back(*rit);
+	}
+}
+
+
 void VspBspTree::ValidateTree()
 {
@@ -1988,5 +2010,5 @@
 						  RayInfoContainer &rays,
 						  RayInfoContainer &frontRays,
-						  RayInfoContainer &backRays)
+						  RayInfoContainer &backRays) const
 {
 	int splits = 0;
@@ -2015,5 +2037,5 @@
 			{
 				//-- split ray
-				//-- test if start point behind or in front of plane
+				//   test if start point behind or in front of plane
 				const int side = plane.Side(bRay.ExtrapOrigin());
 
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/Plane3.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/Plane3.h	(revision 504)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/Plane3.h	(revision 639)
@@ -40,7 +40,7 @@
   }
 
-  int Side(const Vector3 &v, const float threshold = 1e-6) const {
-    return signum(Distance(v), threshold);
-  }
+  /** Returns 1 if v is on front side, -1 if on back side, 0 if on plane.
+  */
+  int Side(const Vector3 &v, const float threshold = 1e-6) const;
 
   /** Finds intersection of line segment between points a and b with plane.
@@ -53,38 +53,10 @@
 						   const Vector3 &b,
 						   float *t = NULL,
-						   bool *coplanar = NULL) const 
-  {
-    const Vector3 v = b - a; // line from A to B
-    float dv = DotProd(v, mNormal);
-    
-    if (signum(dv) == 0)
-	{
-		if (coplanar) (*coplanar) = true;	
-		if (t) (*t) = 0;
-		return a;
-	}
-	
-	if (coplanar) (*coplanar) = false;
-    float u = - Distance(a) / dv; // TODO: could be done more efficiently
-    
-	if (t) (*t) = u;
-	
-    return a + u * v;
-  }
+						   bool *coplanar = NULL) const;
   
   /** Finds value of intersection parameter t on line segment from a to b.
-      @returns -1 if coplanar, else parameter t
+      @returns 0 if coplanar, else parameter t
   */
-  float FindT(const Vector3 &a, const Vector3 &b) const 
-  {	  
-	  const Vector3 v = b - a; // line from A to B
-	  const float dv = DotProd(v, mNormal);
-    
-	  // does not intersect or coincident
-	  if (signum(dv) == 0)
-		  return 0;
-	
-	  return - Distance(a) / dv; // TODO: could be done more efficiently
-  }
+  float FindT(const Vector3 &a, const Vector3 &b) const;
 
   friend bool
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/VssPreprocessor.cpp
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/VssPreprocessor.cpp	(revision 605)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/VssPreprocessor.cpp	(revision 639)
@@ -531,5 +531,5 @@
   if (mUseViewSpaceBox)
   {
-	  if (0)
+	  if (1)
 		  mViewSpaceBox = box;
 	  else
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/RayInfo.cpp
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/RayInfo.cpp	(revision 508)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/RayInfo.cpp	(revision 639)
@@ -106,6 +106,6 @@
 		mMaxT = t; 
 	}
-	
 #endif 
+
 
 int RayInfo::ComputeRayIntersection(const int axis, const float position, float &t) const
@@ -133,23 +133,28 @@
 {	
 	t = splitPlane.FindT(mRay->GetOrigin(), mRay->GetTermination());
-//	Debug << "t: " << t << " mint " << GetMinT() << " maxt " << GetMaxT() << 
-//	" orig: " << mRay->GetOrigin() << " term " << mRay->GetTermination() << endl;
+
+	if (0)
+		Debug << "t: " << t << " mint " << GetMinT() << " maxt " << GetMaxT() 
+		      << " orig: " << mRay->GetOrigin() << " term " << mRay->GetTermination() << endl;
 
 	// NOTE: if plane equals end point of ray, the ray should be classified
 	// non-intersecting, otherwise polygon-plane intersections of bsp tree
 	// approaches are not eliminating any rays intersecting the polygon!
-#if 1
-	if (t >= GetMaxT() - 1e-20)
+	const float thresh = 1 ? 1e-6f : 0.0f;
+
+	// segment is not intersecting plane: fond out if on front or back side
+	if (t >= GetMaxT() - thresh)
+	{
 		return splitPlane.Side(ExtrapOrigin());
-	if (t <= GetMinT() + 1e-20)
+	}
+		
+	if (t <= GetMinT() + thresh)
+	{
 		return splitPlane.Side(ExtrapTermination());
-#else
-	if (t > GetMaxT())
-		return splitPlane.Side(ExtrapOrigin());
-	else if (t < GetMinT())
-		return splitPlane.Side(ExtrapTermination());
-#endif
+	}
+	
 	return 0;
 }
+
 
 float RayInfo::SegmentLength() const
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/ViewCellsManager.cpp
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/ViewCellsManager.cpp	(revision 612)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/ViewCellsManager.cpp	(revision 639)
@@ -16,5 +16,5 @@
 #include "RssPreprocessor.h"
 
-#define SAMPLE_AFTER_SUBDIVISION 0
+#define SAMPLE_AFTER_SUBDIVISION 1
 
 
@@ -115,5 +115,5 @@
 
 /// helper function which destroys rays or copies them into the output ray container
-inline void addOutRays(VssRayContainer &rays, VssRayContainer *outRays)
+inline void disposeRays(VssRayContainer &rays, VssRayContainer *outRays)
 {
 	cout << "disposing samples ... ";
@@ -132,6 +132,14 @@
 	else
 	{
-		CLEAR_CONTAINER(rays);
-	}
+		VssRayContainer::const_iterator it, it_end = rays.end();
+
+		for (it = rays.begin(); it != it_end; ++ it)
+		{
+			//(*it)->Unref();
+			if (!(*it)->IsActive())
+				delete (*it);
+		}
+	}
+
 	cout << "finished" << endl;
 	Debug << "disposed " << n << " samples in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
@@ -162,5 +170,5 @@
 
 	// rays can be passed or deleted
-	addOutRays(initialSamples, outRays);
+	disposeRays(initialSamples, outRays);
 	
 
@@ -196,5 +204,5 @@
 
 
-		addOutRays(constructionSamples, outRays);
+		disposeRays(constructionSamples, outRays);
 
 		cout << "total samples: " << numSamples << endl;
@@ -236,5 +244,5 @@
 	Visualize(preprocessor->mObjects, visualizationSamples);
 
-	addOutRays(visualizationSamples, outRays);
+	disposeRays(visualizationSamples, outRays);
 
 	return numSamples;
@@ -3056,9 +3064,10 @@
 										  const VssRayContainer &rays)
 {
-	const int leafOut = 10;
+	const int leafOut = 20;
 
 	ViewCell::NewMail();
 
-	cout << "visualization using " << mVisualizationSamples << " samples" << endl;
+	cout << "visualization using " << (int)rays.size() << " samples" << endl;
+	Debug << "visualization using " << (int)rays.size() << " samples" << endl;
 	Debug << "\nOutput view cells: " << endl;
 
@@ -3066,19 +3075,15 @@
 	if (0)
 		stable_sort(mViewCells.begin(), mViewCells.end(), vc_gt);
-
+	
 	int limit = min(leafOut, (int)mViewCells.size());
 
-	int raysOut;
+	int raysOut = 0;
 
 	//-- some rays for output
-	if (1)
-		raysOut = min((int)rays.size(), mVisualizationSamples);
-
 	for (int i = 0; i < limit; ++ i)
 	{
 		cout << "creating output for view cell " << i << " ... ";
 
-		VssRayContainer vcRays;
-		Intersectable::NewMail();
+	
 		ViewCell *vc;
 	
@@ -3086,28 +3091,80 @@
 			vc = mViewCells[i];
 		else
-			vc = mViewCells[Random((int)mViewCells.size())];
-
-		vector<ViewCell *> leaves;
-		mViewCellsTree->CollectLeaves(vc, leaves);
-
-        if (1)
-		{
-			// check whether we can add the current ray to the output rays
-			for (int k = 0; k < raysOut; ++ k)
-			{
-				VssRay *ray = rays[k];
-				for	(int j = 0; j < (int)ray->mViewCells.size(); ++ j)
-				{
-					ViewCell *rayvc = ray->mViewCells[j];
-
-					if (leaves[0] == rayvc)
-						vcRays.push_back(ray);
-				}
-			}
-		}
+			vc = mViewCells[(int)RandomValue(0, (float)mViewCells.size() - 1)];
 
 		//bspLeaves[j]->Mail();
 		char s[64]; sprintf(s, "bsp-pvs%04d.x3d", i);
 		Exporter *exporter = Exporter::GetExporter(s);
+		
+		Debug << i << ": pvs size=" << (int)mViewCellsTree->GetPvsSize(vc) << endl;
+
+		if (1 || mExportRays)
+		{
+			if (1)
+			{
+				VssRayContainer vcRays;
+                VssRayContainer collectRays;
+
+				raysOut = min((int)rays.size(), 100);
+
+				// collect intial view cells
+				ViewCellContainer leaves;
+				mViewCellsTree->CollectLeaves(vc, leaves);
+
+				ViewCellContainer::const_iterator vit, vit_end = leaves.end();
+       
+				for (vit = leaves.begin(); vit != vit_end; ++ vit)
+				{
+					BspLeaf *vcLeaf = dynamic_cast<BspViewCell *>(*vit)->mLeaf;
+				
+					VssRayContainer::const_iterator rit, rit_end = vcLeaf->mVssRays.end();
+
+					for (rit = vcLeaf->mVssRays.begin(); rit != rit_end; ++ rit)
+					{
+						collectRays.push_back(*rit);
+					}
+				}
+
+				VssRayContainer::const_iterator rit, rit_end = collectRays.end();
+
+				for (rit = collectRays.begin(); rit != rit_end; ++ rit)
+				{
+					float p = RandomValue(0.0f, (float)collectRays.size());
+			
+					if (p < raysOut)
+						vcRays.push_back(*rit);
+				}
+				//-- export rays piercing this view cell
+				exporter->ExportRays(vcRays, RgbColor(1, 1, 1));
+			}
+
+			
+
+			if (0)
+			{
+				VssRayContainer vcRays;
+				raysOut = min((int)rays.size(), mVisualizationSamples);
+				// check whether we can add the current ray to the output rays
+				for (int k = 0; k < raysOut; ++ k)
+				{
+					VssRay *ray = rays[k];
+					for	(int j = 0; j < (int)ray->mViewCells.size(); ++ j)
+					{
+						ViewCell *rayvc = ray->mViewCells[j];
+	
+						if (rayvc == vc)
+							vcRays.push_back(ray);
+					}
+				}	
+				
+				//-- export rays piercing this view cell
+				exporter->ExportRays(vcRays, RgbColor(1, 1, 0));
+			}
+
+		}
+		
+		
+
+
 		exporter->SetWireframe();
 
@@ -3117,58 +3174,42 @@
 
 		ExportViewCellGeometry(exporter, vc);
-
-
-		Debug << i << ": pvs size=" << (int)mViewCellsTree->GetPvsSize(vc)
-			  << ", piercing rays=" << (int)vcRays.size() << endl;
-			//  << ", leaves=" << (int)vc->mLeaves.size() << endl;
-
-		
-		//-- export rays piercing this view cell
+	
+
+		m.mDiffuseColor = RgbColor(1, 0, 0);
+	    exporter->SetForcedMaterial(m);
+
+		exporter->SetFilled();
+
+
 		if (1)
 		{
-			exporter->ExportRays(vcRays, RgbColor(1, 1, 1));
+			ObjectPvsMap::const_iterator oit,
+				oit_end = vc->GetPvs().mEntries.end();
+
+
+			exporter->SetFilled();
+
+			Intersectable::NewMail();
+	
+			// output PVS of view cell
+			for (oit = vc->GetPvs().mEntries.begin(); oit != oit_end; ++ oit)
+			{		
+				Intersectable *intersect = (*oit).first;
+
+				if (!intersect->Mailed())
+				{
+					//m = RandomMaterial();
+					//exporter->SetForcedMaterial(m);
+
+					exporter->ExportIntersectable(intersect);
+					intersect->Mail();
+				}
+			}
 		}
 		else
 		{
-
-			ViewCellContainer leaves;
-			mViewCellsTree->CollectLeaves(vc, leaves);
-
-			ViewCellContainer::const_iterator lit, lit_end = leaves.end();
-
-			for (lit = leaves.begin(); lit != lit_end; ++ lit)
-			{
-				BspLeaf *l = dynamic_cast<BspViewCell *>(*lit)->mLeaf;
-				exporter->ExportRays(l->mVssRays);
-			}
-		}
-
-	
-		m.mDiffuseColor = RgbColor(1, 0, 0);
-		exporter->SetForcedMaterial(m);
-
-		ObjectPvsMap::const_iterator it,
-			it_end = vc->GetPvs().mEntries.end();
-
-		exporter->SetFilled();
-
-	
-		// output PVS of view cell
-		for (it = vc->GetPvs().mEntries.begin(); it != it_end; ++ it)
-		{
-		
-			Intersectable *intersect = (*it).first;
-
-			if (!intersect->Mailed())
-			{
-				Material m = RandomMaterial();
-				exporter->SetForcedMaterial(m);
-
-				exporter->ExportIntersectable(intersect);
-				intersect->Mail();
-			}
-		}
-
-		
+			exporter->ExportGeometry(objects);
+		}
+
 		DEL_PTR(exporter);
 		cout << "finished" << endl;
