Index: /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/include/TestKdTree.h
===================================================================
--- /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/include/TestKdTree.h	(revision 1163)
+++ /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/include/TestKdTree.h	(revision 1163)
@@ -0,0 +1,70 @@
+#ifndef __KdTreeApp_H__
+#define __KdTreeApp_H__
+
+#include "ExampleApplication.h"
+#include "TestKdTreeAppListener.h"
+
+#include <ivreader.h>
+
+class KdTreeApp : public ExampleApplication
+{
+public:
+
+	KdTreeApp()	{ mFrameListener = 0; }
+
+	~KdTreeApp()
+	{
+		delete mFrameListener;
+	}
+
+protected:
+	SceneNode *mDeathNode;
+	Camera *mTopCam;
+	Camera *mFollowCam;
+	KdTreeAppListener *mFrameListener;
+
+	String  mSceneFiles;
+	String	mSelectedSceneManager;
+	Real	mMoveSpeed;
+	Real	mRotateSpeed;
+	Real	mRotationRadius;
+	Real	mRotationPeriod;
+	int		mModelSpacing;
+	int		mModelCount;
+	int		mRandomCount;
+	Real	mPlaneDim;
+	bool	mShadowsEnabled;
+	int		mSelectEntities;
+
+	virtual void setupResources(void);
+
+	virtual void createScene(void);
+
+	virtual void createFrameListener(void);
+	
+	virtual void chooseSceneManager(void);
+
+    virtual void createCamera(void);
+
+	virtual void createViewports(void);
+
+    /** Configures the application - returns false if the user chooses to abandon configuration. */
+    virtual bool configure(void);
+
+	bool loadScene(const String& filename);
+	bool loadSceneIV(const String &filename, SceneNode *root, const int index);
+private:
+	std::string cat(std::string name, int x, int z)
+	{
+		std::stringstream s;
+		s.fill('0');
+		s << name;
+		s.width(2);
+		s << x;
+		s.width(2);
+		s << z;
+		return s.str();
+	}
+};
+
+#endif
Index: /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/include/TestKdTreeAppListener.h
===================================================================
--- /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/include/TestKdTreeAppListener.h	(revision 1163)
+++ /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/include/TestKdTreeAppListener.h	(revision 1163)
@@ -0,0 +1,847 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of OGRE
+    (Object-oriented Graphics Rendering Engine)
+For the latest info, see http://www.ogre3d.org/
+
+Copyright (c) 2000-2005 The OGRE Team
+Also see acknowledgements in Readme.html
+
+You may use this sample code for anything you like, it is not covered by the
+LGPL like the rest of the engine.
+-----------------------------------------------------------------------------
+*/
+/*
+-----------------------------------------------------------------------------
+Filename:    ExampleFrameListener.h
+Description: Defines an example frame listener which responds to frame events.
+This frame listener just moves a specified camera around based on
+keyboard and mouse movements.
+Mouse:    Freelook
+W or Up:  Forward
+S or Down:Backward
+A:        Step left
+D:        Step right
+             PgUp:     Move upwards
+             PgDown:   Move downwards
+             F:        Toggle frame rate stats on/off
+			 R:        Render mode
+             T:        Cycle texture filtering
+                       Bilinear, Trilinear, Anisotropic(8)
+             P:        Toggle on/off display of camera position / orientation
+-----------------------------------------------------------------------------
+*/
+
+#ifndef __KdTreeAppListener_H__
+#define __KdTreeAppListener_H__
+
+#include "Ogre.h"
+#include "OgreKeyEvent.h"
+#include "OgreEventListeners.h"
+#include "OgreStringConverter.h"
+#include "OgreException.h"
+
+using namespace Ogre;
+
+class KdTreeAppListener: public FrameListener, public KeyListener
+{
+protected:
+	int mSceneDetailIndex ;
+    Real mMoveSpeed;
+    Degree mRotateSpeed;
+    Overlay* mDebugOverlay;
+	Overlay* mKdTreeOverlay;
+	Real mRotationPeriod;
+	bool mShowTree;
+
+	int mSeqNum;
+
+    void updateStats(void)
+    {
+        static String currFps = "Current FPS: ";
+        static String avgFps = "Average FPS: ";
+        static String bestFps = "Best FPS: ";
+        static String worstFps = "Worst FPS: ";
+        static String tris = "Triangle Count: ";
+
+        // 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();
+
+            guiAvg->setCaption(avgFps + StringConverter::toString(stats.avgFPS));
+            guiCurr->setCaption(currFps + StringConverter::toString(stats.lastFPS));
+            guiBest->setCaption(bestFps + StringConverter::toString(stats.bestFPS)
+                +" "+StringConverter::toString(stats.bestFrameTime)+" ms");
+            guiWorst->setCaption(worstFps + StringConverter::toString(stats.worstFPS)
+                +" "+StringConverter::toString(stats.worstFrameTime)+" ms");
+
+            OverlayElement* guiTris = OverlayManager::getSingleton().getOverlayElement("Core/NumTris");
+            guiTris->setCaption(tris + StringConverter::toString(stats.triangleCount));
+
+            OverlayElement* guiDbg = OverlayManager::getSingleton().getOverlayElement("Core/DebugText");
+            guiDbg->setCaption(mWindow->getDebugText());
+        }
+        catch(...)
+        {
+            // ignore
+        }
+    }
+
+public:
+
+    // Constructor takes a RenderWindow because it uses that to determine input context
+    KdTreeAppListener(RenderWindow* win, SceneManager* sm, Real rs, Real ms, Real rp,
+		bool useBufferedInputKeys = false, bool useBufferedInputMouse = false)
+    {
+        mDebugOverlay = OverlayManager::getSingleton().getByName("Core/DebugOverlay");
+		mKdTreeOverlay = OverlayManager::getSingleton().getByName("KdTree/DebugOverlay");
+
+
+        mUseBufferedInputKeys = useBufferedInputKeys;
+		mUseBufferedInputMouse = useBufferedInputMouse;
+		mInputTypeSwitchingOn = mUseBufferedInputKeys || mUseBufferedInputMouse;
+
+		if (mInputTypeSwitchingOn)
+		{
+            mEventProcessor = new EventProcessor();
+			mEventProcessor->initialise(win);
+			mEventProcessor->startProcessingEvents();
+			mEventProcessor->addKeyListener(this);
+			mInputDevice = mEventProcessor->getInputReader();
+
+		}
+        else
+        {
+            mInputDevice = PlatformManager::getSingleton().createInputReader();
+            mInputDevice->initialise(win,true, true);
+        }
+
+		mShowTree = false;
+		mCullCamera = false;
+		mCullTransVec = Vector3::ZERO;
+		mSeqNum = 0;
+
+		mCamera = sm->getCamera("PlayerCam");
+		mTopCam = sm->getCamera("TopCam");
+		mSceneMgr = sm;
+        mWindow = win;
+		mRotateSpeed = rs;
+        mMoveSpeed = ms;
+		mRotationPeriod = rp;
+		mDeathAngle = 0;
+        mStatsOn = true;
+		mNumScreenShots = 0;
+		mTimeUntilNextToggle = 0;
+        mSceneDetailIndex = 0;
+        mMoveScale = 0.0f;
+        mRotScale = 0.0f;
+	    mTranslateVector = Vector3::ZERO;
+        mAniso = 8;
+        mFiltering = TFO_ANISOTROPIC;
+
+        MaterialManager::getSingleton().setDefaultTextureFiltering(mFiltering);
+        MaterialManager::getSingleton().setDefaultAnisotropy(mAniso);
+
+		initKdTreeOverlay();
+
+        showDebugOverlay(true);
+    }
+    virtual ~KdTreeAppListener()
+    {
+		if (mInputTypeSwitchingOn)
+		{
+            delete mEventProcessor;
+		}
+        else
+        {
+            PlatformManager::getSingleton().destroyInputReader( mInputDevice );
+        }
+    }
+
+	void initKdTreeOverlay()
+	{
+		String na = " N/A";
+		String value;
+
+		int maxd;
+		if (mSceneMgr->getOption("KdTreeMaxDepth", &maxd))
+			value = " " + StringConverter::toString(maxd);
+		else
+			value = na;
+		String caption = OverlayManager::getSingleton().getOverlayElement("KdTree/Depth")->getCaption();
+		OverlayManager::getSingleton().getOverlayElement("KdTree/Depth")->setCaption(caption + value);
+
+		Real kt;
+		if (mSceneMgr->getOption("KT", &kt))
+			value = " " + StringConverter::toString(kt);
+		else
+			value = na;
+		caption = OverlayManager::getSingleton().getOverlayElement("KdTree/KT")->getCaption();
+		OverlayManager::getSingleton().getOverlayElement("KdTree/KT")->setCaption(caption + value);
+
+		Real ki;
+		if (mSceneMgr->getOption("KI", &ki))
+			value = " " + StringConverter::toString(ki);
+		else
+			value = na;
+		caption = OverlayManager::getSingleton().getOverlayElement("KdTree/KI")->getCaption();
+		OverlayManager::getSingleton().getOverlayElement("KdTree/KI")->setCaption(caption + value);
+
+		int hl;
+		if (mSceneMgr->getOption("HighlightLevel", &hl))
+			value = " " + StringConverter::toString(hl);
+		else
+			value = na;
+		if (!mShowTree)
+			value = " off";
+		caption = OverlayManager::getSingleton().getOverlayElement("KdTree/Highlight")->getCaption();
+		OverlayManager::getSingleton().getOverlayElement("KdTree/Highlight")->setCaption(caption + value);
+
+		String bm;
+		if (mSceneMgr->getOption("BuildMethod", &bm))
+			value = " " + bm;
+		else
+			value = na;
+		caption = OverlayManager::getSingleton().getOverlayElement("KdTree/BuildMethod")->getCaption();
+		OverlayManager::getSingleton().getOverlayElement("KdTree/BuildMethod")->setCaption(caption + value);
+	}
+
+	void toggleCullCamera()
+	{
+		mCullCamera = !mCullCamera;
+		int zorder = 2; 
+		if (mCullCamera)
+		{
+			Viewport* tvp = mWindow->addViewport(mTopCam,zorder,0.66,0.66,0.34,0.34);
+			tvp->setBackgroundColour(ColourValue(1.0, 0.0, 0.0));
+			tvp->setOverlaysEnabled(false);
+
+			mTopCam->setAspectRatio(
+				Real(tvp->getActualWidth())/Real(tvp->getActualHeight()));
+		}
+		else
+		{
+			mWindow->removeViewport(zorder);
+		}
+	}
+
+    virtual bool processUnbufferedKeyInput(const FrameEvent& evt)
+    {
+		// moving the cull camera
+		if (mInputDevice->isKeyDown(KC_NUMPAD2))
+		{
+			mCullTransVec.y = -mMoveScale;
+		}
+		if (mInputDevice->isKeyDown(KC_NUMPAD8))
+		{
+			mCullTransVec.y = mMoveScale;
+		}
+		if (mInputDevice->isKeyDown(KC_NUMPAD4))
+		{
+			mCullTransVec.x = mMoveScale;
+		}
+		if (mInputDevice->isKeyDown(KC_NUMPAD6))
+		{
+			mCullTransVec.x = -mMoveScale;
+		}
+		if (mInputDevice->isKeyDown(KC_SUBTRACT))
+		{
+			mCullTransVec.z = mMoveScale;
+		}
+		if (mInputDevice->isKeyDown(KC_ADD))
+		{
+			mCullTransVec.z = -mMoveScale;
+		}
+
+		// stuff for the kdtree overlay
+		static String sMaxDepth = "[1][2] Max Tree Depth: ";
+		static String sHL = "[3][4] Highlight: ";
+		static String sKT = "[5][6] KT: ";
+		static String sKI = "[7][8] KI: ";
+		static String sBM = "[Space] Build Method: ";
+
+		static String bmRec = "Recursive";
+		static String bmPQ = "PriorityQueue";
+
+		if ((mInputDevice->isKeyDown(KC_1) || mInputDevice->isKeyDown(KC_2)) && mTimeUntilNextToggle <= 0)
+		{
+			int currdepth;
+			if (mSceneMgr->getOption("KdTreeMaxDepth", &currdepth))
+			{
+				if (mInputDevice->isKeyDown(KC_1))
+					currdepth--;
+				else if (mInputDevice->isKeyDown(KC_2))
+					currdepth++;
+
+				if (mSceneMgr->setOption("KdTreeMaxDepth", &currdepth))
+				{
+					OverlayManager::getSingleton().getOverlayElement("KdTree/Depth")->setCaption(sMaxDepth + StringConverter::toString(currdepth));
+					int hl;
+					if (mSceneMgr->getOption("HighlightLevel", &hl))
+						OverlayManager::getSingleton().getOverlayElement("KdTree/Highlight")->setCaption(sHL + StringConverter::toString(hl));
+					else
+						OverlayManager::getSingleton().getOverlayElement("KdTree/Highlight")->setCaption(sHL + "N/A");
+				}
+			}
+			else
+			{
+				OverlayManager::getSingleton().getOverlayElement("KdTree/Depth")->setCaption(sMaxDepth + "N/A");
+				OverlayManager::getSingleton().getOverlayElement("KdTree/Highlight")->setCaption(sHL + "N/A");
+			}
+
+			if (!mShowTree)
+				OverlayManager::getSingleton().getOverlayElement("KdTree/Highlight")->setCaption(sHL + "off");
+
+			mTimeUntilNextToggle = 0.2;
+		}
+
+		if ((mInputDevice->isKeyDown(KC_3) || mInputDevice->isKeyDown(KC_4)) && mTimeUntilNextToggle <= 0)
+		{
+			int hl;
+			if (mSceneMgr->getOption("HighlightLevel", &hl))
+			{
+				if (mInputDevice->isKeyDown(KC_3))
+					hl--;
+				else if (mInputDevice->isKeyDown(KC_4))
+					hl++;
+
+				if (mSceneMgr->setOption("HighlightLevel", &hl))
+					OverlayManager::getSingleton().getOverlayElement("KdTree/Highlight")->setCaption(sHL + StringConverter::toString(hl));
+			}
+			else
+			{
+				OverlayManager::getSingleton().getOverlayElement("KdTree/Highlight")->setCaption(sHL + "N/A");
+			}
+
+			if (!mShowTree)
+				OverlayManager::getSingleton().getOverlayElement("KdTree/Highlight")->setCaption(sHL + "off");
+
+			mTimeUntilNextToggle = 0.2;
+		}
+
+
+		if ((mInputDevice->isKeyDown(KC_5) ||mInputDevice->isKeyDown(KC_6)) && mTimeUntilNextToggle <= 0)
+		{
+			Real kt;
+			if (mSceneMgr->getOption("KT", &kt))
+			{
+				if (mInputDevice->isKeyDown(KC_5))
+					kt -= 0.1;
+				else if (mInputDevice->isKeyDown(KC_6))
+					kt += 0.1;
+
+				if (kt < 0.1)
+					kt = 0.1;
+			
+				if (mSceneMgr->setOption("KT", &kt))
+					OverlayManager::getSingleton().getOverlayElement("KdTree/KT")->setCaption(sKT + StringConverter::toString(kt));
+			}
+			else
+			{
+				OverlayManager::getSingleton().getOverlayElement("KdTree/KT")->setCaption(sKT + "N/A");
+			}
+
+			mTimeUntilNextToggle = 0.2;
+		}
+
+		if ((mInputDevice->isKeyDown(KC_7) || mInputDevice->isKeyDown(KC_8)) && mTimeUntilNextToggle <= 0)
+		{
+			Real ki;
+			if (mSceneMgr->getOption("KI", &ki))
+			{
+				if (mInputDevice->isKeyDown(KC_7))
+					ki -= 0.1;
+				else if (mInputDevice->isKeyDown(KC_8))
+					ki += 0.1;
+
+				if (ki < 0.1)
+					ki = 0.1;
+
+				if (mSceneMgr->setOption("KI", &ki))
+					OverlayManager::getSingleton().getOverlayElement("KdTree/KI")->setCaption(sKI + StringConverter::toString(ki));
+			}
+			else
+			{
+				OverlayManager::getSingleton().getOverlayElement("KdTree/KI")->setCaption(sKI + "N/A");
+			}
+
+			mTimeUntilNextToggle = 0.2;
+		}
+
+		if (mInputDevice->isKeyDown(KC_SPACE) && mTimeUntilNextToggle <= 0)
+		{
+			String bm;
+			if (mSceneMgr->getOption("BuildMethod", &bm))
+			{
+				if (bm == bmRec)
+					bm = bmPQ;
+				else if (bm == bmPQ)
+					bm = bmRec;
+				if (mSceneMgr->setOption("BuildMethod", &bm))
+					OverlayManager::getSingleton().getOverlayElement("KdTree/BuildMethod")->setCaption(sBM + bm);
+			}
+			else
+			{
+				OverlayManager::getSingleton().getOverlayElement("KdTree/BuildMethod")->setCaption(sBM + "N/A");
+			}
+
+			mTimeUntilNextToggle = 0.2;
+		}
+
+		if (mInputDevice->isKeyDown(KC_BACK) && mTimeUntilNextToggle <= 0)
+		{
+			mSceneMgr->setOption("RebuildKdTree", 0);
+			mTimeUntilNextToggle = 1;
+		}
+
+		if (mInputDevice->isKeyDown(KC_N) && mTimeUntilNextToggle <= 0)
+		{
+			//Entity * ent = mSceneMgr->createEntity("randominsert" + StringConverter::toString(mSeqNum), "robot.mesh");
+			Entity * ent = mSceneMgr->createEntity("randominsert" + StringConverter::toString(mSeqNum), "razor.mesh");
+			//Vector3 position(Math::RangeRandom(100, 1125), -0, Math::RangeRandom(-1125, 1125));
+			Vector3 position(Math::RangeRandom(-5000, 5000), Math::RangeRandom(-5000, 5000), Math::RangeRandom(-5000, 5000));
+			//Quaternion orientation(Radian(Math::RangeRandom(-Math::PI, Math::PI)), Vector3::UNIT_Y);
+			Vector3 axis(Math::RangeRandom(-1,1),Math::RangeRandom(-1,1),Math::RangeRandom(-1,1));
+			axis.normalise();
+			Quaternion orientation(Radian(Math::RangeRandom(-Math::PI, Math::PI)), axis);
+			Vector3 scale(Math::RangeRandom(0.5, 5),Math::RangeRandom(0.5, 5),Math::RangeRandom(0.5, 5));
+			SceneNode * anchor = mSceneMgr->getSceneNode("AnchorNode");
+			SceneNode *sn = anchor->createChildSceneNode("RandomInsertNode" + StringConverter::toString(mSeqNum), position, orientation);
+			sn->attachObject(ent);
+			sn->setScale(scale);
+			mTimeUntilNextToggle = 0.5;
+			mSeqNum++;
+		}
+
+		if (mInputDevice->isKeyDown(KC_J) && mTimeUntilNextToggle <= 0)
+		{
+			if (mSeqNum > 0)
+			{
+				mSeqNum--;
+				mSceneMgr->destroySceneNode("RandomInsertNode" + StringConverter::toString(mSeqNum));
+				mSceneMgr->destroyEntity("randominsert" + StringConverter::toString(mSeqNum));
+				mTimeUntilNextToggle = 0.5;
+			}
+		}
+
+		if (mInputDevice->isKeyDown(KC_Y) && mTimeUntilNextToggle <= 0)
+		{
+			LogManager::getSingleton().logMessage("############## Camera Position:");
+			LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mCamera->getPosition()));
+			LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mCamera->getOrientation()));
+			LogManager::getSingleton().logMessage("############## Cull Camera Position:");
+			LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mTopCam->getPosition()));
+			LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mTopCam->getOrientation()));
+			mTimeUntilNextToggle = 1.0;
+		}
+
+		if (mInputDevice->isKeyDown(KC_B) && mTimeUntilNextToggle <= 0)
+		{
+			mSceneMgr->showBoundingBoxes( ! mSceneMgr->getShowBoundingBoxes() );
+			mTimeUntilNextToggle = 0.5;
+		}
+
+		if (mInputDevice->isKeyDown(KC_C) && mTimeUntilNextToggle <= 0)
+		{
+			toggleCullCamera();
+			mTimeUntilNextToggle = 0.5;
+		}
+
+		if (mInputDevice->isKeyDown(KC_V) && mTimeUntilNextToggle <= 0)
+		{
+			mShowTree = !mShowTree;
+
+			if (mSceneMgr->getTypeName() == "OctreeSceneManager")
+			{
+				//(static_cast<OctreeSceneManager *>(mSceneMgr))->setShowBoxes(mShowTree);
+				mSceneMgr->setOption("ShowOctree", &mShowTree);
+			}
+			else if (mSceneMgr->getTypeName() == "KdTreeSceneManager")
+			{
+				mSceneMgr->setOption("ShowKdTree", &mShowTree);
+				//KdTreeSceneManager *sm = static_cast<KdTreeSceneManager *>(mSceneMgr);
+				//sm->setShowBoxes(!sm->getShowBoxes());
+				//(static_cast<KdTreeSceneManager *>(mSceneMgr))->setShowBoxes(mShowTree);
+			}
+
+			if (!mShowTree)
+				OverlayManager::getSingleton().getOverlayElement("KdTree/Highlight")->setCaption(sHL + "off");
+			else
+			{
+				int hl;
+				if (mSceneMgr->getOption("HighlightLevel", &hl))
+					OverlayManager::getSingleton().getOverlayElement("KdTree/Highlight")->setCaption(sHL + StringConverter::toString(hl));
+				else
+					OverlayManager::getSingleton().getOverlayElement("KdTree/Highlight")->setCaption(sHL + "N/A");
+			}
+			
+			mTimeUntilNextToggle = 0.5;
+		}
+
+		if (mInputDevice->isKeyDown(KC_G) && mTimeUntilNextToggle <= 0)
+		{
+			bool toggleShowAllBoxes;
+			mSceneMgr->getOption("ShowAllBoxes", &toggleShowAllBoxes);
+			toggleShowAllBoxes = !toggleShowAllBoxes;
+			mSceneMgr->setOption("ShowAllBoxes", &toggleShowAllBoxes);
+			mTimeUntilNextToggle = 0.2;
+		}
+
+		if (mInputDevice->isKeyDown(KC_P))
+		{
+			mWindow->writeContentsToTimestampedFile("Screenshot",".jpg");
+		}
+
+        if (mInputDevice->isKeyDown(KC_A))
+        {
+            // Move camera left
+            mTranslateVector.x = -mMoveScale;
+        }
+
+        if (mInputDevice->isKeyDown(KC_D))
+        {
+            // Move camera RIGHT
+            mTranslateVector.x = mMoveScale;
+        }
+
+        /* Move camera forward by keypress. */
+        if (mInputDevice->isKeyDown(KC_UP) || mInputDevice->isKeyDown(KC_W) )
+        {
+            mTranslateVector.z = -mMoveScale;
+        }
+
+        /* Move camera backward by keypress. */
+        if (mInputDevice->isKeyDown(KC_DOWN) || mInputDevice->isKeyDown(KC_S) )
+        {
+            mTranslateVector.z = mMoveScale;
+        }
+
+        if (mInputDevice->isKeyDown(KC_PGUP))
+        {
+            // Move camera up
+            mTranslateVector.y = mMoveScale;
+        }
+
+        if (mInputDevice->isKeyDown(KC_PGDOWN))
+        {
+            // Move camera down
+            mTranslateVector.y = -mMoveScale;
+        }
+
+        if (mInputDevice->isKeyDown(KC_RIGHT))
+        {
+            mCamera->yaw(-mRotScale);
+        }
+		
+        if (mInputDevice->isKeyDown(KC_LEFT))
+        {
+            mCamera->yaw(mRotScale);
+        }
+
+        if( mInputDevice->isKeyDown( KC_ESCAPE) )
+        {            
+            return false;
+        }
+
+		// see if switching is on, and you want to toggle 
+        if (mInputTypeSwitchingOn && mInputDevice->isKeyDown(KC_M) && mTimeUntilNextToggle <= 0)
+        {
+			switchMouseMode();
+            mTimeUntilNextToggle = 1;
+        }
+
+        if (mInputTypeSwitchingOn && mInputDevice->isKeyDown(KC_K) && mTimeUntilNextToggle <= 0)
+        {
+			// must be going from immediate keyboard to buffered keyboard
+			switchKeyMode();
+            mTimeUntilNextToggle = 1;
+        }
+        if (mInputDevice->isKeyDown(KC_F) && mTimeUntilNextToggle <= 0)
+        {
+            mStatsOn = !mStatsOn;
+            showDebugOverlay(mStatsOn);
+
+            mTimeUntilNextToggle = 1;
+        }
+        if (mInputDevice->isKeyDown(KC_T) && mTimeUntilNextToggle <= 0)
+        {
+            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);
+
+
+            showDebugOverlay(mStatsOn);
+
+            mTimeUntilNextToggle = 1;
+        }
+
+        if (mInputDevice->isKeyDown(KC_SYSRQ) && mTimeUntilNextToggle <= 0)
+        {
+			char tmp[20];
+			sprintf(tmp, "screenshot_%d.png", ++mNumScreenShots);
+            mWindow->writeContentsToFile(tmp);
+            mTimeUntilNextToggle = 0.5;
+			mWindow->setDebugText(String("Wrote ") + tmp);
+        }
+		
+		if (mInputDevice->isKeyDown(KC_R) && mTimeUntilNextToggle <=0)
+		{
+			mSceneDetailIndex = (mSceneDetailIndex+1)%3 ;
+			switch(mSceneDetailIndex) {
+				case 0 : mCamera->setPolygonMode(PM_SOLID) ; break ;
+				case 1 : mCamera->setPolygonMode(PM_WIREFRAME) ; break ;
+				case 2 : mCamera->setPolygonMode(PM_POINTS) ; break ;
+			}
+			mTimeUntilNextToggle = 0.5;
+		}
+
+        static bool displayCameraDetails = false;
+        if (mInputDevice->isKeyDown(KC_P) && mTimeUntilNextToggle <= 0)
+        {
+            displayCameraDetails = !displayCameraDetails;
+            mTimeUntilNextToggle = 0.5;
+            if (!displayCameraDetails)
+                mWindow->setDebugText("");
+        }
+        if (displayCameraDetails)
+        {
+            // Print camera details
+            mWindow->setDebugText("P: " + StringConverter::toString(mCamera->getDerivedPosition()) + " " + 
+                "O: " + StringConverter::toString(mCamera->getDerivedOrientation()));
+        }
+
+        // Return true to continue rendering
+        return true;
+    }
+
+    bool 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;
+	}
+
+	void moveCamera()
+	{
+
+        // Make all the changes to the camera
+        // Note that YAW direction is around a fixed axis (freelook style) rather than a natural YAW (e.g. airplane)
+        mCamera->yaw(mRotX);
+        mCamera->pitch(mRotY);
+        mCamera->moveRelative(mTranslateVector);
+		mTopCam->moveRelative(mCullTransVec);
+	}
+
+    void showDebugOverlay(bool show)
+    {
+        if (mDebugOverlay)
+        {
+            if (show)
+            {
+                mDebugOverlay->show();
+				mKdTreeOverlay->show();
+            }
+            else
+            {
+                mDebugOverlay->hide();
+				mKdTreeOverlay->hide();
+            }
+        }
+    }
+
+    // Override frameStarted event to process that (don't care about frameEnded)
+    bool frameStarted(const FrameEvent& evt)
+    {
+        if(mWindow->isClosed())
+            return false;
+
+        if (!mInputTypeSwitchingOn)
+    	{
+            mInputDevice->capture();
+        }
+
+
+		if ( !mUseBufferedInputMouse || !mUseBufferedInputKeys)
+		{
+			// one of the input modes is immediate, so setup what is needed for immediate mouse/key movement
+			if (mTimeUntilNextToggle >= 0) 
+				mTimeUntilNextToggle -= 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;
+			mCullTransVec = Vector3::ZERO;
+		}
+
+        if (mUseBufferedInputKeys)
+        {
+            // no need to do any processing here, it is handled by event processor and 
+			// you get the results as KeyEvents
+        }
+        else
+        {
+            if (processUnbufferedKeyInput(evt) == false)
+			{
+				return false;
+			}
+        }
+        if (mUseBufferedInputMouse)
+        {
+            // no need to do any processing here, it is handled by event processor and 
+			// you get the results as MouseEvents
+        }
+        else
+        {
+            if (processUnbufferedMouseInput(evt) == false)
+			{
+				return false;
+			}
+        }
+
+		if ( !mUseBufferedInputMouse || !mUseBufferedInputKeys)
+		{
+			// one of the input modes is immediate, so update the movement vector
+
+			moveCamera();
+
+		}
+
+		Camera	*followCam = mSceneMgr->getCamera("FollowCam");
+		if (followCam->getAutoTrackTarget() != 0)
+		{
+			// Move the death thingy & update lookat camera FOV
+			SceneNode *deathPivotNode = mSceneMgr->getSceneNode("deathPivotNode");
+			SceneNode *deathNode = mSceneMgr->getSceneNode("movingNode");
+			SceneNode *pivotNode = mSceneMgr->getSceneNode("pivotNode");
+
+			Vector3 fcpos = followCam->getPosition();
+			Vector3 oldpos = deathNode->getWorldPosition();
+			
+			Radian deltaAngle = Radian(evt.timeSinceLastFrame / mRotationPeriod * Math::TWO_PI);
+			deathPivotNode->rotate(Vector3::UNIT_Y, deltaAngle);
+			pivotNode->rotate(Vector3::UNIT_Y, deltaAngle * 4);
+			
+			Vector3 pos = deathNode->getWorldPosition();
+
+			Real olddist = (oldpos - fcpos).length();
+			Real dist = (pos - fcpos).length();
+
+			Radian oldfov = followCam->getFOVy();
+			Radian fov = Radian(olddist / dist) * oldfov;
+
+			followCam->setFOVy(fov);
+		}
+
+		return true;
+    }
+
+    bool frameEnded(const FrameEvent& evt)
+    {
+        updateStats();
+        return true;
+    }
+
+	void switchMouseMode() 
+	{
+        mUseBufferedInputMouse = !mUseBufferedInputMouse;
+		mInputDevice->setBufferedInput(mUseBufferedInputKeys, mUseBufferedInputMouse);
+	}
+	void switchKeyMode() 
+	{
+        mUseBufferedInputKeys = !mUseBufferedInputKeys;
+		mInputDevice->setBufferedInput(mUseBufferedInputKeys, mUseBufferedInputMouse);
+	}
+
+	void keyClicked(KeyEvent* e) 
+	{
+		if (e->getKeyChar() == 'm')
+		{
+			switchMouseMode();
+		}
+		else if (e->getKeyChar() == 'k')
+		{
+
+			switchKeyMode();
+		}
+
+	}
+	void keyPressed(KeyEvent* e) {}
+	void keyReleased(KeyEvent* e) {}
+
+protected:
+    EventProcessor* mEventProcessor;
+    InputReader* mInputDevice;
+    Camera* mCamera;
+	Camera* mTopCam;
+	SceneManager *mSceneMgr;
+	Radian mDeathAngle;
+
+    Vector3 mTranslateVector;
+    RenderWindow* mWindow;
+    bool mStatsOn;
+    bool mUseBufferedInputKeys, mUseBufferedInputMouse, mInputTypeSwitchingOn;
+	unsigned int mNumScreenShots;
+    float mMoveScale;
+    Degree mRotScale;
+    // just to stop toggles flipping too fast
+    Real mTimeUntilNextToggle ;
+    Radian mRotX, mRotY;
+    TextureFilterOptions mFiltering;
+    int mAniso;
+
+	// stuff for the culling camera
+	bool mCullCamera;
+	Vector3 mCullTransVec;
+};
+
+#endif
+
Index: /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/scripts/TestKdTree.vcproj
===================================================================
--- /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/scripts/TestKdTree.vcproj	(revision 1163)
+++ /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/scripts/TestKdTree.vcproj	(revision 1163)
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="windows-1250"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="7.10"
+	Name="TestKdTree"
+	ProjectGUID="{17F2C6F9-6101-430E-ABF4-71383868EF24}"
+	Keyword="Win32Proj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="..\bin\$(ConfigurationName)"
+			IntermediateDirectory="..\obj\$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				ImproveFloatingPointConsistency="TRUE"
+				AdditionalIncludeDirectories="..\include;&quot;$(OGRE_PATH)\Samples\Common\include&quot;;&quot;$(OGRE_PATH)\OgreMain\include&quot;;..\..\..\..\..\..\Lib\Vis\OnlineCullingCHC\IVReader\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;GTP_VISIBILITY_MODIFIED_OGRE;KDTREE_FASTSTART"
+				MinimalRebuild="TRUE"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				EnableFunctionLevelLinking="TRUE"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="TRUE"
+				DebugInformationFormat="3"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="OgreMain_d.lib IVReader.lib"
+				OutputFile="$(OutDir)/$(ProjectName).exe"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;$(OGRE_PATH)\OgreMain\lib\$(ConfigurationName)&quot;;&quot;..\..\..\..\..\..\Lib\Vis\OnlineCullingCHC\IVReader\lib\$(ConfigurationName)&quot;"
+				GenerateDebugInformation="TRUE"
+				ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"
+				SubSystem="2"
+				OptimizeForWindows98="1"
+				TargetMachine="1"/>
+			<Tool
+				Name="VCMIDLTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"
+				CommandLine="copy $(OutDir)\$(TargetFileName) &quot;$(OGRE_PATH)\Samples\Common\bin\$(ConfigurationName)&quot;"/>
+			<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"
+			WholeProgramOptimization="TRUE">
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				GlobalOptimizations="TRUE"
+				InlineFunctionExpansion="1"
+				EnableIntrinsicFunctions="TRUE"
+				ImproveFloatingPointConsistency="TRUE"
+				FavorSizeOrSpeed="1"
+				OmitFramePointers="TRUE"
+				OptimizeForProcessor="2"
+				OptimizeForWindowsApplication="TRUE"
+				AdditionalIncludeDirectories="..\include;&quot;$(OGRE_PATH)\Samples\Common\include&quot;;&quot;$(OGRE_PATH)\OgreMain\include&quot;;..\..\..\..\..\..\Lib\Vis\OnlineCullingCHC\IVReader\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GTP_VISIBILITY_MODIFIED_OGRE;KDTREE_FASTSTART"
+				StringPooling="TRUE"
+				MinimalRebuild="TRUE"
+				RuntimeLibrary="2"
+				BufferSecurityCheck="FALSE"
+				EnableFunctionLevelLinking="TRUE"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="TRUE"
+				DebugInformationFormat="3"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="OgreMain.lib IVReader.lib"
+				OutputFile="$(OutDir)/$(ProjectName).exe"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;$(OGRE_PATH)\OgreMain\lib\$(ConfigurationName)&quot;;&quot;..\..\..\..\..\..\Lib\Vis\OnlineCullingCHC\IVReader\lib\$(ConfigurationName)&quot;"
+				GenerateDebugInformation="FALSE"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				OptimizeForWindows98="1"
+				TargetMachine="1"/>
+			<Tool
+				Name="VCMIDLTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"
+				CommandLine="copy $(OutDir)\$(TargetFileName) &quot;$(OGRE_PATH)\Samples\Common\bin\$(ConfigurationName)&quot;"/>
+			<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">
+			<File
+				RelativePath="..\src\TestKdTree.cpp">
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc">
+			<File
+				RelativePath="..\include\TestKdTree.h">
+			</File>
+			<File
+				RelativePath="..\include\TestKdTreeAppListener.h">
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
Index: /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/src/TestKdTree.cpp
===================================================================
--- /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/src/TestKdTree.cpp	(revision 1163)
+++ /GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/src/TestKdTree.cpp	(revision 1163)
@@ -0,0 +1,442 @@
+#include "TestKdTree.h"
+
+#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
+#define WIN32_LEAN_AND_MEAN
+#include "windows.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
+	INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
+#else
+	int main(int argc, char *argv[])
+#endif
+	{
+		// Create application object
+		KdTreeApp app;
+
+		SET_TERM_HANDLER;
+
+		// init random number generator
+		// srand(time(0));
+
+		try {
+			app.go();
+		} catch( Ogre::Exception& e ) {
+#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
+			MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
+#else
+			std::cerr << "An exception has occured: " <<
+				e.getFullDescription().c_str() << std::endl;
+#endif
+		}
+
+		return 0;
+	}
+
+#ifdef __cplusplus
+}
+#endif
+
+#define ENT_GRID	0x01
+#define ENT_RND		0x02
+#define ENT_SPC		0x04
+#define ENT_MOV		0x08
+#define ENT_PLN		0x10
+
+void KdTreeApp::setupResources(void)
+{
+	String tmp;
+	ConfigFile cfDeath;
+	char *errptr;
+	int base = 10;
+
+	cfDeath.load("testKdTree.cfg");
+
+	mSelectedSceneManager = cfDeath.getSetting("scenemanager");
+	mSceneFiles = cfDeath.getSetting("scene");
+
+	tmp = cfDeath.getSetting("shadows");
+	StringUtil::toLowerCase(tmp);
+	if (tmp == "on")
+		mShadowsEnabled = true;
+	else
+		mShadowsEnabled = false;
+
+
+	tmp = cfDeath.getSetting("planedim");
+	mPlaneDim = static_cast<Real>(strtod(tmp.c_str(), &errptr));
+
+	tmp = cfDeath.getSetting("randomcount");
+	mRandomCount = static_cast<int>(strtol(tmp.c_str(), &errptr, base));
+
+	tmp = cfDeath.getSetting("selectentities");
+	mSelectEntities = static_cast<int>(strtol(tmp.c_str(), &errptr, base));
+
+	tmp = cfDeath.getSetting("count");
+	mModelCount = static_cast<int>(strtol(tmp.c_str(), &errptr, base));
+
+	tmp = cfDeath.getSetting("spacing");
+	mModelSpacing = static_cast<int>(strtol(tmp.c_str(), &errptr, base));
+	
+	tmp = cfDeath.getSetting("radius");
+	mRotationRadius = static_cast<Real>(strtod(tmp.c_str(), &errptr));
+	
+	tmp = cfDeath.getSetting("period");
+	mRotationPeriod = static_cast<Real>(strtod(tmp.c_str(), &errptr));
+
+	tmp = cfDeath.getSetting("movespeed");
+	mMoveSpeed = static_cast<Real>(strtod(tmp.c_str(), &errptr));
+
+	tmp = cfDeath.getSetting("rotatespeed");
+	mRotateSpeed = static_cast<Real>(strtod(tmp.c_str(), &errptr));
+
+	ExampleApplication::setupResources();
+}
+
+
+void KdTreeApp::createScene(void)
+{
+	Entity *deaths;
+	SceneNode *nodes;
+	std::string entName = "death";
+	std::string nodeName = "DeathNode";
+	int i, j, x, z;
+	Real planeHalf = mPlaneDim / 2;
+	Real planeThreeEights = mPlaneDim * 3 / 8;
+	Real planeSixth = mPlaneDim / 6;
+
+	// load scene from file
+	if (mSceneFiles != "")
+	{
+		// don't load the other stuff
+		loadScene(mSceneFiles);
+		//mCamera->setPosition(Vector3(830, 300, -540));
+		//mCamera->setOrientation(Quaternion(-0.3486, 0.0122, 0.9365, 0.0329));
+		mCamera->setPosition(Vector3(688, 866, 944));
+		mCamera->setOrientation(Quaternion(-0.979419, 0.201128, 0.0165594, 0.00340038));
+		mTopCam->setPosition(Vector3(1232, 3990, -1477));
+	}
+	else
+	{
+		SceneNode *anchor = mSceneMgr->getRootSceneNode()->createChildSceneNode("AnchorNode");
+		//SceneNode *grndan = anchor->createChildSceneNode("GroundAnchor");
+		SceneNode *grndan = mSceneMgr->getRootSceneNode();
+
+		if (mSelectEntities & ENT_GRID)
+		{
+			for (j = 0, z =  -(mModelCount / 2 * mModelSpacing); j < mModelCount; j++, z += mModelSpacing)
+			{
+				for (i = 0, x = -(mModelCount / 2 * mModelSpacing); i < mModelCount; i++, x += mModelSpacing) 
+				{
+					deaths = mSceneMgr->createEntity(cat(entName, i, j).c_str(),"robot.mesh");
+					if (mShadowsEnabled)
+						deaths->setCastShadows(true);
+					nodes = /*mSceneMgr->getRootSceneNode()*/anchor->createChildSceneNode(cat(nodeName, i, j).c_str(), Vector3(x, 0 , z));
+					nodes->attachObject(deaths);
+				}
+			}
+		}
+
+		if (mSelectEntities & ENT_RND)
+		{
+			entName = "randomdeath";
+			nodeName = "RandomDeathNode";
+			for (i = 0; i < mRandomCount; i++)
+			{
+				Vector3 pos(
+					Math::RangeRandom(-planeHalf,-planeSixth), 
+					0, 
+					Math::RangeRandom(-planeThreeEights, planeThreeEights));
+				deaths = mSceneMgr->createEntity(cat(entName,666,i),"robot.mesh");
+				if (mShadowsEnabled)
+					deaths->setCastShadows(true);
+				nodes = /*mSceneMgr->getRootSceneNode()*/anchor->createChildSceneNode(cat(nodeName,666,i), pos,
+					Quaternion(Radian(Math::RangeRandom(-Math::PI, Math::PI)), Vector3::UNIT_Y));
+				nodes->attachObject(deaths);
+			}
+		}
+
+		if (mSelectEntities & ENT_SPC)
+		{
+			entName = "randomspaceship";
+			nodeName = "RandomSpaceshipNode";
+			for (i = 0; i < mRandomCount; i++)
+			{
+				Vector3 pos(
+					//Math::RangeRandom(-planeHalf,-planeSixth), 
+					Math::RangeRandom(planeSixth,planeHalf), 
+					Math::RangeRandom(planeHalf * 0.1, planeHalf), 
+					Math::RangeRandom(-planeThreeEights, planeThreeEights));
+				deaths = mSceneMgr->createEntity(cat(entName,666,i),"razor.mesh");
+				if (mShadowsEnabled)
+					deaths->setCastShadows(true);
+				nodes = /*mSceneMgr->getRootSceneNode()*/anchor->createChildSceneNode(cat(nodeName,666,i), pos,
+					Quaternion(Radian(Math::RangeRandom(-Math::PI, Math::PI)), Vector3::UNIT_Y));
+				nodes->attachObject(deaths);
+			}
+		}
+
+		if (mSelectEntities & ENT_MOV)
+		{
+			Entity *movingDeath = mSceneMgr->createEntity("movingDeath","robot.mesh");
+			if (mShadowsEnabled)
+				movingDeath->setCastShadows( true );
+
+			SceneNode *deathPivotNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("deathPivotNode");
+			mDeathNode = deathPivotNode->createChildSceneNode("movingNode", Vector3(0, 0, mRotationRadius)/*,
+				Quaternion(Radian(Math::HALF_PI), Vector3::UNIT_Y)*/);
+			mDeathNode->attachObject(movingDeath);
+
+			Entity *ent_ball = mSceneMgr->createEntity("ball","sphere.mesh");
+			SceneNode *node_pivot = mDeathNode->createChildSceneNode("pivotNode");
+			SceneNode *node_ball = node_pivot->createChildSceneNode("orbitNode", Vector3(120, 40, 0));
+			node_ball->attachObject(ent_ball);
+			node_ball->scale(0.1, 0.1, 0.1);
+			
+
+			mFollowCam->setAutoTracking(true, mDeathNode);
+		}
+		
+		if (mSelectEntities & ENT_PLN)
+		{
+			Plane ground(Vector3::UNIT_Y, 0);
+			MeshManager::getSingleton().createPlane("ground", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, 
+				ground, mPlaneDim * 4 / 3, mPlaneDim, 20, 20, true, 1, 20, 20, Vector3::UNIT_Z);
+			Entity *ent_ground = mSceneMgr->createEntity("GroundEntity", "ground");
+			ent_ground->setCastShadows(false);
+			ent_ground->setMaterialName("Examples/RustySteel");//("Examples/Rockwall");
+			SceneNode *node_ground = /*mSceneMgr->getRootSceneNode()*/grndan->createChildSceneNode("GroundNode", Vector3(0, 0, 0));
+			node_ground->attachObject(ent_ground);
+
+			//MeshManager::getSingleton().createPlane("ground2", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, 
+			//	ground, mPlaneDim/2, mPlaneDim, 10, 20, true, 1, 10, 20, Vector3::UNIT_Z);
+			//ent_ground = mSceneMgr->createEntity("GroundEntity2", "ground2");
+			//ent_ground->setCastShadows(false);
+			//ent_ground->setMaterialName("Examples/RustySteel");
+			//node_ground = /*mSceneMgr->getRootSceneNode()*/grndan->createChildSceneNode("GroundNode2", Vector3(-mPlaneDim/4, 0, 0));
+			//node_ground->attachObject(ent_ground);
+		}
+
+		// Lights
+		mSceneMgr->setAmbientLight(ColourValue(0.1,0.1,0.1));
+		Light *light = mSceneMgr->createLight("light");
+		if (mShadowsEnabled)
+		{
+			mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_ADDITIVE);
+			light->setType(Light::LT_POINT);
+			light->setPosition(Vector3(x, 300, z + 200));
+		}
+		else
+		{
+			light->setType(Light::LT_DIRECTIONAL);
+			light->setDirection(-1,-1,-1);
+		}
+		light->setDiffuseColour(ColourValue());
+		light->setSpecularColour(ColourValue(1, 1, 0.2));
+
+		// Skybox
+		// mSceneMgr->setSkyBox(true, "Examples/SpaceSkyBox", mPlaneDim * 2);
+	
+	}
+
+	/* Some math tests
+	Plane planeX(Vector3::UNIT_X, Vector3(10,10,10));
+	Plane planeY(Vector3::UNIT_Y, Vector3(10,10,10));
+	Plane planeZ(Vector3::UNIT_Z, Vector3(10,10,10));
+	Vector3 vect(20,20,20);
+	Vector3 interX = planeX.projectVector(vect);
+	Vector3 interY = planeY.projectVector(vect);
+	Vector3 interZ = planeZ.projectVector(vect);
+	std::stringstream ssX, ssY, ssZ;
+	ssX << "The intersection of " << planeX << " and " << vect << " is at: " << interX;
+	ssY << "The intersection of " << planeY << " and " << vect << " is at: " << interY;
+	ssZ << "The intersection of " << planeZ << " and " << vect << " is at: " << interZ;
+	LogManager::getSingleton().logMessage(ssX.str());
+	LogManager::getSingleton().logMessage(ssY.str());
+	LogManager::getSingleton().logMessage(ssZ.str());
+	*/
+}
+
+void KdTreeApp::createFrameListener(void)
+{
+	mFrameListener = new KdTreeAppListener(mWindow, mSceneMgr, mRotateSpeed, mMoveSpeed, mRotationPeriod);
+	mFrameListener->showDebugOverlay( true );
+	mRoot->addFrameListener(mFrameListener);
+}
+
+void KdTreeApp::chooseSceneManager(void)
+{
+	// Get the SceneManager
+	mSceneMgr = mRoot->createSceneManager(mSelectedSceneManager,"MySceneManager");
+}
+
+void KdTreeApp::createCamera(void)
+{
+    // Create the camera
+    mCamera = mSceneMgr->createCamera("PlayerCam");
+
+    // Position it at 500 in Z direction
+    //mCamera->setPosition(Vector3(0,50,500));
+	//mCamera->setPosition(Vector3(500,256,666));
+	mCamera->setPosition(Vector3(1280,600,1666));
+    // Look back along -Z
+    //mCamera->lookAt(Vector3(0,50,-300));
+	mCamera->lookAt(Vector3(-20,30,10));
+    mCamera->setNearClipDistance(5);
+
+	mFollowCam = mSceneMgr->createCamera("FollowCam");
+	mFollowCam->setPosition(Vector3(800,150,800));
+	mFollowCam->setNearClipDistance(5);
+	mFollowCam->setFOVy(Angle(15));
+
+	mTopCam = mSceneMgr->createCamera("TopCam");
+	mTopCam->setPosition(Vector3(0,mPlaneDim * 1.25,0));
+	mTopCam->setDirection(0,0,-1);
+	mTopCam->pitch(Radian(-Math::HALF_PI));
+	mTopCam->setCullingFrustum(mCamera);
+	//mTopCam->setProjectionType(PT_ORTHOGRAPHIC);
+	//mTopCam->lookAt(Vector3(0,0,0));
+}
+
+void KdTreeApp::createViewports(void)
+{
+    // Create one viewport, entire window
+    Viewport* vp = mWindow->addViewport(mCamera);
+    vp->setBackgroundColour(ColourValue(0,0,100));
+
+    // Alter the camera aspect ratio to match the viewport
+    mCamera->setAspectRatio(
+        Real(vp->getActualWidth()) / Real(vp->getActualHeight()));
+/*
+	Viewport* fvp = mWindow->addViewport(mFollowCam,2,0.75,0.75,0.25,0.25);
+	fvp->setBackgroundColour(ColourValue(100,0,0));
+	fvp->setOverlaysEnabled( false );
+
+	mFollowCam->setAspectRatio(
+		Real(fvp->getActualWidth()) / Real(fvp->getActualHeight()));
+*/
+}
+
+bool KdTreeApp::configure(void)
+{
+    // Show the configuration dialog and initialise the system
+    // You can skip this and use root.restoreConfig() to load configuration
+    // settings if you were sure there are valid ones saved in ogre.cfg
+#ifdef KDTREE_FASTSTART
+    if(mRoot->restoreConfig())
+#else
+	if(mRoot->showConfigDialog())
+#endif
+    {
+        // If returned true, user clicked OK so initialise
+        // Here we choose to let the system create a default rendering window by passing 'true'
+        mWindow = mRoot->initialise(true);
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+
+//-----------------------------------------------------------------------
+// splits strings containing multiple file names
+static int splitFilenames(const std::string str, std::vector<std::string> &filenames)
+{
+	int pos = 0;
+
+	while(1) 
+	{
+		int npos = (int)str.find(';', pos);
+
+		if (npos < 0 || npos - pos < 1)
+			break;
+		filenames.push_back(std::string(str, pos, npos - pos));
+		pos = npos + 1;
+	}
+
+	filenames.push_back(std::string(str, pos, str.size() - pos));
+	return (int)filenames.size();
+}
+
+bool KdTreeApp::loadScene(const String &filename)
+{
+	// use leaf nodes of the original spatial hierarchy as occludees
+	std::vector<std::string> filenames;
+	int files = splitFilenames(filename, filenames);
+
+	std::stringstream d;
+	d << "number of input files: " << files << "\n";
+	LogManager::getSingleton().logMessage(d.str());
+
+	bool result = false;
+	std::vector<std::string>::const_iterator fit, fit_end = filenames.end();
+	int i = 0;
+	// root for different files
+	for (fit = filenames.begin(); fit != fit_end; ++ fit, ++ i)
+	{
+		const std::string fn = *fit;
+
+		if (strstr(fn.c_str(), ".iv") || strstr(fn.c_str(), ".wrl"))
+		{
+			// hack: set postion manually for vienna
+			//mCamNode->setPosition(Vector3(830, 300, -540));
+			//mCamNode->setOrientation(Quaternion(-0.3486, 0.0122, 0.9365, 0.0329));
+
+			// load iv files
+			loadSceneIV(fn, mSceneMgr->getRootSceneNode(), i);			
+		}
+
+		result = true;
+	}
+
+
+	/*
+	if (result) 
+	{
+	int intersectables, faces;
+
+	std::stringstream d;
+	d << filename << " parsed successfully.\n"
+	<< "#NUM_OBJECTS (Total numner of objects)\n" << intersectables << "\n"
+	<< "#NUM_FACES (Total numner of faces)\n" << faces << "\n";
+	}
+	*/
+
+	return result;
+}
+
+//-----------------------------------------------------------------------
+bool KdTreeApp::loadSceneIV(const String &filename, SceneNode *root, const int index)
+{
+	IVReader * mIVReader = new IVReader();
+
+	if (1)
+	{
+		String logFilename = "IVLog" + Ogre::StringConverter().toString(index) + ".log";
+
+		Log *log = LogManager::getSingleton().createLog(logFilename);
+		mIVReader->setLog(log);
+	}
+
+	//viennaNode->translate(Vector3(-300, -300, 0));
+
+	if (mIVReader->loadFile(filename.c_str()))
+	{
+		SceneNode *node = root->createChildSceneNode("IVSceneNode" + index);
+
+		mIVReader->buildTree(mSceneMgr, node);
+
+		mIVReader->collapse();
+		OGRE_DELETE(mIVReader);
+
+		return true;
+	}
+
+	return false;
+}
Index: /GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TestCullingTerrain.vcproj
===================================================================
--- /GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TestCullingTerrain.vcproj	(revision 1158)
+++ /GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TestCullingTerrain.vcproj	(revision 1163)
@@ -30,5 +30,5 @@
 				WarningLevel="3"
 				Detect64BitPortabilityProblems="TRUE"
-				DebugInformationFormat="4"/>
+				DebugInformationFormat="3"/>
 			<Tool
 				Name="VCCustomBuildTool"/>
@@ -85,8 +85,8 @@
 			<Tool
 				Name="VCLinkerTool"
-				AdditionalDependencies="OGREMain.LIB CEGUIBase.lib OgreGUIRenderer.lib Plugin_OctreeSceneManager.lib Plugin_VisibilitySceneManager.lib IVReader.lib zdll.lib zziplib.lib Plugin_Collada.lib xerces-c_2.lib"
+				AdditionalDependencies="OGREMain.LIB CEGUIBase.lib OgreGUIRenderer.lib Plugin_OctreeSceneManager.lib Plugin_VisibilitySceneManager.lib IVReader.lib zdll.lib zziplib.lib xerces-c_2.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;;..\..\..\..\..\Lib\Vis\OnlineCullingCHC\lib;&quot;..\..\..\..\..\Lib\Vis\OnlineCullingCHC\OGRE\lib\$(ConfigurationName)&quot;;&quot;..\..\..\..\..\Lib\Vis\OnlineCullingCHC\IVReader\lib\$(ConfigurationName)&quot;;d:\work\Collada\bin\release;..\..\..\..\..\..\..\NonGTP\Xerces\xercesc\lib"
+				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;;..\..\..\..\..\Lib\Vis\OnlineCullingCHC\lib;&quot;..\..\..\..\..\Lib\Vis\OnlineCullingCHC\OGRE\lib\$(ConfigurationName)&quot;;&quot;..\..\..\..\..\Lib\Vis\OnlineCullingCHC\IVReader\lib\$(ConfigurationName)&quot;;..\..\..\..\..\..\..\NonGTP\Xerces\xercesc\lib"
 				GenerateDebugInformation="TRUE"
 				SubSystem="2"
Index: /GTP/trunk/Lib/Vis/OnlineCullingCHC/scripts/GtpVisibility.vcproj
===================================================================
--- /GTP/trunk/Lib/Vis/OnlineCullingCHC/scripts/GtpVisibility.vcproj	(revision 1002)
+++ /GTP/trunk/Lib/Vis/OnlineCullingCHC/scripts/GtpVisibility.vcproj	(revision 1163)
@@ -29,5 +29,5 @@
 				WarningLevel="3"
 				Detect64BitPortabilityProblems="TRUE"
-				DebugInformationFormat="4"/>
+				DebugInformationFormat="3"/>
 			<Tool
 				Name="VCCustomBuildTool"/>
Index: /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/include/OgreKdTree.h
===================================================================
--- /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/include/OgreKdTree.h	(revision 1163)
+++ /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/include/OgreKdTree.h	(revision 1163)
@@ -0,0 +1,414 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of the GameTools Project
+http://www.gametools.org
+
+Author: Martin Szydlowski
+-----------------------------------------------------------------------------
+*/
+
+#ifndef _OgreKdTree_H__
+#define _OgreKdTree_H__
+
+#include <OgreAxisAlignedBox.h>
+#include <OgreWireBoundingBox.h>
+#include <OgrePlane.h>
+#include <OgreVector3.h>
+
+#include <OgreRoot.h>
+
+#include <stack>
+
+namespace Ogre
+{
+	class KdRenderable;
+	struct SplitInfo;
+
+	class PlaneEvent
+	{
+	public:
+		enum Type
+		{
+			PET_END,
+			PET_ON,
+			PET_START
+		};
+
+		enum Dimension
+		{
+			PED_X,
+			PED_Y,
+			PED_Z
+		};
+
+		enum Side
+		{
+			PES_LEFT = 0x01,
+			PES_RIGHT = 0x02,
+			PES_BOTH = PES_LEFT | PES_RIGHT
+		};
+
+		PlaneEvent(): mRenderable(0), mPosition(Vector3()), mDimension(PED_X), mType(PET_ON)
+		{ };
+
+		PlaneEvent(KdRenderable *rend, const Vector3& pos, PlaneEvent::Dimension dim, PlaneEvent::Type type):
+			mRenderable(rend), mPosition(pos), mDimension(dim), mType(type) 
+		{ };
+
+		~PlaneEvent() {};
+
+		// the less operator for plane events
+		// first sort by position, then by dimension and finally by type
+		bool operator < (const PlaneEvent& e) const
+		{
+			if(mPosition[mDimension] < e.mPosition[e.mDimension])
+			{
+				return true;
+			}
+
+			if(mPosition[mDimension] == e.mPosition[e.mDimension])
+			{
+				if (mDimension < e.mDimension)
+				{
+					return true;
+				}
+				if (mDimension == e.mDimension)
+				{
+					if (mType < e.mType)
+					{
+						return true;
+					}
+				}
+			}
+
+			return false;
+		};
+
+		// the equals operator for tree events
+		bool operator == (const PlaneEvent& e) const
+		{
+			return	(mPosition[mDimension] == e.mPosition[e.mDimension]) &&
+				(mDimension == e.mDimension) &&
+				(mType == e.mType);
+		};
+
+		bool equalsType(const PlaneEvent& e, PlaneEvent::Type t)
+		{
+			return	(mPosition[mDimension] == e.mPosition[e.mDimension]) &&
+				(mDimension == e.mDimension) &&
+				(mType == t);
+		};
+
+		void classify(const PlaneEvent& e, PlaneEvent::Side side);
+
+		PlaneEvent clip(AxisAlignedBox& box, PlaneEvent::Dimension dim);
+
+		Plane * getSplitPlane() const
+		{
+			Vector3 normal(0,0,0);
+			normal[mDimension] = 1;
+			return new Plane(normal, mPosition);
+		}
+
+		KdRenderable * getRenderable() const //??
+		{
+			return mRenderable;
+		};
+
+		PlaneEvent::Dimension getDimension() const //??
+		{
+			return mDimension;
+		};
+
+		// DEBUG
+		String print();
+	protected:
+		// event info
+		KdRenderable *			mRenderable;
+		Vector3					mPosition;
+		PlaneEvent::Dimension	mDimension;
+		PlaneEvent::Type		mType;
+
+		// ------------------------------------------------------------------------------//
+		// functions to determine the cost of splitting the node parent with the plane
+		// represented by this event
+		// TODO discuss if these functions really belong here, OO & SE - wise
+		// pros: convenient, don't have to pass internal data to the outside
+		// cons: SplitInfo ... 
+	public:
+		// compute "global" surface area heuristic (SAH) for the plane represented by this event
+		// use only with priority queue build method
+		void pqSAH(Real globalSA, Real parentSA, int nLeft, int nPlane, int nRight, AxisAlignedBox& parentBox, SplitInfo& split);
+		static Real pqSplitCost(Real p, Real pl, Real pr, int nLeft, int nRight, Real mu);
+
+		// compute the surface area heuristic (SAH) for the plane represented by this event
+		void SAH(const AxisAlignedBox& parent, int nLeft, int nPlane, int nRight, SplitInfo& split);
+		// the variables determining the cost of a branch traversal (KT) and a leaf intersection (KI)
+		static Real KT;
+		static Real KI;
+		// helper functions
+		static Real splitCost(Real pl, Real pr, int nLeft, int nRight);
+		static Real splitCost(Real pl, Real pr, int nLeft, int nRight, Real mu);
+		static Real surfaceArea(const AxisAlignedBox& box);
+		static Real lookupPenalty(Real p);
+	protected:
+		Real splitBox(const AxisAlignedBox& parent, AxisAlignedBox& left, AxisAlignedBox& right);
+	};
+
+	// Holds all the important information on a split
+	struct SplitInfo
+	{
+		AxisAlignedBox bleft;
+		AxisAlignedBox bright;
+		int nleft;
+		int nright;
+		Real cost;
+		PlaneEvent::Side side;
+		PlaneEvent event;
+
+		// DEBUG
+		String print();
+	};
+
+	typedef std::list<PlaneEvent> PlaneEventList;
+	typedef std::list<KdRenderable *> KdRenderableList;
+	
+	class KdTree
+	{
+	protected:
+		class Branch;
+		class Leaf;
+
+		class Node
+		{
+		public:
+			Node(int level, AxisAlignedBox& aabb, Branch * parent):
+			mLevel(level),
+			mAABB(aabb),
+			mParent(parent),
+			mWBB(0)
+			{ };
+
+			virtual ~Node()
+			{
+				delete mWBB;
+			};
+
+			virtual bool isLeaf() const = 0;
+			virtual bool isEmpty() const = 0;
+			
+			// consider using typesafe callback functions
+			//virtual void cbInsert(KdTree * caller, KdRenderable * rend) = 0;
+
+			WireBoundingBox * getWireBoundingBox()
+			{
+				if (mWBB == 0)
+					mWBB = new WireBoundingBox();
+
+				mWBB->setupBoundingBox(mAABB);
+				
+#ifdef KDTREE_DEBUG
+				int level = -1;
+				bool boxes = false;
+				if (Root::getSingleton()._getCurrentSceneManager()->getOption("HighlightLevel",&level))
+				{
+					if (mLevel == level)
+					{
+						//mWBB->setMaterial("BaseGreenNoLighting");
+						mWBB->setMaterial("aabbHiLite");
+						return mWBB;
+					}
+					else
+					{
+						mWBB->setMaterial("BaseWhiteNoLighting");
+						if (Root::getSingleton()._getCurrentSceneManager()->getOption("ShowAllBoxes", &boxes))
+						{
+							if (boxes)
+								return mWBB;
+							else
+								return 0;
+						}
+					}
+				}
+#else
+				mWBB->setMaterial("BaseWhiteNoLighting");
+#endif // KDTREE_DEBUG
+				return mWBB;
+
+			}
+
+			Branch * mParent;
+			int mLevel;
+			AxisAlignedBox mAABB;
+		protected:
+			WireBoundingBox * mWBB;
+		};
+
+		class Branch : public Node
+		{
+		public:
+			Branch(int level, AxisAlignedBox& aabb, Branch * parent, Plane * splitplane, PlaneEvent::Side side):
+				Node(level, aabb, parent), 
+				mSplitPlane(splitplane), 
+				mLeft(0), 
+				mRight(0),
+				mPlaneSide(side)
+			{ };
+
+			virtual ~Branch()
+			{
+				delete mLeft;
+				delete mRight;
+				delete mSplitPlane;
+			};
+
+			virtual bool isLeaf() const { return false; };
+
+			virtual bool isEmpty() const { return (mLeft == 0 && mRight == 0); }
+			
+			Node * mLeft;
+			Node * mRight;
+			Plane  * mSplitPlane;
+			PlaneEvent::Side mPlaneSide;
+		};
+
+		class Leaf : public Node
+		{
+		public:
+			Leaf(int level, AxisAlignedBox& aabb, Branch * parent):
+			  Node(level, aabb, parent) 
+			{};
+
+			virtual ~Leaf();
+
+			virtual bool isLeaf() const { return true; };
+
+			virtual bool isEmpty() const { return mKdRenderables.empty(); };
+
+			virtual void remove(KdRenderable * rend)
+			{
+				mKdRenderables.remove(rend);
+				//mKdRenderables.erase(find(mKdRenderables.begin(), mKdRenderables.end(), rend));
+			};
+
+			virtual void insert(KdRenderable * rend)
+			{
+				mKdRenderables.push_back(rend);
+			};
+
+			KdRenderableList mKdRenderables;
+		};
+
+		struct SplitCandidate
+		{
+			SplitCandidate(PlaneEventList * e, int n, AxisAlignedBox& a, KdTree::Branch * p, Real c, Real d, SplitInfo * b, PlaneEvent::Side s):
+				events(e), nObjects(n), aabb(a), parent(p), cost(c), decrease(d), best(b), side(s) { };
+
+			bool operator < (const SplitCandidate& rhs) const
+			{
+				return decrease < rhs.decrease;
+			};
+
+			void operator = (const SplitCandidate& rhs)
+			{
+				decrease = rhs.decrease;
+				cost = rhs.cost;
+				nObjects = rhs.nObjects;
+				side = rhs.side;
+				aabb = rhs.aabb;
+				events = rhs.events;
+				parent = rhs.parent;
+				best = rhs.best;
+			};
+
+			// DEBUG
+			String print();
+
+			Real decrease;
+			Real cost;
+			int nObjects;
+			PlaneEvent::Side side;
+			AxisAlignedBox aabb;
+			PlaneEventList * events;
+			KdTree::Branch * parent;
+			SplitInfo * best;
+		};
+
+		//typedef std::stack<SplitCandidate> SplitCandidatePQ;
+		typedef std::priority_queue<SplitCandidate> SplitCandidatePQ;
+
+	public:
+		typedef KdTree::Leaf * LeafPtr;
+		typedef std::set<LeafPtr> LeafSet;
+
+		enum BuildMethod
+		{
+			KDBM_RECURSIVE,
+			KDBM_PRIORITYQUEUE
+		};
+		
+		KdTree(int maxdepth);
+		virtual ~KdTree();
+
+		// DEBUG
+		void KdTree::dump();
+		void KdTree::calcCost();
+
+		// insert a new scene node into an existing kd-tree
+		void insert(KdRenderable * rend);
+		// remove a scene node from the tree
+		void remove(KdRenderable * rend);
+		// function to initialize a kd-tree based on the contents of the scene
+		void build(KdRenderable * sceneRoot);
+
+		// test visibility of objects and add to render	queue
+		void queueVisibleObjects(Camera* cam, RenderQueue* queue, bool onlyShadowCasters, bool showBoxes = false);
+
+		// self-explanatory ...
+		int getMaxDepth() { return mMaxDepth; };
+		AxisAlignedBox getBox() { if (mKdRoot) return mKdRoot->mAABB; else return AxisAlignedBox(); };
+		void setBuildMethod(BuildMethod bm) { mBuildMethod = bm; }
+	protected:
+		// recursive insert funciton
+		void recInsert(KdTree::Node * node, KdRenderable * rend);
+		// helper functions for insert
+		void recInsertNew(KdTree::Branch * parent, PlaneEvent::Side side, KdRenderable * rend);
+		void splitBox(const KdTree::Branch& parent, AxisAlignedBox& left, AxisAlignedBox& right);
+		void rebuildSubtree(KdTree::Node * node, KdRenderable * rend);
+		// build scene from a list of nodes rather than a hierarchy
+		KdTree::Node * buildFromList(KdRenderableList& nodelist, KdTree::Branch * parent, AxisAlignedBox& aabb);
+		void addRendToList(KdTree::Node * node, KdRenderableList& nodelist);
+
+		// recursively delete empty nodes
+		void recDelete(KdTree::Node * node);
+
+		// find the best plane for node division
+		SplitInfo * pqFindPlane(PlaneEventList * events, int nObjects, AxisAlignedBox& aabb, Real globalSA);
+
+		// priority queue based build function
+		KdTree::Node * pqBuild(PlaneEventList& events, int nObjects, AxisAlignedBox& aabb, KdTree::Branch * parent);
+		// recursive build function
+		KdTree::Node * recBuild(PlaneEventList& events, int nObjects, AxisAlignedBox& aabb, KdTree::Branch * parent);
+
+		// recursive rendering function
+		void recQueueVisibleObjects(KdTree::Node * node, unsigned long currentFrame, Camera* cam, RenderQueue* queue, bool onlyShadowCasters, bool showBoxes);
+
+		// the root node of the kdtree
+		KdTree::Node * mKdRoot;
+		// Maximum depth of the tree
+		int mMaxDepth;
+
+		// how to build the tree
+		BuildMethod mBuildMethod;
+
+		// logfile for tree creation
+		Log * mBuildLog;
+
+		// DEBUG
+		void KdTree::dump(KdTree::Node * node);
+		Real KdTree::calcCost(KdTree::Node * node, Real vs);
+	}; // class KdTree
+
+} // namespace Ogre
+
+#endif // _OgreKdTree_H__
Index: /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/include/OgreKdRenderable.h
===================================================================
--- /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/include/OgreKdRenderable.h	(revision 1163)
+++ /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/include/OgreKdRenderable.h	(revision 1163)
@@ -0,0 +1,125 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of the GameTools Project
+http://www.gametools.org
+
+Author: Martin Szydlowski
+-----------------------------------------------------------------------------
+*/
+
+#ifndef _OgreKdRenderable_H__
+#define _OgreKdRenderable_H__
+
+#include "OgreKdTree.h"
+
+namespace Ogre
+{
+
+	// interface which must be implemented by all objects which desire to be
+	// placed in the kd-tree
+	class KdRenderable
+	{
+	public:
+		KdRenderable():mSide(PlaneEvent::PES_BOTH), mClassified(false), mLastQueued(0), mKdTree(0) {};
+		virtual ~KdRenderable()
+		{
+			if (mKdTree)
+				mKdTree->remove(this);
+		}
+
+		// gather the information required for the creation of the kd-tree
+		virtual void computeScene(PlaneEventList& events, AxisAlignedBox& aabb, int& nObjects, bool includeChildren = true) = 0;
+
+		// put all objects this element holds in the renedering queue
+		virtual void queueObjects(Camera* cam, RenderQueue* queue, bool onlyShadowCasters) = 0;
+
+		// return a bounding box enclosing all objects
+		virtual AxisAlignedBox getBoundingBox() const = 0;
+
+		// TODO: reconsider getters/setters !!!
+		inline bool isClassified()
+		{
+			return mClassified;
+		};
+		inline void setClassified(bool q)
+		{
+			mClassified = q;
+		};
+
+		inline PlaneEvent::Side getSide()
+		{
+			return mSide;
+		};
+		inline void setSide(PlaneEvent::Side s)
+		{
+			mSide = s;
+		};
+
+		// funcions for attachment/detachment of renderables to/from the kd-tree
+		inline bool isAttached()
+		{
+			return mLeaves.size() != 0;
+		};
+		// the following functions should work in O(log N)
+		inline bool isAttached(KdTree::LeafPtr leaf)
+		{
+			return mLeaves.find(leaf) != mLeaves.end();
+		};
+		inline bool attachTo(KdTree::LeafPtr leaf, KdTree * kdTree)
+		{
+			if (mKdTree == 0 || mKdTree == kdTree)
+				mKdTree = kdTree;
+			else
+				return false;
+
+			KdTree::LeafSet::_Pairib p = mLeaves.insert(leaf);
+			return p.second;
+		};
+		inline bool detachFrom(KdTree::LeafPtr leaf)
+		{
+			bool success = (mLeaves.erase(leaf) == 1);
+			if (mLeaves.size() == 0)
+				mKdTree = 0;
+
+			return success;
+		};
+
+		inline bool isQueued(unsigned long currentFrame, Camera * currentCam)
+		{
+			if (mLastQueued == currentFrame && mLastCam == currentCam)
+			{
+				return true;
+			}
+			else
+			{
+				mLastQueued = currentFrame;
+				mLastCam = currentCam;
+				return false;
+			}
+		};
+
+		KdTree::LeafSet& getLeaves()
+		{
+			return mLeaves;
+		};
+
+	protected:
+		// number of the frame in which this renderable was last queued for rendering
+		unsigned long mLastQueued;
+		// the camera for which this renderable was last queued for rendering
+		Camera * mLastCam;
+		
+		// kdtree to which this renderable is attached
+		KdTree * mKdTree;
+		// kdtree leaves which overlap this renderable
+		KdTree::LeafSet mLeaves;
+
+		// Flag for the SAH determining the "cheaper" side of the split plane
+		PlaneEvent::Side mSide;
+		// Flag for the SAH which marks if this renderable was already placed in the list after a split
+		bool mClassified;
+	}; // class KdRenderable
+
+} // namespace Ogre
+
+#endif // _OgreKdRenderable_H__
Index: /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/include/OgreKdTreeSceneManager.h
===================================================================
--- /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/include/OgreKdTreeSceneManager.h	(revision 1163)
+++ /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/include/OgreKdTreeSceneManager.h	(revision 1163)
@@ -0,0 +1,89 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of the GameTools Project
+http://www.gametools.org
+
+Author: Martin Szydlowski
+-----------------------------------------------------------------------------
+*/
+
+#ifndef _KdTreeSceneManager_H__
+#define _KdTreeSceneManager_H__
+
+#include <OgreSceneManager.h>
+#include "OgreKdTree.h"
+
+namespace Ogre
+{
+	class KdTreeSceneNode;
+	class WireBoundingBox;
+	typedef std::list < WireBoundingBox * > WBBList;
+
+	class KdTreeSceneManager : public SceneManager
+	{
+	public:
+		KdTreeSceneManager(const String& name);
+		//KdTreeSceneManager(const String& name, int maxdepth);
+		~KdTreeSceneManager(void);
+
+		virtual const String& getTypeName(void) const;
+		virtual SceneNode* createSceneNode(void);
+		virtual SceneNode* createSceneNode(const String& name);
+		void init( int maxdepth );
+		void walkTree(KdTree * node, Camera *cam);
+
+		virtual void _findVisibleObjects(Camera *cam, bool onlyShadowCasters);
+
+		virtual void setShowBoxes(bool showboxes);
+		virtual bool getShowBoxes(void) const;
+
+		virtual void _updateNode(KdTreeSceneNode *node); // TODO: 
+
+		virtual bool setOption(const String& strKey, const void* pValue);
+		virtual bool getOption(const String& strKey, void* pDestValue);
+
+		virtual void clearScene()
+		{
+			// DEBUG must happen before scene is cleared
+			// might be a solution to detach problem
+			//if (mKdTree)
+			//	mKdTree->dump();
+			
+			OGRE_DELETE(mKdTree);
+
+			SceneManager::clearScene();
+		}
+	protected:
+
+		int mMaxDepth;
+
+		KdTree *mKdTree;
+
+		bool mShowBoxes;
+
+		KdTree::BuildMethod mBuildMethod;
+#ifdef KDTREE_DEBUG
+		int mHighlighLevel;
+		bool mShowAllBoxes;
+#endif
+	};
+
+
+
+	/// Factory for KdTreeSceneManager
+	class KdTreeSceneManagerFactory : public SceneManagerFactory
+	{
+	protected:
+		void initMetaData(void) const;
+	public:
+		KdTreeSceneManagerFactory(void) {};
+		~KdTreeSceneManagerFactory(void) {};
+		/// Factory type name
+		static const String FACTORY_TYPE_NAME;
+		SceneManager* createInstance(const String& instanceName);
+		void destroyInstance(SceneManager* instance);
+	};
+
+} // namespace Ogre
+
+#endif // _KdTreeSceneManager_H__
Index: /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/include/OgreKdTreeSceneNode.h
===================================================================
--- /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/include/OgreKdTreeSceneNode.h	(revision 1163)
+++ /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/include/OgreKdTreeSceneNode.h	(revision 1163)
@@ -0,0 +1,55 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of the GameTools Project
+http://www.gametools.org
+
+Author: Martin Szydlowski
+-----------------------------------------------------------------------------
+*/
+
+#ifndef _OgreKdTreeSceneNode_H__
+#define _OgreKdTreeSceneNode_H__
+
+#include <OgreSceneNode.h>
+#include "OgreKdRenderable.h"
+
+namespace Ogre
+{
+
+	class KdTreeSceneNode : public SceneNode, public KdRenderable
+	{
+	public:
+		KdTreeSceneNode(SceneManager *creator):
+		  SceneNode(creator) {};
+
+		KdTreeSceneNode(SceneManager *creator, const String& name):
+		  SceneNode(creator, name) {};
+
+		~KdTreeSceneNode() {};
+
+		// calculate all-enclosing AABB, similar to _updateBounds()
+		void forceComputeAABB(AxisAlignedBox& aabb); // OBSOLETE !!
+
+		// gather info for kd-tree creation
+		virtual void computeScene(PlaneEventList& events, AxisAlignedBox& aabb, int& nObjects, bool includeChildren = true);
+
+		// add all contained objects to render queue
+		virtual void queueObjects(Camera* cam, RenderQueue* queue, bool onlyShadowCasters);
+
+		// return a bounding box enclosing all objects
+		virtual AxisAlignedBox getBoundingBox() const;
+
+		//virtual void _findVisibleObjects(Camera* cam, RenderQueue* queue, 
+		//	bool includeChildren = true, bool displayNodes = false, bool onlyShadowCasters = false);
+
+		// DEBUG
+		String dumpToString();
+	protected:
+		virtual void _updateBounds(void);
+
+		//AxisAlignedBox mLocalAABB;
+	};
+
+} // namespace Ogre
+
+#endif // _OgreKdTreeSceneNode_H__
Index: /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/scripts/Plugin_VisibilitySceneManager.vcproj
===================================================================
--- /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/scripts/Plugin_VisibilitySceneManager.vcproj	(revision 1159)
+++ /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/scripts/Plugin_VisibilitySceneManager.vcproj	(revision 1163)
@@ -21,5 +21,5 @@
 				Optimization="0"
 				AdditionalIncludeDirectories="&quot;$(OGRE_PATH)\PlugIns\OctreeSceneManager\include&quot;;&quot;$(OGRE_PATH)\Samples\Common\include&quot;;&quot;$(OGRE_PATH)\Dependencies\include\CEGUI&quot;;&quot;$(OGRE_PATH)\Samples\Common\CEGUIRenderer\include&quot;;&quot;$(OGRE_PATH)\OgreMain\include&quot;;&quot;$(OGRE_PATH)\Dependencies\include&quot;;..\include;..\..\..\OnlineCullingCHC\include;..\..\..\Preprocessing\src"
-				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;PLUGIN_OCCLUSIONCULLINGSCENEMANAGER_EXPORTS;GTP_VISIBILITY_MODIFIED_OGRE"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;PLUGIN_OCCLUSIONCULLINGSCENEMANAGER_EXPORTS;GTP_VISIBILITY_MODIFIED_OGRE;KDTREE_DEBUG"
 				MinimalRebuild="TRUE"
 				BasicRuntimeChecks="3"
@@ -30,5 +30,5 @@
 				WarningLevel="3"
 				Detect64BitPortabilityProblems="TRUE"
-				DebugInformationFormat="4"/>
+				DebugInformationFormat="3"/>
 			<Tool
 				Name="VCCustomBuildTool"/>
@@ -36,10 +36,10 @@
 				Name="VCLinkerTool"
 				IgnoreImportLibrary="TRUE"
-				AdditionalDependencies="OgreMain_d.lib CEGUIBase_d.lib OgreGUIRenderer_d.lib Plugin_OctreeSceneManager.lib GtpVisibility.lib zdll.lib zziplibd.lib Preprocessor.lib devil.lib glut32.lib xerces-c_2.lib OpenGL32.Lib glu32.lib cg.lib cgGL.lib glew32.lib qtmain.lib QtOpenGLd4.lib QtCored4.lib QtGuid4.lib Qt3Supportd4.lib QAxContainer.lib"
+				AdditionalDependencies="OgreMain_d.lib CEGUIBase_d.lib OgreGUIRenderer_d.lib Plugin_OctreeSceneManager.lib GtpVisibility.lib zdll.lib zziplibd.lib Preprocessor.lib devil.lib glut32.lib xerces-c_2D.lib OpenGL32.Lib glu32.lib cg.lib cgGL.lib glew32.lib"
 				OutputFile="$(OutDir)/Plugin_VisibilitySceneManager.dll"
 				Version="0.99"
 				LinkIncremental="1"
 				SuppressStartupBanner="TRUE"
-				AdditionalLibraryDirectories="&quot;$(OGRE_PATH)\OgreMain\lib\$(ConfigurationName)&quot;;&quot;$(OGRE_PATH)\Dependencies\lib\$(ConfigurationName)&quot;;&quot;$(OGRE_PATH)\PlugIns\OctreeSceneManager\bin\$(ConfigurationName)&quot;;&quot;$(OGRE_PATH)\Samples\Common\CEGUIRenderer\lib&quot;;&quot;..\lib\$(ConfigurationName)&quot;;&quot;..\..\lib\$(ConfigurationName)&quot;;&quot;..\..\..\Preprocessing\lib\$(ConfigurationName)&quot;;..\..\..\Preprocessing\src\GL;..\..\..\..\..\..\..\NonGTP\Xerces\xercesc\lib;&quot;$(QTDIR)\lib&quot;;&quot;$(CG_LIB_PATH)&quot;"
+				AdditionalLibraryDirectories="&quot;$(OGRE_PATH)\OgreMain\lib\$(ConfigurationName)&quot;;&quot;$(OGRE_PATH)\Dependencies\lib\$(ConfigurationName)&quot;;&quot;$(OGRE_PATH)\PlugIns\OctreeSceneManager\bin\$(ConfigurationName)&quot;;&quot;$(OGRE_PATH)\Samples\Common\CEGUIRenderer\lib&quot;;&quot;..\lib\$(ConfigurationName)&quot;;&quot;..\..\lib\$(ConfigurationName)&quot;;&quot;..\..\..\Preprocessing\lib\$(ConfigurationName)&quot;;..\..\..\Preprocessing\src\GL;..\..\..\..\..\..\..\NonGTP\Xerces\xercesc\lib;&quot;$(CG_LIB_PATH)&quot;"
 				ModuleDefinitionFile="..\misc\OgreVisibilitySceneManager.def"
 				GenerateDebugInformation="TRUE"
@@ -89,5 +89,5 @@
 				OptimizeForProcessor="2"
 				AdditionalIncludeDirectories="&quot;$(OGRE_PATH)\PlugIns\OctreeSceneManager\include&quot;;&quot;$(OGRE_PATH)\Samples\Common\include&quot;;&quot;$(OGRE_PATH)\Dependencies\include\CEGUI&quot;;&quot;$(OGRE_PATH)\Samples\Common\CEGUIRenderer\include&quot;;&quot;$(OGRE_PATH)\OgreMain\include&quot;;&quot;$(OGRE_PATH)\Dependencies\include&quot;;..\include;..\..\..\OnlineCullingCHC\include;..\..\..\Preprocessing\src"
-				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;GTP_VISIBILITY_MODIFIED_OGRE"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;GTP_VISIBILITY_MODIFIED_OGRE;KDTREE_DEBUG"
 				StringPooling="TRUE"
 				RuntimeLibrary="2"
@@ -104,5 +104,5 @@
 				Name="VCLinkerTool"
 				IgnoreImportLibrary="TRUE"
-				AdditionalDependencies="OgreMain.lib CEGUIBase.lib OgreGUIRenderer.lib Plugin_OctreeSceneManager.lib GtpVisibility.lib zdll.lib zziplib.lib Preprocessor.lib xerces-c_2.lib devil.lib qtmain.lib QtOpenGL4.lib QtCore4.lib QtGui4.lib Qt3Support4.lib QAxContainer.lib glut32.lib OpenGL32.Lib glu32.lib cg.lib cgGL.lib glew32.lib glew32s.lib"
+				AdditionalDependencies="OgreMain.lib CEGUIBase.lib OgreGUIRenderer.lib Plugin_OctreeSceneManager.lib GtpVisibility.lib zdll.lib zziplib.lib Preprocessor.lib xerces-c_2.lib devil.lib glut32.lib OpenGL32.Lib glu32.lib cg.lib cgGL.lib glew32.lib glew32s.lib"
 				OutputFile="$(OutDir)/Plugin_VisibilitySceneManager.dll"
 				Version="0.99"
@@ -260,4 +260,37 @@
 			</Filter>
 		</Filter>
+		<Filter
+			Name="KdTreeSceneManager"
+			Filter="">
+			<Filter
+				Name="Header Files"
+				Filter="">
+				<File
+					RelativePath="..\include\OgreKdRenderable.h">
+				</File>
+				<File
+					RelativePath="..\include\OgreKdTree.h">
+				</File>
+				<File
+					RelativePath="..\include\OgreKdTreeSceneManager.h">
+				</File>
+				<File
+					RelativePath="..\include\OgreKdTreeSceneNode.h">
+				</File>
+			</Filter>
+			<Filter
+				Name="Source Files"
+				Filter="">
+				<File
+					RelativePath="..\src\OgreKdTree.cpp">
+				</File>
+				<File
+					RelativePath="..\src\OgreKdTreeSceneManager.cpp">
+				</File>
+				<File
+					RelativePath="..\src\OgreKdTreeSceneNode.cpp">
+				</File>
+			</Filter>
+		</Filter>
 		<File
 			RelativePath=".\VTune\Plugin_VisibilitySceneManager.vpj">
Index: /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreKdTreeSceneManager.cpp
===================================================================
--- /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreKdTreeSceneManager.cpp	(revision 1163)
+++ /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreKdTreeSceneManager.cpp	(revision 1163)
@@ -0,0 +1,328 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of the GameTools Project
+http://www.gametools.org
+
+Author: Martin Szydlowski
+-----------------------------------------------------------------------------
+*/
+
+#include <OgreCamera.h>
+#include "OgreKdTreeSceneManager.h"
+#include "OgreKdTreeSceneNode.h"
+#include "OgreKdTree.h"
+
+#include <OgreLogManager.h>
+#include <OgreStringConverter.h>
+
+namespace Ogre
+{
+	KdTreeSceneManager::KdTreeSceneManager(const String& name):
+		SceneManager(name)
+	{
+		int maxdepth = 20;
+		mKdTree = 0;
+		init(maxdepth);
+	}
+
+	KdTreeSceneManager::~KdTreeSceneManager(void)
+	{
+		delete mKdTree;
+	}
+
+	const String& KdTreeSceneManager::getTypeName(void) const
+	{
+		return KdTreeSceneManagerFactory::FACTORY_TYPE_NAME;
+	}
+
+	void KdTreeSceneManager::init(int maxdepth)
+	{
+		// Replace root node with my node
+		OGRE_DELETE(mSceneRoot);
+
+		mSceneRoot = new KdTreeSceneNode(this, "root node");
+		mSceneRoot->_notifyRootNode();
+
+		mMaxDepth = maxdepth;
+		mShowBoxes = false;
+
+		// kill the old kd-tree if exists 
+		OGRE_DELETE(mKdTree);
+
+		mBuildMethod = KdTree::KDBM_RECURSIVE;
+		//mBuildMethod = KdTree::KDBM_PRIORITYQUEUE;
+#ifdef KDTREE_DEBUG
+		mHighlighLevel = 0;
+		mShowAllBoxes = false;
+#endif
+	}
+
+	void KdTreeSceneManager::setShowBoxes(bool showboxes)
+	{
+		mShowBoxes = showboxes;
+	}
+
+	bool KdTreeSceneManager::getShowBoxes(void) const
+	{
+		return mShowBoxes;
+	}
+
+	bool KdTreeSceneManager::setOption(const String& strKey, const void* pValue)
+	{
+		// change max depth of the kdtree
+		// rebuild the tree if already exists
+		if (strKey == "KdTreeMaxDepth")
+		{
+			int maxdepth = *static_cast<const int *>(pValue);
+
+			// no negative depth, plz!
+			if (maxdepth < 0)
+			{
+				return false;
+			}
+			else
+			{
+				mMaxDepth = maxdepth;
+#ifdef KDTREE_DEBUG
+				if (mHighlighLevel > mMaxDepth)
+					mHighlighLevel = mMaxDepth;
+#endif
+				return true;
+			}
+			return true;
+		}
+		else if (strKey == "KT")
+		{
+			Real kt = *static_cast<const Real *>(pValue);
+			if (kt > 0)
+			{
+				PlaneEvent::KT = kt;
+				return true;
+			}
+			else
+			{
+				return false;
+			}
+		}
+		else if (strKey == "KI")
+		{
+			Real ki = *static_cast<const Real *>(pValue);
+			if (ki > 0)
+			{
+				PlaneEvent::KI = ki;
+				return true;
+			}
+			else
+			{
+				return false;
+			}
+		}
+		else if (strKey == "RebuildKdTree")
+		{
+			OGRE_DELETE(mKdTree);
+			mKdTree = new KdTree(mMaxDepth);
+			mKdTree->setBuildMethod(mBuildMethod);
+			mKdTree->build(static_cast<KdTreeSceneNode *>(mSceneRoot));
+			return true;
+		}
+#ifdef KDTREE_DEBUG
+		else if (strKey == "HighlightLevel")
+		{
+			int hl = *static_cast<const int *>(pValue);
+			if (hl >= 0 && hl <= mMaxDepth)
+			{
+				mHighlighLevel = hl;
+				return true;
+			}
+			else
+			{
+				return false;
+			}
+		}
+		else if (strKey == "ShowAllBoxes")
+		{
+			bool sa = *static_cast<const bool *>(pValue);
+			mShowAllBoxes = sa;
+			return true;
+		}
+#endif
+		else if (strKey == "BuildMethod")
+		{
+			String bm = *static_cast<const String *>(pValue);
+			if (bm == "PriorityQueue")
+			{
+				mBuildMethod = KdTree::KDBM_PRIORITYQUEUE;
+				return true;
+			}
+			else if (bm == "Recursive")
+			{
+				mBuildMethod = KdTree::KDBM_RECURSIVE;
+				return true;
+			}
+			else
+			{
+				return false;
+			}
+		}
+		else if (strKey == "ShowKdTree")
+		{
+			bool sk = *static_cast<const bool *>(pValue);
+			mShowBoxes = sk;
+			return true;
+		}
+
+		return SceneManager::setOption(strKey, pValue);
+	}
+
+	bool KdTreeSceneManager::getOption(const String& strKey, void* pDestValue)
+	{
+		if (strKey == "KdTreeMaxDepth")
+		{
+			*static_cast<int *>(pDestValue) = mMaxDepth;
+			return true;
+		}
+		else if (strKey == "KT")
+		{
+			*static_cast<Real *>(pDestValue) = PlaneEvent::KT;
+			return true;
+		}
+		else if (strKey == "KI")
+		{
+			*static_cast<Real *>(pDestValue) = PlaneEvent::KI;
+			return true;
+		}
+#ifdef KDTREE_DEBUG
+		else if (strKey == "HighlightLevel")
+		{
+			*static_cast<int *>(pDestValue) = mHighlighLevel;
+			return true;
+		}
+		else if (strKey == "ShowAllBoxes")
+		{
+			*static_cast<bool *>(pDestValue) = mShowAllBoxes;
+			return true;
+		}
+#endif
+		else if (strKey == "BuildMethod")
+		{
+			if (mBuildMethod == KdTree::KDBM_PRIORITYQUEUE)
+			{
+				*static_cast<String *>(pDestValue) = "PriorityQueue";
+			}
+			else if (mBuildMethod == KdTree::KDBM_RECURSIVE)
+			{
+				*static_cast<String *>(pDestValue) = "Recursive";
+			}
+			return true;
+		}
+		else if (strKey == "TreeBox")
+		{
+			if (mKdTree)
+				*static_cast<AxisAlignedBox *>(pDestValue) = mKdTree->getBox();
+			else
+				*static_cast<AxisAlignedBox *>(pDestValue) = AxisAlignedBox();
+		}
+
+		return SceneManager::getOption(strKey, pDestValue);
+	}
+
+	SceneNode* KdTreeSceneManager::createSceneNode(void)
+	{
+		SceneNode* sn = new KdTreeSceneNode(this);
+		assert(mSceneNodes.find(sn->getName()) == mSceneNodes.end());
+		mSceneNodes[sn->getName()] = sn;
+		return sn;
+	}
+
+	SceneNode* KdTreeSceneManager::createSceneNode(const String& name)
+	{
+		// Check name not used
+		if (mSceneNodes.find(name) != mSceneNodes.end())
+		{
+			OGRE_EXCEPT(
+				Exception::ERR_DUPLICATE_ITEM,
+				"A scene node with the name " + name + " already exists",
+				"KdTreeSceneManager::createSceneNode" );
+		}
+
+		SceneNode* sn = new KdTreeSceneNode(this, name);
+		mSceneNodes[sn->getName()] = sn;
+		return sn;
+	}
+
+	// make sure it's called only for non-empty nodes .. avoids one uneccessary funciton call
+	void KdTreeSceneManager::_updateNode(KdTreeSceneNode *node)
+	{
+		//LogManager::getSingleton().logMessage("### _updateNode called for " + node->getName());
+
+		/* Rebuild kdtree when it was wiped out
+		 * Usually this happens only before the first frame
+		 * The initial AABB shall enclose all objects present
+		 * in the scene at the time of construction
+		 * TODO: find a more appropriate place for it,
+		 * e.g., before the first render call
+		 * teh stupid thing is I can't find any other place so far ...
+		 */
+		if (!mKdTree)
+		{
+			mKdTree = new KdTree(mMaxDepth);
+			mKdTree->setBuildMethod(mBuildMethod);
+			mKdTree->build(static_cast<KdTreeSceneNode *>(mSceneRoot));
+		}
+
+		// if the node is in the tree and _updateNode was called, then the node was moved/rotated/resized/wahtever
+		if (node->isAttached())
+		{
+			// TEST: perfomance when adding & removing for every frame
+			//mKdTree->remove(node);
+			//mKdTree->insert(node);
+		}
+		// there's a new node in town ... 
+		else
+		{			
+			// inserting single nodes yields sub-optimal results
+			// rebuilding tree takes too long
+			// "What now", spoke Zeus ...
+
+			//mKdTree->insert(node);
+			
+			//delete mKdTree;
+			//mKdTree = new KdTree(mMaxDepth);
+			//mKdTree->build(static_cast<KdTreeSceneNode *>(mSceneRoot));
+		}
+
+	}
+
+	void KdTreeSceneManager::_findVisibleObjects(Camera *cam, bool onlyShadowCasters)
+	{
+		getRenderQueue()->clear();
+		if (mKdTree)
+			mKdTree->queueVisibleObjects(cam, getRenderQueue(), onlyShadowCasters, mShowBoxes);
+		//SceneManager::_findVisibleObjects(cam, onlyShadowCasters);
+	}
+
+	//-----------------------------------------------------------------------
+	//-----------------------------------------------------------------------
+	const String KdTreeSceneManagerFactory::FACTORY_TYPE_NAME = "KdTreeSceneManager";
+	//-----------------------------------------------------------------------
+	void KdTreeSceneManagerFactory::initMetaData(void) const
+	{
+		mMetaData.typeName = FACTORY_TYPE_NAME;
+		mMetaData.description = "Scene manager that organises the scene based on a kd-tree";
+		mMetaData.sceneTypeMask = ST_GENERIC; // support generic scenes (so far)
+		mMetaData.worldGeometrySupported = false;
+	}
+	//-----------------------------------------------------------------------
+	SceneManager* KdTreeSceneManagerFactory::createInstance(
+		const String& instanceName)
+	{
+		return new KdTreeSceneManager(instanceName);
+	}
+	//-----------------------------------------------------------------------
+	void KdTreeSceneManagerFactory::destroyInstance(SceneManager* instance)
+	{
+		delete instance;
+	}
+
+} // namespace Ogre
+
Index: /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreVisibilitySceneManagerDll.cpp
===================================================================
--- /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreVisibilitySceneManagerDll.cpp	(revision 1153)
+++ /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreVisibilitySceneManagerDll.cpp	(revision 1163)
@@ -26,4 +26,5 @@
 //#include <OgreVisibilityTerrainSceneManager.h>
 #include <OgreOcclusionCullingSceneManager.h>
+#include <OgreKdTreeSceneManager.h>
 
 //#include <OgreHeightmapTerrainPageSource.h>
@@ -41,4 +42,5 @@
 //VisibilityTerrainSceneManagerFactory *visibilityTerrainPlugin;
 OcclusionCullingSceneManagerFactory *occlusionCullingPlugin;
+KdTreeSceneManagerFactory *kdTreeFactory;
 
 //-----------------------------------------------------------------------
@@ -52,4 +54,5 @@
 	//visibilityTerrainPlugin = new VisibilityTerrainSceneManagerFactory(visManager);
 	occlusionCullingPlugin = new OcclusionCullingSceneManagerFactory(visManager);
+	kdTreeFactory = new KdTreeSceneManagerFactory();
 	// Construct listener manager singleton
 	new TerrainPageSourceListenerManager();
@@ -58,4 +61,5 @@
 	//Root::getSingleton().addSceneManagerFactory(visibilityTerrainPlugin);
 	Root::getSingleton().addSceneManagerFactory(occlusionCullingPlugin);
+	Root::getSingleton().addSceneManagerFactory(kdTreeFactory);
 }
 //-----------------------------------------------------------------------
@@ -64,4 +68,5 @@
 	//Root::getSingleton().removeSceneManagerFactory(visibilityTerrainPlugin);
 	Root::getSingleton().removeSceneManagerFactory(occlusionCullingPlugin);
+	Root::getSingleton().removeSceneManagerFactory(kdTreeFactory);
 	// destroy listener manager
 	delete TerrainPageSourceListenerManager::getSingletonPtr();
@@ -75,4 +80,5 @@
 	//delete visibilityTerrainPlugin;
 	delete occlusionCullingPlugin;
+	delete kdTreeFactory;
 
 	delete visManager;
Index: /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreKdTreeSceneNode.cpp
===================================================================
--- /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreKdTreeSceneNode.cpp	(revision 1163)
+++ /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreKdTreeSceneNode.cpp	(revision 1163)
@@ -0,0 +1,162 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of the GameTools Project
+http://www.gametools.org
+
+Author: Martin Szydlowski
+-----------------------------------------------------------------------------
+*/
+
+#include "OgreKdTreeSceneNode.h"
+#include "OgreKdTreeSceneManager.h"
+
+#include <OgreStringConverter.h>
+
+namespace Ogre
+{
+	// TRIVIA: this function is _not_ called for nodes which did not change since the last frame
+	// only exception: the root node ... it's aabb should be null however, so we don't care
+	void KdTreeSceneNode::_updateBounds(void)
+	{
+		// Reset bounds first
+		mWorldAABB.setNull();
+
+		// Update bounds from own attached objects
+		ObjectMap::iterator i;
+		for (i = mObjectsByName.begin(); i != mObjectsByName.end(); ++i)
+		{
+			// Merge world bounds of each object
+			mWorldAABB.merge(i->second->getWorldBoundingBox(true));
+		}
+
+		if (!mWorldAABB.isNull())
+		{
+			static_cast<KdTreeSceneManager *>(mCreator)->_updateNode(this);
+		}
+	}
+
+	void KdTreeSceneNode::forceComputeAABB(AxisAlignedBox& aabb) // OBSOLETE !!
+	{
+
+		// Update bounds from own attached objects
+		ObjectMap::iterator i;
+		for (i = mObjectsByName.begin(); i != mObjectsByName.end(); ++i)
+		{
+			// Merge world bounds of each object
+			aabb.merge(i->second->getWorldBoundingBox(true));
+		}
+		// Merge with children
+		ChildNodeMap::iterator child;
+		for (child = mChildren.begin(); child != mChildren.end(); ++child)
+		{
+			KdTreeSceneNode* sceneChild = static_cast<KdTreeSceneNode*>(child->second);
+			sceneChild->forceComputeAABB(aabb);
+		}
+	}
+
+	void KdTreeSceneNode::computeScene(PlaneEventList& events, AxisAlignedBox& aabb, int& nObjects, bool includeChildren)
+	{
+		// first compute nodes AABB
+		mWorldAABB.setNull();
+		// Update bounds from own attached objects
+		ObjectMap::iterator i;
+		for (i = mObjectsByName.begin(); i != mObjectsByName.end(); ++i)
+		{
+			// Merge world bounds of each object
+			mWorldAABB.merge(i->second->getWorldBoundingBox(true));
+		}
+
+		if (!mWorldAABB.isNull())
+		{
+			// merge aabb with global AABB
+			aabb.merge(mWorldAABB);
+			// increase object count
+			nObjects++;
+
+			// generate events
+			PlaneEvent::Dimension axes[] = 
+				{PlaneEvent::PED_X, PlaneEvent::PED_Y, PlaneEvent::PED_Z};
+			Vector3 min = mWorldAABB.getMinimum();
+			Vector3 max = mWorldAABB.getMaximum();
+			//PlaneEvent * e;
+			for (int i = 0; i < 3; i++)
+			{
+				// 1-D and 2-D objects
+				if (min[i] == max[i])
+				{	
+					//e = new PlaneEvent(this, min, axes[i], PlaneEvent::PET_ON);
+					//sceneinfo.events.push_back(*e);
+					events.push_back(PlaneEvent(this, min, axes[i], PlaneEvent::PET_ON));
+				}
+				else
+				{
+					//e = new PlaneEvent(this, min, axes[i], PlaneEvent::PET_START);
+					//sceneinfo.events.push_back(*e);
+					//e = new PlaneEvent(this, max, axes[i], PlaneEvent::PET_END);
+					//sceneinfo.events.push_back(*e);
+					events.push_back(PlaneEvent(this, min, axes[i], PlaneEvent::PET_START));
+					events.push_back(PlaneEvent(this, max, axes[i], PlaneEvent::PET_END));
+				}
+			}
+		}
+
+		// Merge with children
+		if (includeChildren)
+		{
+			ChildNodeMap::iterator child;
+			for (child = mChildren.begin(); child != mChildren.end(); ++child)
+			{
+				KdTreeSceneNode* sceneChild = static_cast<KdTreeSceneNode*>(child->second);
+				sceneChild->computeScene(events, aabb, nObjects);
+			}
+		}
+	}
+
+	//void KdTreeSceneNode::_findVisibleObjects(Camera* cam, RenderQueue* queue, 
+	//	bool includeChildren, bool displayNodes, bool onlyShadowCasters)
+	void KdTreeSceneNode::queueObjects(Camera* cam, RenderQueue* queue, bool onlyShadowCasters)
+	{
+		//SceneNode::_findVisibleObjects(cam, queue, includeChildren, displayNodes, onlyShadowCasters);
+
+		// Add all entities
+		ObjectMap::iterator iobj;
+		ObjectMap::iterator iobjend = mObjectsByName.end();
+		for (iobj = mObjectsByName.begin(); iobj != iobjend; ++iobj)
+		{
+			// Tell attached objects about camera position (incase any extra processing they want to do)
+			iobj->second->_notifyCurrentCamera(cam);
+			if (!onlyShadowCasters || iobj->second->getCastShadows())
+			{
+				iobj->second->_updateRenderQueue(queue);
+			}
+		}
+
+		// Check if the bounding box should be shown.
+		// See if our flag is set or if the scene manager flag is set.
+		if (mShowBoundingBox || (mCreator && mCreator->getShowBoundingBoxes())) 
+		{ 
+			_addBoundingBoxToQueue(queue);
+		}
+	}
+
+	AxisAlignedBox KdTreeSceneNode::getBoundingBox() const
+	{
+		return mWorldAABB;
+	}
+
+	// DEBUG
+	String KdTreeSceneNode::dumpToString()
+	{
+		String objects;
+		// Add all entities
+		ObjectMap::iterator iobj = mObjectsByName.begin();
+		ObjectMap::iterator iobjend = mObjectsByName.end();
+		while (iobj != iobjend)
+		{
+			objects += " " + iobj->second->getName();
+			iobj++;
+		}
+		objects += " Attached to " + StringConverter::toString(mLeaves.size()) + " KdLeaves.";
+		return objects;
+	}
+}
Index: /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreKdTree.cpp
===================================================================
--- /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreKdTree.cpp	(revision 1163)
+++ /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreKdTree.cpp	(revision 1163)
@@ -0,0 +1,1421 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of the GameTools Project
+http://www.gametools.org
+
+Author: Martin Szydlowski
+-----------------------------------------------------------------------------
+*/
+
+#include <OgreCamera.h>
+#include "OgreKdTree.h"
+#include "OgreKdRenderable.h"
+#include "OgreKdTreeSceneNode.h"
+#include "OgreKdTreeSceneManager.h"
+
+#include <OgreStringConverter.h>
+#include <OgreLogManager.h>
+#include <OgreRoot.h>
+#include <OgreTimer.h>
+
+#include <OgreMaterialManager.h>
+
+#define KDTREE_LOGNAME "KdTreeBuild.log"
+
+namespace Ogre
+{
+	Real PlaneEvent::KT = 2.0;
+	Real PlaneEvent::KI = 1.0;
+
+	void PlaneEvent::classify(const PlaneEvent& e, PlaneEvent::Side side)
+	{
+		// only classify events of the same dimension
+		if (mDimension == e.mDimension)
+		{
+			if (mType == PET_END && mPosition[mDimension] <= e.mPosition[e.mDimension])
+			{
+				mRenderable->setSide(PES_LEFT);
+			}
+			else if (mType == PET_START && mPosition[mDimension] >= e.mPosition[e.mDimension])
+			{
+				mRenderable->setSide(PES_RIGHT);
+			}
+			else if (mType == PET_ON)
+			{
+				if (mPosition[mDimension] < e.mPosition[e.mDimension] ||
+					(mPosition[mDimension] == e.mPosition[e.mDimension] && side == PES_LEFT))
+				{
+					mRenderable->setSide(PES_LEFT);
+				}
+				if (mPosition[mDimension] > e.mPosition[e.mDimension] ||
+					(mPosition[mDimension] == e.mPosition[e.mDimension] && side == PES_RIGHT))
+				{
+					mRenderable->setSide(PES_RIGHT);
+				}
+			}
+		}
+	}
+
+	PlaneEvent PlaneEvent::clip(AxisAlignedBox& box, PlaneEvent::Dimension dim)
+	{
+		Vector3 newpos = mPosition, min = box.getMinimum(), max = box.getMaximum();
+		if (newpos[dim] < min[dim])
+			newpos[dim] = min[dim];
+		else if (newpos[dim] > max[dim])
+			newpos[dim] = max[dim];
+
+		return PlaneEvent(mRenderable, newpos, mDimension, mType);
+	}
+
+	void PlaneEvent::SAH(const AxisAlignedBox& parent, int nLeft, int nPlane, int nRight, SplitInfo& split)
+	{
+
+#ifdef KDTREE_DEBUG_OFF
+		Real mu = splitBox(parent, split.bleft, split.bright);
+		Real sav = surfaceArea(parent); // optimize?? called several times for the same box
+		Real savl = surfaceArea(split.bleft);
+		Real savr = surfaceArea(split.bright);
+		Real pl = savl / sav;
+		Real pr = savr / sav;
+		Real costl = splitCost(pl, pr, nLeft + nPlane, nRight, mu);
+		Real costr = splitCost(pl, pr, nLeft, nPlane + nRight, mu);
+
+		Log * log = LogManager::getSingleton().getLog(KDTREE_LOGNAME);
+		log->logMessage("SAH: SA-parent=" + StringConverter::toString(sav) + 
+			"\n\tSA-left=" + StringConverter::toString(savl) + 
+			" SA-right=" + StringConverter::toString(savr) + 
+			"\n\tp-left=" + StringConverter::toString(pl) + 
+			" p-right=" + StringConverter::toString(pr) +
+			"\n\tmu=" + StringConverter::toString(mu) +
+			"\n\tcost-left=" + StringConverter::toString(costl) +
+			" cost-right=" + StringConverter::toString(costr));
+#else
+		Real mu = splitBox(parent, split.bleft, split.bright);
+		Real sav = surfaceArea(parent); // optimize?? called several times for the same box
+		Real pl = surfaceArea(split.bleft) / sav;
+		Real pr = surfaceArea(split.bright) / sav;
+		Real costl = splitCost(pl, pr, nLeft + nPlane, nRight, mu);
+		Real costr = splitCost(pl, pr, nLeft, nPlane + nRight, mu);
+
+#endif
+		if (costl < costr)
+		{
+			split.cost = costl;
+			split.side = PES_LEFT;
+			split.nleft = nLeft + nPlane;
+			split.nright = nRight;
+		}
+		else
+		{
+			split.cost = costr;
+			split.side = PES_RIGHT;
+			split.nleft = nLeft;
+			split.nright = nPlane + nRight;
+
+		}
+		split.event = *this;
+	}
+
+	Real PlaneEvent::splitBox(const AxisAlignedBox& parent, AxisAlignedBox& left, AxisAlignedBox& right)
+	{
+		Vector3 bmin = parent.getMinimum();
+		Vector3 bmax = parent.getMaximum();
+#ifdef KDTREE_DEBUG_OFF
+		if(bmin[mDimension] > mPosition[mDimension] || bmax[mDimension] < mPosition[mDimension])
+		{
+			Log * log = LogManager::getSingleton().getLog(KDTREE_LOGNAME);
+			log->logMessage("SPLITBOX SNAFU in event " + print() +
+				"\n\tmin=" + StringConverter::toString(bmin[mDimension]) + 
+				" split=" + StringConverter::toString(mPosition[mDimension]) + 
+				" max=" + StringConverter::toString(bmax[mDimension]));
+		}
+#endif
+		// calculate the penalty for spliting the box that way
+		Real mu = lookupPenalty((mPosition[mDimension] - bmin[mDimension]) / (bmax[mDimension] - bmin[mDimension]));
+		// set corners which are the same as parent AABB
+		left.setMinimum(bmin);
+		right.setMaximum(bmax);
+		// modify "inner" corners
+		bmin[mDimension] = mPosition[mDimension];
+		bmax[mDimension] = mPosition[mDimension];
+		// set the corners on the split plane
+		left.setMaximum(bmax);
+		right.setMinimum(bmin);
+
+		return mu;
+	}
+
+	Real PlaneEvent::splitCost(Real pLeft, Real pRight, int nLeft, int nRight)
+	{
+		//assert(pLeft <= 1.0 && pRight <= 1.0);
+
+		// reward splitting off chunks of empty space
+		Real lambda = 1.0;
+		if (nLeft == 0 || nRight == 0)
+		{
+			lambda = 0.8;
+		}
+
+		// penalize splitting off small chunks
+		Real mu = 1.0;
+		if (pLeft < 0.1 || pRight < 0.1 || pLeft > 0.9 || pRight > 0.9)
+		{
+			mu = 1.5;
+		}
+		return lambda * mu * (KT + (KI * (pLeft*nLeft + pRight*nRight)));
+		
+		//return lambda * (KT + (KI * (pLeft*nLeft + pRight*nRight)));
+	}
+
+	Real PlaneEvent::splitCost(Real pLeft, Real pRight, int nLeft, int nRight, Real mu)
+	{
+		//assert(pLeft <= 1.0 && pRight <= 1.0);
+
+		// reward splitting off chunks of empty space
+		Real lambda = 1.0;
+		if (nLeft == 0 || nRight == 0)
+		{
+			lambda = 0.8;
+		}
+
+		return lambda * mu * (KT + (KI * (pLeft*nLeft + pRight*nRight)));
+	}
+
+	Real PlaneEvent::surfaceArea(const AxisAlignedBox& box)
+	{
+		Vector3 sides = box.getMaximum() - box.getMinimum();
+#ifdef KDTREE_DEBUG_OFF
+		if(sides.x < 0 || sides.y < 0 || sides.z < 0)
+		{
+			Log * log = LogManager::getSingleton().getLog(KDTREE_LOGNAME);
+			log->logMessage("AABB SNAFU: x=" + StringConverter::toString(sides.x) + 
+				" y=" + StringConverter::toString(sides.y) + " z=" + StringConverter::toString(sides.z) +
+				" BOX=" + StringConverter::toString(box.getMinimum()) + "," + StringConverter::toString(box.getMaximum()));
+		}
+#endif
+		return	2 * sides.x * sides.y +
+				2 * sides.y * sides.z +
+				2 * sides.z * sides.x;
+	}
+
+	void PlaneEvent::pqSAH(Real globalSA, Real parentSA, int nLeft, int nPlane, int nRight, AxisAlignedBox& parentBox, SplitInfo& split)
+	{
+		Real mu = splitBox(parentBox, split.bleft, split.bright);
+		Real p = parentSA / globalSA;
+		Real pl = surfaceArea(split.bleft) / globalSA;
+		Real pr = surfaceArea(split.bright) / globalSA;
+		Real costl = pqSplitCost(p, pl, pr, nLeft + nPlane, nRight, mu);
+		Real costr = pqSplitCost(p, pl, pr, nLeft, nPlane + nRight, mu);
+
+		if (costl < costr)
+		{
+			split.cost = costl;
+			split.side = PES_LEFT;
+			split.nleft = nLeft + nPlane;
+			split.nright = nRight;
+		}
+		else
+		{
+			split.cost = costr;
+			split.side = PES_RIGHT;
+			split.nleft = nLeft;
+			split.nright = nPlane + nRight;
+
+		}
+		split.event = *this;
+	}
+
+	Real PlaneEvent::pqSplitCost(Real pParent, Real pLeft, Real pRight, int nLeft, int nRight, Real mu)
+	{
+		// reward splitting off chunks of empty space
+		//Real lambda = 1.0;
+		//if (nLeft == 0 || nRight == 0)
+		//{
+		//	lambda = 0.8;
+		//}
+
+		return /* lambda * mu * */ (pParent*KT + (KI * (pLeft*nLeft + pRight*nRight)));
+	}
+
+#define PLT_SIZE 101
+
+	// lookup the penalty for placing the splitting plane near to the edge of the AABB
+	// 0.0 <= p <= 1.0, p = 0.5 means the plane divides the aabb in half
+	Real PlaneEvent::lookupPenalty(Real p)
+	{
+		// precomputed table of {x^6 + 1|0 <= x <= 1}
+		static Real mPenaltyLookupTable[PLT_SIZE];
+		static bool init_done = false;
+
+		if (!init_done)
+		{
+			Real step = 1.0  / (PLT_SIZE - 1);
+			Real x = 0.0; 
+			//LogManager::getSingleton().logMessage("### Calculating Lookup Table ###");
+			for (int i = 0; i < PLT_SIZE; i++)
+			{
+				mPenaltyLookupTable[i] = Math::Pow(x, 6) + 1.0;
+				x += step;
+				//LogManager::getSingleton().logMessage("### mPenaltyLookupTable[" + StringConverter::toString(i,3) + "]=" + StringConverter::toString(mPenaltyLookupTable[i]));
+			}
+			init_done = true;
+			//LogManager::getSingleton().logMessage("### Lookup Table Calculated ###");
+		}
+
+		// normalize p to [0,1]
+		Real x = Math::Abs(p * 2 - 1);
+		int i = Math::IFloor(x * (PLT_SIZE - 1));
+
+		return mPenaltyLookupTable[i];
+	}
+
+	// DEBUG
+	String PlaneEvent::print()
+	{
+		String dim, type;
+		if (mDimension == PED_X)
+			dim = "X";
+		if (mDimension == PED_Y)
+			dim = "Y";
+		if (mDimension == PED_Z)
+			dim = "Z";
+		if (mType == PET_END)
+			type = "END  ";
+		if (mType == PET_ON)
+			type = "ON   ";
+		if (mType == PET_START)
+			type = "START";
+		//return StringConverter::toString(mPosition[mDimension]) + " " + dim + " " + type;
+		return type + " " + dim + " " + StringConverter::toString(mPosition[mDimension]);
+	};
+
+	String SplitInfo::print()
+	{
+		String sside;
+		if (side == PlaneEvent::PES_BOTH)
+			sside = "BOTH ";
+		if (side == PlaneEvent::PES_LEFT)
+			sside = "LEFT ";
+		if (side == PlaneEvent::PES_RIGHT)
+			sside = "RIGHT";
+		return "nLeft: " + StringConverter::toString(nleft, 4) + " nRight: " + 
+			StringConverter::toString(nright, 4) + " Cost: " + StringConverter::toString(cost, 8, 9) +
+			" Side: " + sside + " Event: " + event.print() + " Leftbox: " + 
+			StringConverter::toString(bleft.getMinimum()) + ", " + 
+			StringConverter::toString(bleft.getMaximum()) + " Rightbox: " +
+			StringConverter::toString(bright.getMinimum()) + ", " + 
+			StringConverter::toString(bright.getMaximum());
+	};
+
+	String KdTree::SplitCandidate::print()
+	{		
+		String sside;
+		if (side == PlaneEvent::PES_BOTH)
+			sside = "BOTH ";
+		if (side == PlaneEvent::PES_LEFT)
+			sside = "LEFT ";
+		if (side == PlaneEvent::PES_RIGHT)
+			sside = "RIGHT";
+		return "List: " + StringConverter::toString(events->size(), 4) + " Objects: " +
+			StringConverter::toString(nObjects, 4) + " Cost: " + StringConverter::toString(cost, 8, 9) + 
+			" Decrease: " + StringConverter::toString(decrease, 8, 9) + " Side: " + sside + " Best: " +
+			best->print() +  " Box: " + StringConverter::toString(aabb.getMinimum()) + ", "
+			+ StringConverter::toString(aabb.getMaximum());
+
+	};
+
+	//----------------------------------------------------------------------------
+	//----------------------------------------------------------------------------
+	//----------------------------------------------------------------------------
+
+	KdTree::KdTree(int maxdepth): mMaxDepth(maxdepth), mKdRoot(0), mBuildMethod(KDBM_RECURSIVE), mBuildLog(0)
+	{
+#ifdef KDTREE_DEBUG
+		try
+		{
+			ColourValue cv(0.0, 1.0, 0.0);
+			MaterialPtr mp = MaterialManager::getSingleton().create("aabbHiLite","General");
+			mp->setSelfIllumination(cv);
+			mp->setDiffuse(cv);
+		}
+		catch (Ogre::Exception&)
+		{
+			// SO FUCKING DON'T CARE !!!
+		}
+#endif
+		try
+		{
+			mBuildLog = LogManager::getSingleton().getLog(KDTREE_LOGNAME);
+		}
+		catch (Exception&)
+		{		
+			mBuildLog = LogManager::getSingleton().createLog(KDTREE_LOGNAME);
+		}
+	}
+
+	KdTree::~KdTree()
+	{
+		delete mKdRoot;
+	}
+
+	void KdTree::remove(KdRenderable * rend)
+	{
+		// DEBUG
+		//LogManager::getSingleton().logMessage("-- Removing SceneNode: " + (static_cast<KdTreeSceneNode *>(rend))->getName());
+		std::queue<LeafPtr> cleanup;
+		LeafPtr leaf;
+		LeafSet ls = rend->getLeaves();
+		LeafSet::iterator it = ls.begin();
+		LeafSet::iterator end = ls.end();
+		while (it != end)
+		{
+			cleanup.push(*it);
+			it++;
+		}
+		while (!cleanup.empty())
+		{
+			leaf = cleanup.front();
+			cleanup.pop();
+			leaf->remove(rend);
+			bool gone = rend->detachFrom(leaf);
+			assert(gone && "Failed to detach leave which is abso-fuckin-lutely impossible!!!");
+			//dump();
+			recDelete(leaf);
+			//dump();
+		}
+	}
+
+	void KdTree::recDelete(KdTree::Node * node)
+	{
+		if (node == 0) // DEBUG
+		{
+			OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
+				"SNAFU while inserting KdRenderable into KdTree.",
+				"KdTree::recInsert" );
+			return;
+		}
+
+		if (node->isEmpty())
+		{
+			if (node == mKdRoot)
+			{
+				OGRE_DELETE(mKdRoot);
+			} 
+			else
+			{
+				KdTree::Branch * parent = node->mParent;
+				if (node == parent->mLeft)
+				{
+					OGRE_DELETE(parent->mLeft);
+				}
+				else if (node == parent->mRight)
+				{
+					OGRE_DELETE(parent->mRight);
+				}
+				recDelete(parent);
+			}
+		}
+	}
+
+	void KdTree::insert(KdRenderable * rend)
+	{
+		// make sure the tree exists
+		if (mKdRoot)
+		{
+			// make sure the renderable is inside the world bounding box
+			AxisAlignedBox aabb = rend->getBoundingBox();
+			AxisAlignedBox isect = mKdRoot->mAABB.intersection(aabb);
+			if (isect.getMinimum() == aabb.getMinimum() && isect.getMaximum() == aabb.getMaximum())
+			{
+				recInsert(mKdRoot, rend);
+			}
+			else
+			{
+				//LogManager::getSingleton().logMessage("Inserted node outside of world AABB.");
+				KdRenderableList nodelist;
+				nodelist.push_back(rend);
+				addRendToList(mKdRoot, nodelist);
+				OGRE_DELETE(mKdRoot);
+				mKdRoot = buildFromList(nodelist, 0, AxisAlignedBox());
+			}
+		}
+		// otherwise build a new one
+		else
+		{
+			build(rend);
+		}
+	}
+
+	void KdTree::recInsert(KdTree::Node * node, KdRenderable * rend)
+	{
+		if (node == 0) // DEBUG
+		{
+			OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
+				"SNAFU while inserting KdRenderable into KdTree.",
+				"KdTree::recInsert" );
+			return;
+		}
+
+		// rebuild the leaf/replace with subtree ...
+		if (node->isLeaf())
+		{
+			//LogManager::getSingleton().logMessage("## Replacing leaf.");
+			rebuildSubtree(node, rend);
+		}
+		else
+		{
+			KdTree::Branch * branch = static_cast<KdTree::Branch *>(node);
+			AxisAlignedBox aabb = rend->getBoundingBox();
+			Plane::Side smin = branch->mSplitPlane->getSide(aabb.getMinimum());
+			Plane::Side smax = branch->mSplitPlane->getSide(aabb.getMaximum());
+			if (smin == smax)
+			{
+				if (smax == Plane::NEGATIVE_SIDE ||
+					(smax == Plane::NO_SIDE && branch->mPlaneSide == PlaneEvent::PES_LEFT))
+				{
+					if (branch->mLeft)
+						recInsert(branch->mLeft, rend);
+					else
+						recInsertNew(branch, PlaneEvent::PES_LEFT, rend);
+				}
+				else if (smin == Plane::POSITIVE_SIDE || 
+					(smin == Plane::NO_SIDE && branch->mPlaneSide == PlaneEvent::PES_RIGHT))
+				{
+					if (branch->mRight)
+						recInsert(branch->mRight, rend);
+					else
+						recInsertNew(branch, PlaneEvent::PES_RIGHT, rend);
+				}
+			}
+			else
+			{
+				if (smin == Plane::NEGATIVE_SIDE && smax == Plane::NO_SIDE)
+				{
+					if (branch->mLeft)
+						recInsert(branch->mLeft, rend);
+					else
+						recInsertNew(branch, PlaneEvent::PES_LEFT, rend);
+				}
+				else if (smax == Plane::POSITIVE_SIDE && smin == Plane::NO_SIDE)
+				{
+					if (branch->mRight)
+						recInsert(branch->mRight, rend);
+					else
+						recInsertNew(branch, PlaneEvent::PES_RIGHT, rend);
+				}
+				else
+				{
+					// to avoid SNAFUs, rebuild whole subtree
+					//LogManager::getSingleton().logMessage("## Rebuilding subtree for insertion");
+					rebuildSubtree(node, rend);
+				}
+			}
+		}
+	}
+
+	void KdTree::recInsertNew(KdTree::Branch * parent, PlaneEvent::Side side, KdRenderable * rend)
+	{
+		//LogManager::getSingleton().logMessage("## Inserting into new subtree");
+
+		AxisAlignedBox left, rigth, aabb;
+		PlaneEventList events;
+		int nObjects;
+		
+		rend->computeScene(events, aabb, nObjects, false);
+
+		// override aabb
+		splitBox(*parent, left, rigth);
+		if (side == PlaneEvent::PES_LEFT)
+		{
+			aabb = left;
+			if (mBuildMethod == KDBM_RECURSIVE)
+				parent->mLeft = recBuild(events, nObjects, aabb, parent);
+			else if (mBuildMethod == KDBM_PRIORITYQUEUE)
+				parent->mLeft = pqBuild(events, nObjects, aabb, parent);
+			else
+			{
+				OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
+					"Invalid build method for the KdTree.",
+					"KdTree::buildFromList");
+				parent->mLeft = 0;
+			}
+			
+		}
+		else if (side == PlaneEvent::PES_RIGHT)
+		{
+			aabb = rigth;
+			if (mBuildMethod == KDBM_RECURSIVE)
+				parent->mRight = recBuild(events, nObjects, aabb, parent);
+			else if (mBuildMethod == KDBM_PRIORITYQUEUE)
+				parent->mRight = pqBuild(events, nObjects, aabb, parent);
+			else
+			{
+				OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
+					"Invalid build method for the KdTree.",
+					"KdTree::buildFromList");
+				parent->mRight = 0;
+			}
+		}
+	}
+
+	void KdTree::rebuildSubtree(KdTree::Node * node, KdRenderable * rend)
+	{
+		//LogManager::getSingleton().logMessage("## Rebuilding subtree");
+
+		AxisAlignedBox aabb = node->mAABB;
+		
+		KdRenderableList nodelist;
+		nodelist.push_back(rend);
+		addRendToList(node, nodelist);
+
+		if (node == mKdRoot)
+		{
+			OGRE_DELETE(mKdRoot);
+			mKdRoot = buildFromList(nodelist, 0, aabb);
+		}
+		else
+		{
+			KdTree::Branch * parent = static_cast<KdTree::Branch *>(node->mParent);
+
+			if (node == parent->mLeft)
+			{
+				OGRE_DELETE(parent->mLeft);
+				parent->mLeft = buildFromList(nodelist, parent, aabb);
+			}
+			else if (node == parent->mRight)
+			{
+				OGRE_DELETE(parent->mRight);
+				parent->mRight = buildFromList(nodelist, parent, aabb);
+			}
+			else
+			{
+				OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
+					"SNAFU while inserting KdRenderable into KdTree.",
+					"KdTree::recInsert" );
+			}
+		}
+	}
+
+	// compute both AABB then return the requested one.
+	void KdTree::splitBox(const KdTree::Branch& parent, AxisAlignedBox& left, AxisAlignedBox& right)
+	{
+		Vector3 bmin = parent.mAABB.getMinimum();
+		Vector3 bmax = parent.mAABB.getMaximum();
+		Real pos = - parent.mSplitPlane->d;
+		int dim = static_cast<int>(parent.mSplitPlane->normal.dotProduct(Vector3(0,1,2)));
+		// set corners which are the same as parent AABB
+		left.setMinimum(bmin);
+		right.setMaximum(bmax);
+		// modify "inner" corners
+		bmin[dim] = pos;
+		bmax[dim] = pos;
+		// set the corners on the split plane
+		left.setMaximum(bmax);
+		right.setMinimum(bmin);
+	}
+
+	void KdTree::addRendToList(KdTree::Node * node, KdRenderableList& nodelist)
+	{
+		if (node->isLeaf())
+		{
+			KdTree::Leaf * leaf = static_cast<KdTree::Leaf *>(node);
+			KdRenderableList::iterator it  = leaf->mKdRenderables.begin();
+			KdRenderableList::iterator end = leaf->mKdRenderables.end();
+			while (it != end)
+			{
+				nodelist.push_back(*it);
+				it++;
+			}
+		}
+		else
+		{
+			KdTree::Branch * branch = static_cast<KdTree::Branch *>(node);
+			if (branch->mLeft)
+				addRendToList(branch->mLeft, nodelist);
+			if (branch->mRight)
+				addRendToList(branch->mRight, nodelist);
+		}
+	}
+
+	void KdTree::build(KdRenderable * sceneRoot)
+	{
+		// DEBUG
+		//LogManager *lm = LogManager::getSingletonPtr();
+		Timer *timer = Root::getSingleton().getTimer();
+		unsigned long t1, t2, t3, t4;
+		//AxisAlignedBox aabb;
+		
+		// data we want to collect
+		PlaneEventList events;
+		AxisAlignedBox aabb;
+		int nObjects = 0;
+
+		t1 = timer->getMicroseconds(); // DEBUG
+		sceneRoot->computeScene(events, aabb, nObjects);
+		t2 = timer->getMicroseconds(); // DEBUG
+		events.sort();
+		t3 = timer->getMicroseconds(); // DEBUG
+
+		// <DEBUG>
+		//lm->logMessage("# of perfect splits " + StringConverter::toString(events.size()));
+		//PlaneEventList::iterator it;
+		//for (it = events.begin(); it != events.end(); it++)
+		//{
+		//	lm->logMessage(it->print());
+		//}
+		// </DEBUG>
+
+		assert(! aabb.isNull() && "Teh stubid worldAABB iz NULL ... waht now?");
+		// hack to avoid SNAFU with "2-dimensional" scene
+		aabb.merge(aabb.getMaximum()+Vector3(1,1,1));
+		aabb.merge(aabb.getMinimum()+Vector3(-1,-1,-1));
+
+		if (mBuildMethod == KDBM_RECURSIVE)
+			mKdRoot = recBuild(events, nObjects, aabb, 0);
+		else if (mBuildMethod == KDBM_PRIORITYQUEUE)
+			mKdRoot = pqBuild(events, nObjects, aabb, 0);
+		else
+		{
+			OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
+				"Invalid build method for the KdTree.",
+				"KdTree::build");
+			mKdRoot = 0;
+		}
+
+		t4 = timer->getMicroseconds(); // DEBUG
+
+		mBuildLog->logMessage("######## SAH Statistics ########");
+		mBuildLog->logMessage("Time for events build: " + StringConverter::toString(t2 - t1) + "µs");
+		mBuildLog->logMessage("Time for events sort: " + StringConverter::toString(t3 - t2) + "µs");
+		mBuildLog->logMessage("Time for tree build: " + StringConverter::toString(t4 - t3) + "µs");
+		mBuildLog->logMessage("Total time: " + StringConverter::toString(t4 - t1) + "µs");
+		mBuildLog->logMessage("######## SAH Statistics ########");
+		calcCost();
+	}
+
+	KdTree::Node * KdTree::buildFromList(KdRenderableList& nodelist, KdTree::Branch * parent, AxisAlignedBox& aabb)
+	{
+		// data we want to collect
+		PlaneEventList events;
+		AxisAlignedBox nodeaabb;
+		int nObjects = 0;
+
+		KdRenderableList::iterator it = nodelist.begin();
+		KdRenderableList::iterator end = nodelist.end();
+		while (it != end)
+		{
+			(*it)->computeScene(events, nodeaabb, nObjects, false);
+			it++;
+		}
+		events.sort();
+		// HACK
+		if (aabb.isNull())
+		{
+			//LogManager::getSingleton().logMessage("AABB empty, using node AABB.");
+			aabb = nodeaabb;
+		}
+
+		// this must never happen!!
+		//AxisAlignedBox isect = aabb.intersection(nodeaabb);
+		//if (isect.getMinimum() != nodeaabb.getMinimum() || isect.getMaximum() != nodeaabb.getMaximum())
+		//{
+		//	LogManager::getSingleton().logMessage("#+#+#+#+#+ SceneNodes outside of node AABB.");
+		//}
+
+		if (mBuildMethod == KDBM_RECURSIVE)
+			return recBuild(events, nObjects, aabb, parent);
+		else if (mBuildMethod == KDBM_PRIORITYQUEUE)
+			return pqBuild(events, nObjects, aabb, parent);
+		else
+		{
+			OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
+				"Invalid build method for the KdTree.",
+				"KdTree::buildFromList");
+			return 0;
+		}
+	}
+
+	KdTree::Node * KdTree::recBuild(PlaneEventList& events, int nObjects, AxisAlignedBox& aabb, KdTree::Branch * parent)
+	{
+		// determine the depth we are on
+		int level = 0;
+		if (parent)
+		{
+			level = parent->mLevel + 1;
+		}
+
+#ifdef KDTREE_DEBUG_OFF
+		mBuildLog->logMessage("events.size()=" + StringConverter::toString(events.size()));
+#endif
+#ifdef KDTREE_DEBUG_OFF
+		PlaneEventList::iterator xit, xbegin, xend;
+		xbegin = events.begin();
+		xend = events.end();
+		xit = xbegin;
+		while (xit != xend)
+		{
+			mBuildLog->logMessage(xit->print());
+			xit++;
+		}
+#endif
+
+		/************************************************/
+		/**************** BEGIN FINDPLANE ***************/
+		/************************************************/
+		// find optimal split plane and split node accordingly
+		const int dim = 3;
+		int pStart, pOn, pEnd;
+		int nLeft[dim], nPlane[dim], nRight[dim];
+		for (int i = 0; i < dim; i++)
+		{
+			nLeft[i] = 0; nPlane[i] = 0; nRight[i] = nObjects;
+		}
+
+		SplitInfo split, best;
+		best.cost = Math::POS_INFINITY;
+
+
+		PlaneEventList::iterator begin = events.begin();
+		PlaneEventList::iterator end = events.end();
+		PlaneEventList::iterator it = begin;
+		// try all planes to find the best one for the given set of objects
+		while (it != end)
+		{
+			PlaneEventList::iterator p = it;
+			pStart = pOn = pEnd = 0;
+			while (it != end && p->equalsType(*it, PlaneEvent::PET_END))
+			{
+				it++; pEnd++;
+			}
+			while (it != end && p->equalsType(*it, PlaneEvent::PET_ON))
+			{
+				it++; pOn++;
+			}
+			while (it != end && p->equalsType(*it, PlaneEvent::PET_START))
+			{
+				it++; pStart++;
+			}
+			int d = p->getDimension();
+			nPlane[d] = pOn; nRight[d] -= pOn; nRight[d] -= pEnd;
+			p->SAH(aabb, nLeft[d], nPlane[d], nRight[d], split);
+			if (split.cost < best.cost)
+			{
+				best = split;
+			}
+			nLeft[d] += pStart; nLeft[d] += pOn; nPlane[d] = 0;
+		}
+
+#ifdef KDTREE_DEBUG_OFF
+		Real lvol = best.bleft.volume();
+		Real rvol = best.bright.volume();
+
+		if (lvol == 0 || rvol == 0)
+		{
+			mBuildLog->logMessage("WARNING INVALID SPLIT!!!");
+			String side;
+			if (best.side == PlaneEvent::PES_LEFT)
+				side = "left";
+			else
+				side = "right";
+
+			mBuildLog->logMessage("Splitting node on level " + StringConverter::toString(level) + 
+				"\n\tcost=" + StringConverter::toString(best.cost) + " term=" + StringConverter::toString(PlaneEvent::KI*nObjects) +
+				" side=" + side +
+				"\n\tVolume: left=" + StringConverter::toString(lvol) +
+				" right=" + StringConverter::toString(rvol));
+		}
+#endif
+		/************************************************/
+		/**************** BEGIN TERMINATE ***************/
+		/************************************************/
+		// check terminating condition
+		if (best.cost > PlaneEvent::KI*nObjects || level >= mMaxDepth)
+		{
+			// Terminating condition reached, create leaf and add renderables to list
+			KdTree::Leaf * leaf = new KdTree::Leaf(level, aabb, parent);
+			KdRenderable *rend;
+			it = begin;
+			while (it != end)
+			{
+				rend = it->getRenderable();
+				rend->setClassified(false);
+				if (rend->attachTo(leaf, this))
+				{
+					leaf->insert(rend);
+					//LogManager::getSingleton().logMessage("++ Adding SceneNode: " + (static_cast<KdTreeSceneNode *>(rend))->getName());
+				}
+				it++;
+			}
+			return leaf;
+		}
+
+		/************************************************/
+		/**************** BEGIN CLASSIFY ****************/
+		/************************************************/
+		else
+		{
+			PlaneEventList eventsRight, eventsLeft;
+			it = begin;
+			// slightly redundant, since we mark each renderable up to 6 times
+			while (it != end)
+			{
+				it->getRenderable()->setSide(PlaneEvent::PES_BOTH);
+				it->getRenderable()->setClassified(false);
+				it++;
+			}
+			// now classify all renderables. do they belong to the left child, the right child or both?
+			it = begin;
+			while (it != end)
+			{
+				it->classify(best.event, best.side);
+				it++;
+			}
+			// divide the event lists
+			int nLeftS = 0, nRightS = 0, nBothS = 0;
+			it = begin;
+			while (it != end)
+			{
+				// right-only nodes get moved
+				if (it->getRenderable()->getSide() == PlaneEvent::PES_RIGHT)
+				{
+					if (!it->getRenderable()->isClassified())
+					{
+						it->getRenderable()->setClassified(true);
+						nRightS++;
+					}
+
+					eventsRight.push_back(*it);
+				}
+				// both-only nodes get copied
+				// must clip AABBs to child AABB !!!
+				else if (it->getRenderable()->getSide() == PlaneEvent::PES_BOTH)
+				{
+					if (!it->getRenderable()->isClassified())
+					{
+						it->getRenderable()->setClassified(true);
+						nBothS++;
+					}
+
+					//eventsRight.push_back(*it);
+					//eventsLeft.push_back(*it);
+					eventsRight.push_back(it->clip(best.bright, best.event.getDimension()));
+					eventsLeft.push_back(it->clip(best.bleft, best.event.getDimension()));
+				}
+				else
+				{
+					if (!it->getRenderable()->isClassified())
+					{
+						it->getRenderable()->setClassified(true);
+						nLeftS++;
+					}
+					eventsLeft.push_back(*it);
+				}
+				it++;
+			}
+
+#ifdef KDTREE_DEBUG_OFF
+			mBuildLog->logMessage("Splitting on " + best.event.print());
+			mBuildLog->logMessage("eventsLeft.size()=" + StringConverter::toString(eventsLeft.size()));
+			mBuildLog->logMessage("eventsRight.size()=" + StringConverter::toString(eventsRight.size()));
+#endif
+			KdTree::Branch * branch = new KdTree::Branch(level, aabb, parent, best.event.getSplitPlane(), best.side);
+
+			// now create the child nodes and continue recursion
+			if (eventsLeft.size() > 0)
+			{
+				branch->mLeft = recBuild(eventsLeft, nLeftS + nBothS, best.bleft, branch);
+			}
+			if (eventsRight.size() > 0)
+			{
+				branch->mRight = recBuild(eventsRight, nBothS + nRightS, best.bright, branch);
+			}
+
+			//assert(branch->mRight || branch->mLeft);
+
+			return branch;
+		}
+	}
+
+	KdTree::Node * KdTree::pqBuild(PlaneEventList& events, int nObjects, AxisAlignedBox& aabb, KdTree::Branch * parent)
+	{
+		SplitCandidatePQ pqueue;
+		Real globalTreeCost;
+		Real globalSA;
+
+		KdTree::Node * newNode = 0, * topNode = 0;
+		// init global tree cost
+		globalTreeCost = PlaneEvent::KI * nObjects;
+		globalSA = PlaneEvent::surfaceArea(aabb);
+
+		PlaneEventList * e = new PlaneEventList(events);
+
+		// inital split candidate
+		SplitInfo * best = pqFindPlane(e, nObjects, aabb, globalSA);
+		SplitCandidate splitcandidate(e, nObjects, aabb, parent, globalTreeCost, globalTreeCost - best->cost, best, PlaneEvent::PES_BOTH);
+		pqueue.push(splitcandidate);
+
+#ifdef KDTREE_DEBUG_OFF
+		//mBuildLog->logMessage("best.pevent=" + best->event.print() + 
+		//	" events.size()=" + StringConverter::toString(events.size()));
+		mBuildLog->logMessage("New split on " + splitcandidate.print());
+#endif
+
+
+		/*** BEGIN ITERATIVE BUILD ***/
+		while (!pqueue.empty())
+		{
+			SplitCandidate sc = pqueue.top();
+			pqueue.pop();
+
+			// determine the depth we are on
+			int level = 0;
+			if (sc.parent)
+			{
+				level = sc.parent->mLevel + 1;
+			}
+
+#ifdef KDTREE_DEBUG_OFF
+			//mBuildLog->logMessage("Splitting on " + sc.best->event.print() +
+			//	" sc.events.size()=" + StringConverter::toString(sc.events->size()));
+			mBuildLog->logMessage("Splitting on " + sc.print());
+#endif
+
+			/************************************************/
+			/**************** BEGIN TERMINATE ***************/
+			/************************************************/
+			// check terminating condition
+			//if (best.cost > PlaneEvent::KI*sc.nObjects || level >= mMaxDepth)
+			if (sc.decrease < 0.0 || level >= mMaxDepth)
+			{
+				// Terminating condition reached, create leaf and add renderables to list
+				KdTree::Leaf * leaf = new KdTree::Leaf(level, sc.aabb, sc.parent);
+				KdRenderable *rend;
+				PlaneEventList::iterator begin = sc.events->begin();
+				PlaneEventList::iterator end = sc.events->end();
+				PlaneEventList::iterator it = begin;
+				while (it != end)
+				{
+					rend = it->getRenderable();
+					rend->setClassified(false);
+					if (rend->attachTo(leaf, this))
+					{
+						leaf->insert(rend);
+						//LogManager::getSingleton().logMessage("++ Adding SceneNode: " + (static_cast<KdTreeSceneNode *>(rend))->getName());
+					}
+					it++;
+				}
+				newNode = leaf;
+				if (!topNode)
+					topNode = leaf;
+			}
+
+			/************************************************/
+			/**************** BEGIN CLASSIFY ****************/
+			/************************************************/
+			else
+			{
+				PlaneEventList * eventsLeft = new PlaneEventList();
+				PlaneEventList * eventsRight = new PlaneEventList();
+				PlaneEventList::iterator begin = sc.events->begin();
+				PlaneEventList::iterator end = sc.events->end();
+				PlaneEventList::iterator it = begin;
+				// slightly redundant, since we mark each renderable up to 6 times
+				while (it != end)
+				{
+#ifdef KDTREE_DEBUG_OFF
+					mBuildLog->logMessage(it->print());
+#endif
+					it->getRenderable()->setSide(PlaneEvent::PES_BOTH);
+					it->getRenderable()->setClassified(false);
+					it++;
+				}
+				// now classify all renderables. do they belong to the left child, the right child or both?
+#ifdef KDTREE_DEBUG_OFF
+				bool bla = true;
+				it = begin;
+				while (it != end)
+				{
+					it->classify(sc.best->event, sc.best->side);
+					if (*it == sc.best->event)
+					{
+						mBuildLog->logMessage("YEEPEE classified against valid event");
+						bla = false;
+					}
+					it++;
+				}
+				if (bla)
+					mBuildLog->logMessage("FUCKIT! Invalid classification");
+#else
+				it = begin;
+				while (it != end)
+				{
+					it->classify(sc.best->event, sc.best->side);
+					it++;
+				}
+#endif
+
+
+				// divide the event lists
+				int nLeftS = 0, nRightS = 0, nBothS = 0;
+				it = begin;
+				while (it != end)
+				{
+					if (it->getRenderable()->getSide() == PlaneEvent::PES_RIGHT)
+					{
+						if (!it->getRenderable()->isClassified())
+						{
+							it->getRenderable()->setClassified(true);
+							nRightS++;
+						}
+
+						eventsRight->push_back(*it);
+					}
+					else if (it->getRenderable()->getSide() == PlaneEvent::PES_BOTH)
+					{
+						if (!it->getRenderable()->isClassified())
+						{
+							it->getRenderable()->setClassified(true);
+							nBothS++;
+						}
+
+						eventsRight->push_back(it->clip(sc.best->bright, sc.best->event.getDimension()));
+						eventsLeft->push_back(it->clip(sc.best->bleft, sc.best->event.getDimension()));
+					}
+					else
+					{
+						if (!it->getRenderable()->isClassified())
+						{
+							it->getRenderable()->setClassified(true);
+							nLeftS++;
+						}
+						eventsLeft->push_back(*it);
+					}
+					it++;
+				}
+
+#ifdef KDTREE_DEBUG_OFF
+				mBuildLog->logMessage("#### Splitting node on level " + StringConverter::toString(level));
+				Plane * vplane;
+				int count = 0;
+				PlaneEventList::iterator vit, vbegin, vend;
+				vbegin = eventsLeft->begin();
+				vend = eventsLeft->end();
+				vit = vbegin;
+				while (vit != vend)
+				{
+					vplane = vit->getSplitPlane();
+					if (!sc.best.bleft.intersects(*vplane))
+					{
+						mBuildLog->logMessage("Invalid event classification! Plane: " + 
+						StringConverter::toString(vplane->normal) + ", " + StringConverter::toString(-vplane->d) +
+						" Box: |" + StringConverter::toString(sc.best.bleft.getMinimum()) + "|" +
+						StringConverter::toString(sc.best.bleft.getMaximum()) + "|");
+						count++;
+					}
+					OGRE_DELETE(vplane);
+					vit++;
+				}
+				mBuildLog->logMessage("@@@@ Number of invalid events on the left: " + 
+					StringConverter::toString(count) +
+					" Number of events on both sides: " + StringConverter::toString(nBothS));
+				count = 0;
+				vbegin = eventsRight->begin();
+				vend = eventsRight->end();
+				vit = vbegin;
+				while (vit != vend)
+				{
+					vplane = vit->getSplitPlane();
+					if (!sc.best.bright.intersects(*vplane))
+					{
+						mBuildLog->logMessage("Invalid event classification! Plane: " + 
+						StringConverter::toString(vplane->normal) + ", " + StringConverter::toString(-vplane->d) +
+						" Box: |" + StringConverter::toString(sc.best.bright.getMinimum()) + "|" +
+						StringConverter::toString(sc.best.bright.getMaximum()) + "|");
+						count++;
+					}
+					OGRE_DELETE(vplane);
+					vit++;
+				}
+				mBuildLog->logMessage("@@@@ Number of invalid events on the right: " + 
+					StringConverter::toString(count) +
+					" Number of events on both sides: " + StringConverter::toString(nBothS));
+#endif
+
+				KdTree::Branch * branch = 
+					new KdTree::Branch(level, sc.aabb, sc.parent, sc.best->event.getSplitPlane(), sc.best->side);
+
+				//Real decr = (PlaneEvent::surfaceArea(sc.aabb)/globalSA*PlaneEvent::KI*sc.nObjects) - sc.best.cost;
+				globalTreeCost -= sc.decrease;
+
+				//mBuildLog->logMessage("Splitting, cost is now " + StringConverter::toString(globalTreeCost) + "");
+
+				// now create the child nodes and continue recursion
+				if (eventsLeft->size() > 0)
+				{
+					best = pqFindPlane(eventsLeft, nLeftS + nBothS, sc.best->bleft, globalSA);
+					Real old = PlaneEvent::surfaceArea(sc.best->bleft)/globalSA*PlaneEvent::KI*(nLeftS + nBothS);
+					SplitCandidate scleft(eventsLeft, nLeftS + nBothS, sc.best->bleft, 
+						branch, old, old - best->cost, best, PlaneEvent::PES_LEFT);
+					pqueue.push(scleft);
+
+#ifdef KDTREE_DEBUG_OFF
+					//mBuildLog->logMessage("best.pevent: " + best->event.print() + 
+					//	" eventsLeft.size()=" + StringConverter::toString(eventsLeft->size()));
+					mBuildLog->logMessage("New split on " + scleft.print());
+					Plane * plane = best->event.getSplitPlane();
+					if (!sc.best->bleft.intersects(*plane))
+					{
+						mBuildLog->logMessage("Best plane outside parent box on level " + 
+							StringConverter::toString(level));
+					}
+					OGRE_DELETE(plane);
+#endif
+				}
+				if (eventsRight->size() > 0)
+				{
+					best = pqFindPlane(eventsRight, nBothS + nRightS, sc.best->bright, globalSA);
+					Real old = PlaneEvent::surfaceArea(sc.best->bright)/globalSA*PlaneEvent::KI*(nBothS + nRightS);
+					SplitCandidate scright(eventsRight, nBothS + nRightS, sc.best->bright, 
+						branch, old, old - best->cost, best, PlaneEvent::PES_RIGHT);
+					pqueue.push(scright);
+
+#ifdef KDTREE_DEBUG_OFF
+					//mBuildLog->logMessage("best.pevent: " + best->event.print() + 
+					//	" eventsRight.size()=" + StringConverter::toString(eventsRight->size()));
+					mBuildLog->logMessage("New split on " + scright.print());
+					Plane * plane = best->event.getSplitPlane();
+					if (!sc.best->bright.intersects(*plane))
+					{
+						mBuildLog->logMessage("Best plane outside parent box on level " + 
+							StringConverter::toString(level));
+					}
+					OGRE_DELETE(plane);
+#endif
+				}
+
+				newNode = branch;
+				if (!topNode)
+					topNode = branch;
+			}
+
+			// attach new node to parent
+			if (sc.parent)
+			{
+				if (sc.side == PlaneEvent::PES_LEFT)
+				{
+					sc.parent->mLeft = newNode;
+				}
+				else if (sc.side == PlaneEvent::PES_RIGHT)
+				{
+					sc.parent->mRight = newNode;
+				}
+				else
+				{
+					OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
+						"PQBUILD SNAFU - CHILD I AM NOT LEFT NOR RIGHT","KdTree::pqBuild");
+				}
+			}
+
+			//cleanup
+			OGRE_DELETE(sc.events);
+			OGRE_DELETE(sc.best);
+		}
+		mBuildLog->logMessage("Cost after PQBUILD " + StringConverter::toString(globalTreeCost));
+		return topNode;
+	}
+
+	SplitInfo * KdTree::pqFindPlane(PlaneEventList * events, int nObjects, AxisAlignedBox& aabb, Real globalSA)
+	{
+		static const int dim = 3;
+		int pStart, pOn, pEnd;
+		int nLeft[dim], nPlane[dim], nRight[dim];
+		for (int i = 0; i < dim; i++)
+		{
+			nLeft[i] = 0; nPlane[i] = 0; nRight[i] = nObjects;
+		}
+
+		SplitInfo split, best;
+		best.cost = Math::POS_INFINITY;
+
+		Real parentSA = PlaneEvent::surfaceArea(aabb);
+
+		PlaneEventList::iterator begin = events->begin();
+		PlaneEventList::iterator end = events->end();
+		PlaneEventList::iterator it = begin;
+		// try all planes to find the best one for the given set of objects
+		while (it != end)
+		{
+			PlaneEventList::iterator p = it;
+			pStart = pOn = pEnd = 0;
+			while (it != end && p->equalsType(*it, PlaneEvent::PET_END))
+			{
+				it++; pEnd++;
+			}
+			while (it != end && p->equalsType(*it, PlaneEvent::PET_ON))
+			{
+				it++; pOn++;
+			}
+			while (it != end && p->equalsType(*it, PlaneEvent::PET_START))
+			{
+				it++; pStart++;
+			}
+			int d = p->getDimension();
+			nPlane[d] = pOn; nRight[d] -= pOn; nRight[d] -= pEnd;
+			p->pqSAH(globalSA, parentSA, nLeft[d], nPlane[d], nRight[d], aabb, split);
+			if (split.cost < best.cost)
+			{
+				best = split;
+			}
+			nLeft[d] += pStart; nLeft[d] += pOn; nPlane[d] = 0;
+		}
+		return new SplitInfo(best);
+	}
+
+	void KdTree::queueVisibleObjects(Camera* cam, RenderQueue* queue, bool onlyShadowCasters, bool showBoxes)
+	{
+		if (mKdRoot)
+			recQueueVisibleObjects(mKdRoot, Root::getSingleton().getCurrentFrameNumber(), cam, queue, onlyShadowCasters, showBoxes);
+	}
+
+	void KdTree::recQueueVisibleObjects(KdTree::Node * node, unsigned long currentFrame, Camera* cam, RenderQueue* queue, bool onlyShadowCasters, bool showBoxes)
+	{
+		// test visibility
+		if (cam->isVisible(node->mAABB))
+		{
+#ifdef KDTREE_DEBUG
+			WireBoundingBox * wbb = 0;
+			if (showBoxes)
+				wbb = node->getWireBoundingBox();
+#endif
+
+			if (node->isLeaf())
+			{
+				KdTree::Leaf * leaf = static_cast<KdTree::Leaf *>(node);
+				KdRenderableList::iterator it  = leaf->mKdRenderables.begin();
+				KdRenderableList::iterator end = leaf->mKdRenderables.end();
+				while (it != end)
+				{			
+					if (!(*it)->isQueued(currentFrame, cam))
+					{
+						(*it)->queueObjects(cam, queue, onlyShadowCasters);
+					}
+					it++;
+				}
+#ifdef KDTREE_DEBUG
+				if (wbb)
+					queue->addRenderable(wbb);
+#else
+				if (showBoxes)
+					queue->addRenderable(leaf->getWireBoundingBox());
+#endif
+			}
+			else
+			{
+				KdTree::Branch * branch = static_cast<KdTree::Branch *>(node);
+#ifdef KDTREE_DEBUG
+				if (wbb)
+					queue->addRenderable(wbb);
+#else
+				if (showBoxes)
+					queue->addRenderable(branch->getWireBoundingBox());
+#endif
+
+				if (branch->mLeft)
+					recQueueVisibleObjects(branch->mLeft, currentFrame, cam, queue, onlyShadowCasters, showBoxes);
+				if (branch->mRight)
+					recQueueVisibleObjects(branch->mRight, currentFrame, cam, queue, onlyShadowCasters, showBoxes);
+			}
+		}
+	}
+
+	void KdTree::dump()
+	{
+		LogManager::getSingleton().logMessage("#@#@#@#@ Dumping KdTree #@#@#@#@");
+		if (mKdRoot)
+			dump(mKdRoot);
+	}
+
+	void KdTree::dump(KdTree::Node * node)
+	{
+		LogManager * log = LogManager::getSingletonPtr();
+		KdTreeSceneNode * scenenode;
+		String pad;
+		int p;
+		
+		pad = "";
+		for (p = 0; p < node->mLevel; p++)
+		{
+			pad += " ";
+		}
+
+		if (node->isLeaf())
+		{
+			KdTree::Leaf * leaf = static_cast<KdTree::Leaf *>(node);
+			KdRenderableList::iterator it  = leaf->mKdRenderables.begin();
+			KdRenderableList::iterator end = leaf->mKdRenderables.end();
+			while (it != end)
+			{
+				scenenode = dynamic_cast<KdTreeSceneNode *>(*it);
+				log->logMessage(pad + "# Leaf   level " + StringConverter::toString(node->mLevel) + 
+					" SceneNode " + scenenode->getName());
+				log->logMessage(pad + "## Objects: " + scenenode->dumpToString());
+				it++;
+			}
+		}
+		else
+		{
+			KdTree::Branch * branch = static_cast<KdTree::Branch *>(node);
+			if (branch->mLeft)
+			{
+				log->logMessage(pad + "# Branch level " + StringConverter::toString(node->mLevel) + " Left Child");
+				dump(branch->mLeft);
+			}
+			if (branch->mRight)
+			{
+				log->logMessage(pad + "# Branch level " + StringConverter::toString(node->mLevel) + " Right Child");
+				dump(branch->mRight);
+			}
+		}
+	}
+
+	void KdTree::calcCost()
+	{
+		Real cost = 0;
+		if (mKdRoot)
+			cost = calcCost(mKdRoot, PlaneEvent::surfaceArea(mKdRoot->mAABB));
+
+		//LogManager::getSingleton().logMessage("#@#@#@ One KdTree: " + StringConverter::toString(cost));
+		mBuildLog->logMessage("#@#@#@ One KdTree: " + StringConverter::toString(cost));
+	}
+
+	Real KdTree::calcCost(KdTree::Node * node, Real vs)
+	{
+		if (node == 0)
+			return 0.0;
+
+		if (node->isLeaf())
+		{
+			KdTree::Leaf * leaf = static_cast<KdTree::Leaf *>(node);
+			return (PlaneEvent::surfaceArea(node->mAABB)/vs)*PlaneEvent::KI*leaf->mKdRenderables.size();
+		}
+		else
+		{
+			KdTree::Branch * branch = static_cast<KdTree::Branch *>(node);
+			return (PlaneEvent::surfaceArea(node->mAABB)/vs)*PlaneEvent::KT + calcCost(branch->mLeft, vs) + calcCost(branch->mRight, vs);
+		}
+	}
+
+	KdTree::Leaf::~Leaf()
+	{
+		// detach all scene nodes in the case that we are rebuilding
+		// the tree but not the scene
+		KdRenderableList::iterator it = mKdRenderables.begin();
+		KdRenderableList::iterator end = mKdRenderables.end();
+		while (it != end)
+		{
+			(*it)->detachFrom(this);
+			it++;
+		}
+		mKdRenderables.clear();
+	}
+}
Index: /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/misc/OgreKdTreeSceneManager.def
===================================================================
--- /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/misc/OgreKdTreeSceneManager.def	(revision 1163)
+++ /GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/misc/OgreKdTreeSceneManager.def	(revision 1163)
@@ -0,0 +1,5 @@
+LIBRARY Plugin_KdTreeSceneManager
+EXPORTS	
+	dllStartPlugin
+	dllShutdownPlugin
+	dllStopPlugin
Index: /GTP/trunk/Lib/Vis/Preprocessing/scripts/Preprocessor.vcproj
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/scripts/Preprocessor.vcproj	(revision 1150)
+++ /GTP/trunk/Lib/Vis/Preprocessing/scripts/Preprocessor.vcproj	(revision 1163)
@@ -29,5 +29,5 @@
 				WarningLevel="3"
 				Detect64BitPortabilityProblems="TRUE"
