Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/SceneEntity.h
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/src/SceneEntity.h	(revision 3260)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/src/SceneEntity.h	(revision 3262)
@@ -122,4 +122,7 @@
 	*/
 	static int GetCurrentVisibleId();
+
+	static AxisAlignedBox3 ComputeBoundingBox(SceneEntity **entities, int numEntities);
+	static AxisAlignedBox3 ComputeBoundingBox(const SceneEntityContainer &entities);
 
 
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/Bvh.h
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/src/Bvh.h	(revision 3259)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/src/Bvh.h	(revision 3262)
@@ -31,5 +31,5 @@
 	friend class BvhLoader;
 	friend class BvhExporter;
-	friend class mygreaterdistance;
+	friend class BvhConstructor;
 
 public:
@@ -236,5 +236,5 @@
 	//-- rendering related options
 
-	/// the bounding boxes of the test nodes are queries instead of the actual node
+	/// we  query the bounding boxes of the test nodes when testing this node
 	int mTestNodesIdx;
 	/// the number of these test nodes
@@ -246,175 +246,4 @@
 
 
-/////////////////
-//-- public inline functions
-
-
-int BvhNode::GetLastVisitedFrame() const 
-{ 
-	return mVisibility[sCurrentState].mLastVisitedFrame; 
-}
-
-
-void BvhNode::SetLastVisitedFrame(const int lastVisited) 
-{ 
-	mVisibility[sCurrentState].mLastVisitedFrame = lastVisited; 
-}
-
-
-bool BvhNode::IsVisible() const 
-{ 
-	return mVisibility[sCurrentState].mIsVisible; 
-}
-
-
-void BvhNode::SetVisible(bool visible) 
-{ 
-	mVisibility[sCurrentState].mIsVisible = visible; 
-}
-
-
-void BvhNode::IncTimesTestedInvisible() 
-{ 
-	++ mVisibility[sCurrentState].mTimesInvisible; 
-}
-
-
-int BvhNode::GetTimesTestedInvisible() const 
-{ 
-	return mVisibility[sCurrentState].mTimesInvisible; 
-}
-
-
-void BvhNode::SetTimesTestedInvisible(int t) 
-{ 
-	mVisibility[sCurrentState].mTimesInvisible = t; 
-}
-
-
-bool BvhNode::IsViewFrustumCulled() const 
-{ 
-	return mVisibility[sCurrentState].mIsFrustumCulled; 
-}
-
-
-void BvhNode::SetViewFrustumCulled(bool frustumCulled) 
-{ 
-	mVisibility[sCurrentState].mIsFrustumCulled = frustumCulled; 
-}
-
-
-bool BvhNode::IsNew() const 
-{ 
-	return mVisibility[sCurrentState].mIsNew;
-}
-
-
-void BvhNode::SetIsNew(bool isNew) 
-{ 
-	mVisibility[sCurrentState].mIsNew = isNew; 
-}
-
-
-void BvhNode::SetAssumedVisibleFrameId(int t) 
-{ 
-	mVisibility[sCurrentState].mAssumedVisibleFrameId = t; 
-}
-
-
-int BvhNode::GetAssumedVisibleFrameId() const 
-{ 
-	return mVisibility[sCurrentState].mAssumedVisibleFrameId;
-}
-
-
-int BvhNode::GetLastQueriedFrame() const
-{
-	return mVisibility[sCurrentState].mLastQueriedFrame;
-}
-
-
-void BvhNode::SetLastQueriedFrame(int lastTested)
-{
-	mVisibility[sCurrentState].mLastQueriedFrame = lastTested;
-}
-
-
-int BvhNode::GetLastRenderedFrame() const 
-{ 
-	return mLastRenderedFrame[sCurrentState]; 
-}
-	
-
-void BvhNode::SetLastRenderedFrame(int lastRenderedFrame)
-{
-	mLastRenderedFrame[sCurrentState] = lastRenderedFrame;
-}
-	
-	
-bool BvhNode::Empty() const 
-{ 
-	return (mFirst == -1); 
-}
-
-
-int BvhNode::CountPrimitives() const 
-{
-	return mLast - mFirst + 1; 
-}
-
-int BvhNode::GetDepth() const 
-{ 
-	return mDepth; 
-}
-
-
-BvhNode *BvhNode::GetParent() 
-{ 
-	return mParent; 
-}
-
-
-int BvhNode::GetNumLeaves() const
-{
-	return mNumLeaves;
-}
-
-
-bool BvhNode::IsVirtualLeaf() const
-{ 
-	return mIsVirtualLeaf; 
-}
-
-
-float BvhNode::GetDistance() const
-{
-	return mDistance; 
-}
-
-	
-const AxisAlignedBox3 &BvhNode::GetBox() const
-{
-	return mBox; 
-}
-
-
-int BvhNode::GetId() const 
-{
-	return mId; 
-}
-
-
-void BvhNode::SetId(int id) 
-{
-	mId = id; 
-}
-
-
-void BvhNode::SetCurrentState(int _state) 
-{
-	sCurrentState = _state; 
-}
-
-
 /** Internal node of the bv hierarchy.
 */