-				DebugInformationFormat="4"/>
+				DebugInformationFormat="3"/>
 			<Tool
 				Name="VCCustomBuildTool"/>
Index: /GTP/trunk/Lib/Vis/Preprocessing/scripts/TestPreprocessor.vcproj
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/scripts/TestPreprocessor.vcproj	(revision 1150)
+++ /GTP/trunk/Lib/Vis/Preprocessing/scripts/TestPreprocessor.vcproj	(revision 1163)
@@ -36,5 +36,5 @@
 				OutputFile="$(OutDir)/Preprocessor.exe"
 				LinkIncremental="2"
-				AdditionalLibraryDirectories="..\include;..\src\GL;&quot;$(CG_LIB_PATH)&quot;;&quot;$(GTPDIR)\NonGTP\Xerces&quot;;&quot;$(GTPDIR)\NonGTP\Xerces\xercesc\lib&quot;;&quot;$(GTPDIR)\NonGTP\zlib\lib&quot;;&quot;$(GTPDIR)\NonGTP\Devil\lib&quot;;..\lib\debug"
+				AdditionalLibraryDirectories="..\include;..\src\GL;&quot;$(CG_LIB_PATH)&quot;;&quot;$(GTPDIR)\NonGTP\Xerces&quot;;&quot;$(GTPDIR)\NonGTP\Xerces\xercesc\lib&quot;;&quot;$(GTPDIR)\NonGTP\zlib\lib&quot;;&quot;$(GTPDIR)\NonGTP\Devil\lib&quot;;..\lib\debug;&quot;$(BOOST_LIB)&quot;"
 				GenerateDebugInformation="TRUE"
 				ProgramDatabaseFile="$(OutDir)/TestPreprocessor.pdb"
Index: /GTP/trunk/Lib/Vis/shared/scripts/GtpVisibility.sln
===================================================================
--- /GTP/trunk/Lib/Vis/shared/scripts/GtpVisibility.sln	(revision 1146)
+++ /GTP/trunk/Lib/Vis/shared/scripts/GtpVisibility.sln	(revision 1163)
@@ -34,5 +34,9 @@
 	EndProjectSection
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QtRenderer", "..\..\QtRenderer\QtRenderer.vcproj", "{B85DC7B1-58B6-4912-BD64-8B452630A368}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QtGlRenderer", "..\..\QtRenderer\QtRenderer.vcproj", "{B85DC7B1-58B6-4912-BD64-8B452630A368}"
+	ProjectSection(ProjectDependencies) = postProject
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestKdTree", "..\..\..\..\App\Demos\Vis\KdTreeDemo\OGRE\scripts\TestKdTree.vcproj", "{17F2C6F9-6101-430E-ABF4-71383868EF24}"
 	ProjectSection(ProjectDependencies) = postProject
 	EndProjectSection
@@ -76,4 +80,8 @@
 		{B85DC7B1-58B6-4912-BD64-8B452630A368}.Release.ActiveCfg = Release|Win32
 		{B85DC7B1-58B6-4912-BD64-8B452630A368}.Release.Build.0 = Release|Win32