@@ -424,16 +253,17 @@
 	friend class BvhLoader;
 	friend class BvhExporter;
+	friend class BvhConstructor;
 
 public:
 
-	BvhInterior(BvhNode *parent): mBack(NULL), mFront(NULL), BvhNode(parent)
-	{}
-	virtual bool IsLeaf() const { return false; }
+	BvhInterior(BvhNode *parent);
+	
+	virtual bool IsLeaf() const;
 	/** Back child.
 	*/
-	inline BvhNode *GetBack() { return mBack; }
+	inline BvhNode *GetBack();
 	/** Front child.
 	*/
-	inline BvhNode *GetFront() { return mFront; }
+	inline BvhNode *GetFront();
 	/** Recursivly delete hierarchy.
 	*/
@@ -448,4 +278,5 @@
 
 
+
 class BvhLeaf: public BvhNode
 {
@@ -455,10 +286,9 @@
 public:
 
-	BvhLeaf(BvhNode *parent): BvhNode(parent)
-	{}
+	BvhLeaf(BvhNode *parent);
 
 	~BvhLeaf();
 
-	virtual bool IsLeaf() const { return true; }
+	virtual bool IsLeaf() const;
 };
 
@@ -485,4 +315,5 @@
 {
 	friend class BvhLoader;
+	friend class BvhConstructor;
 	friend class BvhExporter;
 
@@ -646,5 +477,5 @@
 
 	////////////
-	//-- functions influencing the tightness of the bounds that are used for testing
+	//-- these functions determine the 'tightness' of the bounds that are used for querying
 
 
@@ -681,12 +512,12 @@
 		Sets the static and dynamic objects for the hierarchy.
 	*/
-	const Bvh(const SceneEntityContainer &staticEntities, 
-		      const SceneEntityContainer &dynamicEntities);
+	Bvh(const SceneEntityContainer &staticEntities, 
+	    const SceneEntityContainer &dynamicEntities);
 	/** Protected constructor taking scene geometry into account
 		Sets the static and dynamic objects for the hierarchy.
 	*/
-	const Bvh(const SceneEntityContainer &staticEntities, 
-		      const SceneEntityContainer &dynamicEntities,
-			  int maxDepthForTestingChildren);
+	Bvh(const SceneEntityContainer &staticEntities, 
+	    const SceneEntityContainer &dynamicEntities,
+	    int maxDepthForTestingChildren);
 	/** Called by the constructor. Initializes important members.
 	*/
@@ -842,5 +673,184 @@
 
 
-int Bvh::GetNumNodes() const
+inline int BvhNode::GetLastVisitedFrame() const 
+{ 
+	return mVisibility[sCurrentState].mLastVisitedFrame; 
+}
+
+
+inline void BvhNode::SetLastVisitedFrame(const int lastVisited) 
+{ 
+	mVisibility[sCurrentState].mLastVisitedFrame = lastVisited; 
+}
+
+
+inline bool BvhNode::IsVisible() const 
+{ 
+	return mVisibility[sCurrentState].mIsVisible; 
+}
+
+
+inline void BvhNode::SetVisible(bool visible) 
+{ 
+	mVisibility[sCurrentState].mIsVisible = visible; 
+}
+
+
+inline void BvhNode::IncTimesTestedInvisible() 
+{ 
+	++ mVisibility[sCurrentState].mTimesInvisible; 
+}
+
+
+inline int BvhNode::GetTimesTestedInvisible() const 
+{ 
+	return mVisibility[sCurrentState].mTimesInvisible; 
+}
+
+
+inline void BvhNode::SetTimesTestedInvisible(int t) 
+{ 
+	mVisibility[sCurrentState].mTimesInvisible = t; 
+}
+
+
+inline bool BvhNode::IsViewFrustumCulled() const 
+{ 
+	return mVisibility[sCurrentState].mIsFrustumCulled; 
+}
+
+
+inline void BvhNode::SetViewFrustumCulled(bool frustumCulled) 
+{ 
+	mVisibility[sCurrentState].mIsFrustumCulled = frustumCulled; 
+}
+
+
+inline bool BvhNode::IsNew() const 
+{ 
+	return mVisibility[sCurrentState].mIsNew;
+}
+
+
+inline void BvhNode::SetIsNew(bool isNew) 
+{ 
+	mVisibility[sCurrentState].mIsNew = isNew; 
+}
+
+
+inline void BvhNode::SetAssumedVisibleFrameId(int t) 
+{ 
+	mVisibility[sCurrentState].mAssumedVisibleFrameId = t; 
+}
+
+
+inline int BvhNode::GetAssumedVisibleFrameId() const 
+{ 
+	return mVisibility[sCurrentState].mAssumedVisibleFrameId;
+}
+
+
+inline int BvhNode::GetLastQueriedFrame() const
+{
+	return mVisibility[sCurrentState].mLastQueriedFrame;
+}
+
+
+inline void BvhNode::SetLastQueriedFrame(int lastTested)
+{
+	mVisibility[sCurrentState].mLastQueriedFrame = lastTested;
+}
+
+
+inline int BvhNode::GetLastRenderedFrame() const 
+{ 
+	return mLastRenderedFrame[sCurrentState]; 
+}
+	
+
+inline void BvhNode::SetLastRenderedFrame(int lastRenderedFrame)
+{
+	mLastRenderedFrame[sCurrentState] = lastRenderedFrame;
+}
+	
+	
+inline bool BvhNode::Empty() const 
+{ 
+	return (mFirst == -1); 
+}
+
+
+inline int BvhNode::CountPrimitives() const 
+{
+	return mLast - mFirst + 1; 
+}
+
+inline int BvhNode::GetDepth() const 
+{ 
+	return mDepth; 
+}
+
+
+inline BvhNode *BvhNode::GetParent() 
+{ 
+	return mParent; 
+}
+
+
+inline int BvhNode::GetNumLeaves() const
+{
+	return mNumLeaves;
+}
+
+
+inline bool BvhNode::IsVirtualLeaf() const
+{ 
+	return mIsVirtualLeaf; 
+}
+
+
+inline float BvhNode::GetDistance() const
+{
+	return mDistance; 
+}
+
+	
+inline const AxisAlignedBox3 &BvhNode::GetBox() const
+{
+	return mBox; 
+}
+
+
+inline int BvhNode::GetId() const 
+{
+	return mId; 
+}
+
+
+inline void BvhNode::SetId(int id) 
+{
+	mId = id; 
+}
+
+
+inline void BvhNode::SetCurrentState(int _state) 
+{
+	sCurrentState = _state; 
+}
+
+
+inline BvhNode *BvhInterior::GetBack()
+{
+	return mBack; 
+}
+
+
+inline BvhNode *BvhInterior::GetFront() 
+{ 
+	return mFront; 
+}
+
+
+inline int Bvh::GetNumNodes() const
 {
 	return mNumNodes; 
@@ -848,5 +858,5 @@
 
 
-int Bvh::GetNumLeaves() const 
+inline int Bvh::GetNumLeaves() const 
 { 
 	return mNumNodes / 2 + 1;
@@ -854,5 +864,5 @@
 
 
-int Bvh::GetNumVirtualNodes() const  
+inline int Bvh::GetNumVirtualNodes() const  
 { 
 	return mNumVirtualNodes; 
@@ -860,5 +870,5 @@
 
 
-int Bvh::GetNumVirtualLeaves() const
+inline int Bvh::GetNumVirtualLeaves() const
 {
 	return mNumVirtualNodes / 2 + 1;
@@ -866,5 +876,5 @@
 
 
-BvhNode *Bvh::GetRoot()
+inline BvhNode *Bvh::GetRoot()
 { 
 	return mRoot; 
@@ -872,5 +882,5 @@
 
 
-BvhNode *Bvh::GetDynamicRoot()
+inline BvhNode *Bvh::GetDynamicRoot()
 { 
 	return mDynamicRoot; 
@@ -878,5 +888,5 @@
 
 
-BvhNode *Bvh::GetStaticRoot()
+inline BvhNode *Bvh::GetStaticRoot()
 { 
 	return mStaticRoot; 
@@ -884,5 +894,5 @@
 
 
-const AxisAlignedBox3 &Bvh::GetBox() const 
+inline const AxisAlignedBox3 &Bvh::GetBox() const 
 { 
 	return mBox; 
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/Bvh.cpp
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/src/Bvh.cpp	(revision 3259)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/src/Bvh.cpp	(revision 3262)
@@ -146,31 +146,30 @@
 }
 
+BvhInterior::BvhInterior(BvhNode *parent):
+mBack(NULL), mFront(NULL), BvhNode(parent)
+{}
+
+
+bool BvhInterior::IsLeaf() const
+{
+	return false; 
+}
+
+
+
+BvhLeaf::BvhLeaf(BvhNode *parent): BvhNode(parent)
+{}
+
+
+bool BvhLeaf::IsLeaf() const
+{
+	return true; 
+}
+
+
 
 /**********************************************************/
 /*                class Bvh implementation                */
 /**********************************************************/
-
-
-
-inline AxisAlignedBox3 ComputeBoundingBox(SceneEntity **entities, int numEntities)
-{
-	AxisAlignedBox3 box;
-	
-	if (!numEntities)
-	{	// no box=> just initialize
-		box.Initialize();
-	}
-	else
-	{
-		box = entities[0]->GetWorldBoundingBox();
-
-		for (int i = 1; i < numEntities; ++ i)
-		{
-			box.Include(entities[i]->GetWorldBoundingBox());
-		}
-	}
-
-	return box;
-}
 
 
@@ -1440,6 +1439,6 @@
 	leaf->mParent = parent;
 	
-	front->mBox = ComputeBoundingBox(mGeometry + front->mFirst, front->CountPrimitives());
-	leaf->mBox = ComputeBoundingBox(mGeometry + leaf->mFirst, leaf->CountPrimitives());
+	front->mBox = SceneEntity::ComputeBoundingBox(mGeometry + front->mFirst, front->CountPrimitives());
+	leaf->mBox = SceneEntity::ComputeBoundingBox(mGeometry + leaf->mFirst, leaf->CountPrimitives());
 
 	// recursively continue subdivision
@@ -1468,5 +1467,5 @@
 		SceneEntity **entities = GetGeometry(node, numEntities);
 
-		node->mBox = ComputeBoundingBox(entities, numEntities);
+		node->mBox = SceneEntity::ComputeBoundingBox(entities, numEntities);
 		//cout << "box: " << node->mBox << endl;
 	}
@@ -1488,5 +1487,5 @@
 {
 	// the bvh has two main branches
-	// a static branch (the old root), and adynamic branch 
+	// a static branch (the old root), and a dynamic branch 
 	// we create a 'dynamic' leaf which basically is a container
 	// for all dynamic objects underneath
@@ -1501,5 +1500,6 @@
 	mDynamicRoot = l;
 
-	l->mBox = ComputeBoundingBox(mGeometry + mStaticGeometrySize, (int)mDynamicGeometrySize);
+	l->mBox = SceneEntity::ComputeBoundingBox(mGeometry + mStaticGeometrySize, 
+		                                      (int)mDynamicGeometrySize);
 
 	l->mFirst = (int)mStaticGeometrySize;
@@ -1510,5 +1510,7 @@
 
 	if (mDynamicGeometrySize)
+	{
 		mDynamicRoot = SubdivideLeaf(l, 0);
+	}
 }
 
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/BvhConstructor.h
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/src/BvhConstructor.h	(revision 3262)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/src/BvhConstructor.h	(revision 3262)
@@ -0,0 +1,47 @@
+#ifndef __BVHCONSTRUCTOR_H
+#define __BVHCONSTRUCTOR_H
+
+#include "Bvh.h"
+
+
+
+namespace CHCDemoEngine
+{
+
+/** This class represents a bvh construction algorithm
+*/
+class BvhConstructor
+{
+	BvhConstructor(SceneEntity **entities, int first, int last);
+
+	/** Constructs a bvh and returns the root and the number of bvh nodes.
+	*/
+	BvhNode *Construct(int &nodes);
+
+
+protected:
+
+	int SortTriangles(BvhLeaf *leaf, int axis, float position);
+
+	int SortTrianglesSpatialMedian(BvhLeaf *leaf, int axis);
+
+	BvhNode *SubdivideLeaf(BvhLeaf *leaf, int parentAxis);
+
+	inline bool TerminationCriteriaMet(BvhLeaf *leaf) const;
+
+
+	/////////////////
+
+	SceneEntity **mEntities;
+
+	int mFirst;
+	int mLast;
+
+	int mMaxDepth;
+	int mMaxObjects;
+	int mNumNodes;
+};
+
+}
+
+#endif // __BVH_H
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/SceneEntity.cpp
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/src/SceneEntity.cpp	(revision 3259)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/src/SceneEntity.cpp	(revision 3262)
@@ -183,3 +183,49 @@
 
 
-}
+AxisAlignedBox3 SceneEntity::ComputeBoundingBox(SceneEntity **entities, int numEntities)
+{
+	AxisAlignedBox3 box;
+	
+	if (!numEntities)
+	{	// no box => just initialize
+		box.Initialize();
+	}
+	else
+	{
+		box = entities[0]->GetWorldBoundingBox();
+
+		for (int i = 1; i < numEntities; ++ i)
+		{
+			box.Include(entities[i]->GetWorldBoundingBox());
+		}
+	}
+
+	return box;
+}
+
+
+AxisAlignedBox3 SceneEntity::ComputeBoundingBox(const SceneEntityContainer &entities)
+{
+	AxisAlignedBox3 box;
+	
+	if (!entities.empty())
+	{	// no box => just initialize
+		box.Initialize();
+	}
+	else
+	{
+		box = entities[0]->GetWorldBoundingBox();
+
+		for (size_t i = 1; i < entities.size(); ++ i)
+		{
+			box.Include(entities[i]->GetWorldBoundingBox());
+		}
+	}
+
+	return box;
+}
+
+
+
+
+}
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/BvhConstructor.cpp
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/src/BvhConstructor.cpp	(revision 3262)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/src/BvhConstructor.cpp	(revision 3262)
@@ -0,0 +1,176 @@
+#include "BvhConstructor.h"
+#include "Triangle3.h"
+#include "SceneEntity.h"
+#include "Geometry.h"
+#include "gzstream.h"
+
+#include <queue>
+#include <stack>
+#include <fstream>
+
+#ifdef _CRT_SET
+	#define _CRTDBG_MAP_ALLOC
+	#include <stdlib.h>
+	#include <crtdbg.h>
+
+	// redefine new operator
+	#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
+	#define new DEBUG_NEW
+#endif
+
+
+using namespace std;
+
+
+namespace CHCDemoEngine
+{
+
+BvhConstructor::BvhConstructor(SceneEntity **entities, 
+							   int first, 
+							   int last):
+mEntities(entities),
+mFirst(first),
+mLast(last),
+mMaxDepth(10),
+mMaxObjects(1),
+mNumNodes(0)
+{
+}
+
+
+int BvhConstructor::SortTriangles(BvhLeaf *leaf, 
+								  int axis, 
+								  float position)
+{
+	int i = leaf->mFirst;
+	int j = leaf->mLast;
+
+    while (1)
+	{
+		while (mEntities[i]->GetWorldCenter()[axis] < position) ++ i;
+		//while ((j > 0) && (position < mGeometry[j]->GetWorldCenter()[axis])) -- j;
+		while (position < mEntities[j]->GetWorldCenter()[axis]) -- j;
+
+		// sorting finished
+		if (i >= j) break;
+
+		// swap entities
+		swap(mEntities[i], mEntities[j]);
+			
+		++ i;
+		-- j;
+	}
+
+	return j;
+}
+
+
+int BvhConstructor::SortTrianglesSpatialMedian(BvhLeaf *leaf, 
+											   int axis)
+{
+	// spatial median
+	float m = leaf->GetBox().Center()[axis];
+	return SortTriangles(leaf, axis, m);
+}
+
+
+BvhNode *BvhConstructor::SubdivideLeaf(BvhLeaf *leaf, 
+									   int parentAxis
+									   )
+{
+	if (TerminationCriteriaMet(leaf))
+	{
+		cout << "leaf constructed:" << leaf->mBox << " " << leaf->mFirst << " " << leaf->mLast << endl;
+		return leaf;
+	}
+
+	//const int axis = (parentAxis + 1) % 3;
+	const int axis = leaf->mBox.MajorAxis();
+	const int scale = 20;
+
+	// position of the split in the partailly sorted array of triangles
+	// corresponding to this leaf
+	int split = -1;
+	float pos = -1.0f;
+	
+	// Spatial median subdivision
+	split = SortTrianglesSpatialMedian(leaf, axis);
+	pos = leaf->mBox.Center()[axis];
+	
+	if (split == leaf->mLast)
+	{
+		// no split could be achieved => just halve number of objects
+		split = (leaf->mLast - leaf->mFirst) / 2;
+		cerr << "no reduction " << leaf->CountPrimitives() << " " << leaf->mFirst << " " << leaf->mLast << endl;
+	}
+
+	// create two more nodes
+	mNumNodes += 2;
+	BvhInterior *parent = new BvhInterior(leaf->GetParent());
+	parent->mFirst = leaf->mFirst;
+	parent->mLast = leaf->mLast;
+	
+	parent->mAxis = axis;
+	parent->mBox = leaf->mBox;
+	parent->mDepth = leaf->mDepth;
+
+	BvhLeaf *front = new BvhLeaf(parent);
+
+	parent->mBack = leaf;
+	parent->mFront = front;
+		
+	// now assign the triangles to the subnodes
+	front->mFirst = split + 1;
+	front->mLast = leaf->mLast;
+	front->mDepth = leaf->mDepth + 1;
+
+	leaf->mLast = split;
+	leaf->mDepth = front->mDepth;
+	leaf->mParent = parent;
+	
+	front->mBox = SceneEntity::ComputeBoundingBox(mEntities + front->mFirst, front->CountPrimitives());
+	leaf->mBox = SceneEntity::ComputeBoundingBox(mEntities + leaf->mFirst, leaf->CountPrimitives());
+
+	// recursively continue subdivision
+	parent->mBack = SubdivideLeaf(static_cast<BvhLeaf *>(parent->mBack), axis);
+	parent->mFront = SubdivideLeaf(static_cast<BvhLeaf *>(parent->mFront), axis);
+	
+	return parent;
+}
+
+
+bool BvhConstructor::TerminationCriteriaMet(BvhLeaf *leaf) const
+{
+	const bool criteriaMet = 
+		(leaf->mDepth > mMaxDepth) ||
+		(leaf->CountPrimitives() <= mMaxObjects);
+
+	return criteriaMet;
+}
+
+
+BvhNode *BvhConstructor::Construct(int &numNodes)
+{
+	BvhNode *root;
+
+	mNumNodes = 1;
+
+	BvhLeaf *l = new BvhLeaf(NULL);
+	
+	l->mBox = SceneEntity::ComputeBoundingBox(mEntities + mFirst, mFirst - mLast + 1);
+
+	l->mFirst = mFirst;
+	l->mLast = mLast;
+	l->mArea = l->mBox.SurfaceArea();
+	
+	cout << "constructing bvh"  << endl;
+
+	root = SubdivideLeaf(l, 0);
+
+	numNodes = mNumNodes;
+
+	return root;
+}
+
+
+}
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/MainApp.vcproj
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/MainApp.vcproj	(revision 3261)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/MainApp.vcproj	(revision 3262)
@@ -130,4 +130,5 @@
 				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS"
 				RuntimeLibrary="2"
+				BufferSecurityCheck="false"
 				EnableEnhancedInstructionSet="2"
 				RuntimeTypeInfo="false"
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/VboFormatConverter.vcproj
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/VboFormatConverter.vcproj	(revision 3260)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/VboFormatConverter.vcproj	(revision 3262)
@@ -125,4 +125,5 @@
 				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
 				RuntimeLibrary="2"
+				RuntimeTypeInfo="false"
 				UsePrecompiledHeader="0"
 				WarningLevel="3"
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/FriendlyCulling.vcproj
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/FriendlyCulling.vcproj	(revision 3260)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/FriendlyCulling.vcproj	(revision 3262)
@@ -160,4 +160,12 @@
 			>
 			<File
+				RelativePath=".\src\BvhConstructor.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\BvhConstructor.h"
+				>
+			</File>
+			<File
 				RelativePath=".\src\BvhExporter.cpp"
 				>
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/ObjConverter2.cpp
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/ObjConverter2.cpp	(revision 3261)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/ObjConverter2.cpp	(revision 3262)
@@ -12,5 +12,5 @@
 						const VertexArray &vertices, 
 						const VertexArray &normals, 
-						const vector<pair<float, float> > &texcoords,
+						const vector<Texcoord> &texcoords,
 						VertexArray &faceVertices,
 						VertexArray &faceNormals,
@@ -28,5 +28,4 @@
 	{
 		string s(pch);
-		//s += "\n",
 		triples.push_back(s);
 		
@@ -34,27 +33,31 @@
 	}
 
+	// throw away last symbol (\n)
+	triples.back().resize(triples.back().size() - 1);
+
 	vector<int> indices;
 	vector<int> nIndices;
 	vector<int> tIndices;
 
-	char seps[] = " /\t\n";
+	char seps[] = " ";
+	char seps2[] = "/";
 
 	for (size_t i = 0; i < triples.size(); ++ i)
 	{
-		static int dummy = 0;
-
+		//cout << "triple " << i << " " << triples[i] << endl;
 		size_t found;
-		found = triples[i].find_first_of(seps);
+		found = triples[i].find_first_of(seps2);
 		size_t prevfound = 0;
-		// vertex, normal, texture indices
+
+		// extract vertex, normal, texture indices
 		string str = triples[i].substr(prevfound, found);
 
 		int index = (int)strtol(str.c_str(), NULL, 10) - 1;
-
 		int tIndex = index;
 		int nIndex = index;	
 		
-		prevfound = found;
-		found = triples[i].find_first_of(seps, found + 1);  
+		// try to extract texture and normal indices
+		prevfound = found + 1;
+		found = triples[i].find_first_of(seps2, prevfound);  
 
 		if (found != string::npos)
@@ -65,6 +68,6 @@
 			if (idx > 0) tIndex = idx;
 		}
-
-		if ((found + 1) < triples[i].size())
+		
+		if (found != string::npos)
 		{
 			str = triples[i].substr(found + 1);
@@ -80,6 +83,9 @@
 			nIndices.push_back(nIndex);
 			tIndices.push_back(tIndex);
-		}
-
+
+			//cout << index << " " << tIndex << " " << nIndex << endl;
+		}
+
+		int idx[3];
 		// new triangle found
 		if (indices.size() > 2)
@@ -87,29 +93,28 @@
 			// change orientation of faces?
 #if 1
-			int idx1 = 0;
-			int idx2 = (int)indices.size() - 2;
-			int idx3 = (int)indices.size() - 1;
+			idx[0] = 0;
+			idx[1] = (int)indices.size() - 2;
+			idx[2] = (int)indices.size() - 1;
 #else
-			int idx3 = 0;
-			int idx2 = (int)indices.size() - 2;
-			int idx1 = (int)indices.size() - 1;
+			idx[2] = 0;
+			idx[1] = (int)indices.size() - 2;
+			idx[0] = (int)indices.size() - 1;
 #endif
-			faceVertices.push_back(vertices[indices[idx1]]);
-			faceVertices.push_back(vertices[indices[idx2]]);
-			faceVertices.push_back(vertices[indices[idx3]]);
+			for (int j = 0; j < 3; ++ j)
+				faceVertices.push_back(vertices[indices[idx[j]]]);
 
 
 			if (!normals.empty())
 			{
-				faceNormals.push_back(normals[nIndices[idx1]]);
-				faceNormals.push_back(normals[nIndices[idx2]]);
-				faceNormals.push_back(normals[nIndices[idx3]]);
+				for (int j = 0; j < 3; ++ j)
+					faceNormals.push_back(normals[nIndices[idx[j]]]);
 			}
 			else
 			{
 				// no face normals? => create normals
-				const SimpleTri tri(vertices[indices[idx1]],
-					                vertices[indices[idx2]], 
-									vertices[indices[idx3]]);
+				const SimpleTri tri(vertices[indices[idx[0]]],
+					                vertices[indices[idx[1]]], 
+									vertices[indices[idx[2]]]);
+
 				const SimpleVec n = tri.GetNormal();
 
@@ -121,7 +126,12 @@
 			if (!texcoords.empty())
 			{
-				faceTexcoords.push_back(texcoords[tIndices[idx1]]);
-				faceTexcoords.push_back(texcoords[tIndices[idx2]]);
-				faceTexcoords.push_back(texcoords[tIndices[idx3]]);
+				for (int j = 0; j < 3; ++ j)
+				{
+					if (tIndices[idx[j]] >= (int)texcoords.size())
+						cerr << "error: texcoord indices exceed array size " << texcoords.size() << " " << tIndices[idx[j]] << endl;
+					const int tidx = min((int)texcoords.size() - 1, tIndices[idx[j]]);
+
+					faceTexcoords.push_back(texcoords[tidx]);
+				}
 			}
 		}
@@ -219,5 +229,4 @@
 	}
 
-
 	return true;
 }
@@ -233,12 +242,16 @@
 	for (it = filenames.begin(); it != it_end; ++ it)
 	{
-		cout << "\n==================\n loading file " << *it << endl;
-
-		if (!ReadFile(*it))
-		{
-			cerr << "could not read file " << *it << endl;
-			return false;
-		}
-	}
+		const string filename = *it;
+
+		cout << "\n==================\n loading file " << filename << endl;
+
+		if (!ReadFile(filename))
+		{
+			cerr << "could not read file ... skipping " << filename << endl;
+			//return false;
+		}
+	}
+
+	cout << "\n*******************\n writing file " << outputFilename << endl;
 
 	if (!WriteFile(outputFilename))
@@ -279,4 +292,6 @@
 	while (fgets(str, len, file) != NULL)
 	{
+		//cout << "line: " << line << endl;
+
 		switch (str[0])
 		{
@@ -323,4 +338,6 @@
 				//-- indices in the current line
 
+				//cout << "f: " << vertices.size() << " n: " << normals.size() << " " << texcoords.size() << endl;
+
 				LoadIndices(str, 
 					        vertices, normals, texcoords, 
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/main.cpp
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/main.cpp	(revision 3261)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/main.cpp	(revision 3262)
@@ -32,5 +32,5 @@
 	
 	//const int numFiles = 879;
-	const int numFiles = 100;
+	const int numFiles = 300;
 
 	vector<string> filenames;
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter.vcproj
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter.vcproj	(revision 3261)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter.vcproj	(revision 3262)
@@ -133,4 +133,5 @@
 				StringPooling="true"
 				RuntimeLibrary="2"
+				BufferSecurityCheck="false"
 				EnableEnhancedInstructionSet="2"
 				RuntimeTypeInfo="false"
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/default.env
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/default.env	(revision 3260)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/default.env	(revision 3262)
@@ -23,5 +23,5 @@
 visibilitySolution=vienna_full-8x3-pgv
 viewCellsScaleFactor=1.0f
-useSkylightForIllum=1
+useSkylightForIllum=0
 
 
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/VisibilitySolutionConverter.vcproj
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/VisibilitySolutionConverter.vcproj	(revision 3258)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/VisibilitySolutionConverter.vcproj	(revision 3262)
@@ -122,7 +122,16 @@
 				Name="VCCLCompilerTool"
 				AdditionalOptions=" /D &quot;_CRT_SECURE_NO_WARNINGS&quot;"
+				Optimization="3"
+				InlineFunctionExpansion="2"
+				EnableIntrinsicFunctions="true"
+				FavorSizeOrSpeed="1"
+				OmitFramePointers="true"
+				EnableFiberSafeOptimizations="true"
 				AdditionalIncludeDirectories="libs\Zlib\include; src"
 				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
 				RuntimeLibrary="2"
+				BufferSecurityCheck="false"
+				EnableEnhancedInstructionSet="2"
+				RuntimeTypeInfo="false"
 				UsePrecompiledHeader="0"
 				WarningLevel="3"
@@ -145,9 +154,10 @@
 				AdditionalLibraryDirectories="libs\Zlib\lib; lib\$(ConfigurationName)"
 				IgnoreDefaultLibraryNames="libCMT"
-				GenerateDebugInformation="true"
+				GenerateDebugInformation="false"
 				SubSystem="1"
 				LargeAddressAware="2"
 				OptimizeReferences="2"
 				EnableCOMDATFolding="2"
+				OptimizeForWindows98="1"
 				TargetMachine="1"
 			/>