+		{17F2C6F9-6101-430E-ABF4-71383868EF24}.Debug.ActiveCfg = Debug|Win32
+		{17F2C6F9-6101-430E-ABF4-71383868EF24}.Debug.Build.0 = Debug|Win32
+		{17F2C6F9-6101-430E-ABF4-71383868EF24}.Release.ActiveCfg = Release|Win32
+		{17F2C6F9-6101-430E-ABF4-71383868EF24}.Release.Build.0 = Release|Win32
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
Index: /GTP/trunk/Lib/Vis/QtRenderer/QtRenderer.vcproj
===================================================================
--- /GTP/trunk/Lib/Vis/QtRenderer/QtRenderer.vcproj	(revision 1153)
+++ /GTP/trunk/Lib/Vis/QtRenderer/QtRenderer.vcproj	(revision 1163)
@@ -20,5 +20,5 @@
 				Name="VCCLCompilerTool"
 				Optimization="0"
-				AdditionalIncludeDirectories="&quot;$(QTDIR)\include\QtCore&quot;;&quot;$(QTDIR)\include\QtGui&quot;;&quot;$(QTDIR)\include&quot;;&quot;$(QTDIR)\include\QtOpenGl&quot;"
+				AdditionalIncludeDirectories="..\Preprocessing\src;&quot;$(QTDIR)\include\QtCore&quot;;&quot;$(QTDIR)\include\QtGui&quot;;&quot;$(QTDIR)\include&quot;;&quot;$(QTDIR)\include\QtOpenGl&quot;;..\..\..\..\..\NonGTP\Zlib\include;&quot;$(CG_INC_PATH)&quot;"
 				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;QTRENDERER_EXPORTS"
 				MinimalRebuild="TRUE"
@@ -28,14 +28,15 @@
 				WarningLevel="3"
 				Detect64BitPortabilityProblems="TRUE"
-				DebugInformationFormat="4"/>
+				DebugInformationFormat="3"/>
 			<Tool
 				Name="VCCustomBuildTool"/>
 			<Tool
 				Name="VCLinkerTool"
-				AdditionalDependencies="preprocessor.lib "
-				OutputFile="$(OutDir)/QtRenderer.dll"
-				LinkIncremental="2"
+				AdditionalDependencies="Preprocessor.lib qtmain.lib QtGui4.lib Qt3Support4.lib QAxContainer.lib QtCore4.lib QtOpenGL4.lib xerces-c_2.lib glew32.lib OpenGL32.Lib glu32.lib cg.lib cgGL.lib"
+				OutputFile="$(OutDir)/QtGlRenderer.dll"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;$(QTDIR)\lib&quot;;..\..\..\..\..\NonGTP\Zlib\lib;&quot;$(CG_LIB_PATH)&quot;;&quot;..\Preprocessing\lib\$(ConfigurationName)&quot;;..\Preprocessing\src\GL;..\..\..\..\..\NonGTP\Xerces\xercesc\lib"
 				GenerateDebugInformation="TRUE"
-				ProgramDatabaseFile="$(OutDir)/QtRenderer.pdb"
+				ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"
 				SubSystem="2"
 				ImportLibrary="$(OutDir)/QtRenderer.lib"
