Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/FriendlyCulling.sln
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/FriendlyCulling.sln	(revision 3010)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/FriendlyCulling.sln	(revision 3012)
@@ -6,8 +6,10 @@
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Converter", "Converter.vcproj", "{93A522E1-76F0-4D46-9C97-30DC2DDB531D}"
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FriendlyCulling", "MainApp.vcproj", "{A564071F-D054-4556-883B-999D7F9CC58C}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MainApp", "MainApp.vcproj", "{A564071F-D054-4556-883B-999D7F9CC58C}"
 	ProjectSection(ProjectDependencies) = postProject
 		{03661866-4093-4B02-B26A-028EA91AF023} = {03661866-4093-4B02-B26A-028EA91AF023}
 	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IrradianceMapping", "IrradianceMapping.vcproj", "{91680C49-A358-48AE-A02C-66CB884B7D7F}"
 EndProject
 Global
@@ -29,4 +31,8 @@
 		{A564071F-D054-4556-883B-999D7F9CC58C}.Release|Win32.ActiveCfg = Release|Win32
 		{A564071F-D054-4556-883B-999D7F9CC58C}.Release|Win32.Build.0 = Release|Win32
+		{91680C49-A358-48AE-A02C-66CB884B7D7F}.Debug|Win32.ActiveCfg = Debug|Win32
+		{91680C49-A358-48AE-A02C-66CB884B7D7F}.Debug|Win32.Build.0 = Debug|Win32
+		{91680C49-A358-48AE-A02C-66CB884B7D7F}.Release|Win32.ActiveCfg = Release|Win32
+		{91680C49-A358-48AE-A02C-66CB884B7D7F}.Release|Win32.Build.0 = Release|Win32
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/MainApp.vcproj
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/MainApp.vcproj	(revision 3011)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/MainApp.vcproj	(revision 3012)
@@ -3,5 +3,5 @@
 	ProjectType="Visual C++"
 	Version="8,00"
-	Name="FriendlyCulling"
+	Name="MainApp"
 	ProjectGUID="{A564071F-D054-4556-883B-999D7F9CC58C}"
 	RootNamespace="MainApp"
@@ -143,4 +143,5 @@
 				Name="VCLinkerTool"
 				AdditionalDependencies="DemoEngine.lib glut32.lib glew32s.lib glew32.lib DevIL.lib ILUT.lib zlib.lib cg.lib cgGL.lib"
+				OutputFile="$(OutDir)\FriendlyCulling.exe"
 				LinkIncremental="1"
 				AdditionalLibraryDirectories="&quot;lib/$(ConfigurationName)&quot;;libs;&quot;$(CG_LIB_PATH)&quot;;libs/GL;libs/Devil/lib;libs/Zlib/lib"
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/chcdemo.cpp
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/src/chcdemo.cpp	(revision 3010)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/src/chcdemo.cpp	(revision 3012)
@@ -59,4 +59,6 @@
 /// the renderable scene geometry
 SceneEntityContainer sceneEntities;
+SceneEntityContainer sceneEntities2;
+
 // traverses and renders the hierarchy
 RenderTraverser *traverser = NULL;
@@ -440,12 +442,11 @@
 	loader = new ResourceManager();
 
-	//const string filename("data/city/model/city.dem");
 	const string filename = string(model_path + "city.dem");
 
 	if (loader->Load(filename, sceneEntities))
-		cout << "scene " << filename << " loaded" << endl;
+		cout << "model " << filename << " loaded" << endl;
 	else
 	{
-		cerr << "loading scene " << filename << " failed" << endl;
+		cerr << "loading model " << filename << " failed" << endl;
 		CleanUp();
 		exit(0);
@@ -463,45 +464,4 @@
 	}
 	
-#if 0
-
-	int merged = 0;
-
-	SceneEntity *oldEnt = NULL;
-
-	cout << "merging entities .. " << endl;
-	SceneEntityContainer::const_iterator sit, sit_end = sceneEntities.end();
-
-	for (sit = sceneEntities.begin(); sit < sit_end; ++ sit)
-	{
-		SceneEntity *newEnt = (*sit);
-
-		if (!newEnt->GetTransform()->IsIdentity())
-		{
-			sceneEntities2.push_back(newEnt);
-			continue;
-		}
-
-		if (oldEnt)
-		{
-			EntityMerger merger(newEnt, oldEnt);
-			SceneEntity *ent = merger.Merge();
-
-			sceneEntities2.push_back(ent);
-
-			oldEnt = NULL;
-
-			++ merged;
-		}
-		else
-		{
-			oldEnt = newEnt;
-		}
-	}
-
-	if (oldEnt && oldEnt->GetTransform()->IsIdentity())
-		sceneEntities2.push_back(oldEnt);
-
-	cout << "merged " << merged << " of " << (int)sceneEntities.size() << " entities " << endl;
-#endif
 
 	// set far plane based on scene extent
@@ -1171,5 +1131,4 @@
 		// actually render the scene geometry using the specified algorithm
 		traverser->RenderScene();
-		//renderQueue->Apply();
 	}
 
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/ObjConverter.cpp
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/ObjConverter.cpp	(revision 2965)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/ObjConverter.cpp	(revision 3012)
@@ -1,3 +1,5 @@
 #include "ObjConverter.h"
+#include "SimpleTri.h"
+#include "SimpleVec.h"
 #include "gzstream.h"
 #include <iostream>
@@ -35,5 +37,5 @@
 	for (size_t i = 0; i < substrings.size(); ++ i)
 	{
-		// vertex, normal and texture indices
+		// vertex, normal, texture indices
 		char *str = strtok_s(substrings[i], "/", &next_token);	  
 		int index = (int)strtol(str, NULL, 10) - 1;
@@ -42,10 +44,19 @@
 		int nIndex = index;
 
-		/*str = strtok_s(substrings[i], "/", &next_token);	  
-		int tIndex = (int)strtol(str, NULL, 10) - 1;
-
 		str = strtok_s(substrings[i], "/", &next_token);	  
-		int nIndex = (int)strtol(str, NULL, 10) - 1;
-*/
+
+		if (str != NULL)
+		{
+			int idx = (int)strtol(str, NULL, 10) - 1;
+			if (idx) tIndex = idx;
+		}
+		str = strtok_s(substrings[i], "/", &next_token);	  
+
+		if (str != NULL)
+		{
+			int idx = (int)strtol(str, NULL, 10) - 1;
+			if (idx) nIndex = idx;
+		}
+
 		// store indices
 		if (index >= 0)
@@ -59,5 +70,5 @@
 		if (indices.size() > 2)
 		{
-#if 1
+#if 0
 			int idx1 = 0;
 			int idx2 = (int)indices.size() - 2;
@@ -71,22 +82,28 @@
 			faceVertices.push_back(vertices[indices[idx2]]);
 			faceVertices.push_back(vertices[indices[idx3]]);
-	
-			Vector3 dummy(1, 0, 0);
-			faceNormals.push_back(dummy);
-			faceNormals.push_back(dummy);
-			faceNormals.push_back(dummy);
-
-			/*
-			const Vector3 v2 = mVertices[2] - mVertices[1];
-			Normalize(CrossProd(v2, v1));
-
-			faceNormals.push_back(normals[nIndices[idx1]]);
-			faceNormals.push_back(normals[nIndices[idx2]]);
-			faceNormals.push_back(normals[nIndices[idx3]]);
-
-			faceTexcoords.push_back(texcoords[tIndices[idx1]]);
-			faceTexcoords.push_back(texcoords[tIndices[idx2]]);
-			faceTexcoords.push_back(texcoords[tIndices[idx3]]);
-			*/
+
+			if (!normals.empty())
+			{
+				faceNormals.push_back(normals[nIndices[idx1]]);
+				faceNormals.push_back(normals[nIndices[idx2]]);
+				faceNormals.push_back(normals[nIndices[idx3]]);
+			}
+			else
+			{
+				// no face normals?
+				const SimpleTri tri(vertices[indices[idx1]], vertices[indices[idx2]], vertices[indices[idx3]]);
+				const SimpleVec n = tri.GetNormal();
+
+				faceNormals.push_back(n);
+				faceNormals.push_back(n);
+				faceNormals.push_back(n);
+			}
+
+			if (!texcoords.empty())
+			{
+				faceTexcoords.push_back(texcoords[tIndices[idx1]]);
+				faceTexcoords.push_back(texcoords[tIndices[idx2]]);
+				faceTexcoords.push_back(texcoords[tIndices[idx3]]);
+			}
 		}
 	}
@@ -121,6 +138,6 @@
 
 	// convert the triangles to geometry
-	geom->mVertices = new Vector3[numElements];
-	geom->mNormals = new Vector3[numElements];
+	geom->mVertices = new SimpleVec[numElements];
+	geom->mNormals = new SimpleVec[numElements];
 	geom->mTexcoords = new Texcoord[numElements];
 
@@ -132,12 +149,22 @@
 	for (int i = 0; i < numElements; ++ i)
 	{
+#if 0
 		geom->mVertices[i].x = faceVertices[i].x;
 		geom->mVertices[i].y = -faceVertices[i].z;
 		geom->mVertices[i].z = faceVertices[i].y;
-
+	
 		geom->mNormals[i].x = faceNormals[i].x;
 		geom->mNormals[i].y = -faceNormals[i].z;
 		geom->mNormals[i].z = faceNormals[i].y;
-
+#else
+		geom->mVertices[i].x = faceVertices[i].x;
+		geom->mVertices[i].y = faceVertices[i].y;
+		geom->mVertices[i].z = faceVertices[i].z;
+	
+		geom->mNormals[i].x = faceNormals[i].x;
+		geom->mNormals[i].y = faceNormals[i].y;
+		geom->mNormals[i].z = faceNormals[i].z;
+
+#endif
 		if (i < geom->mTexcoordCount)
 		{
@@ -220,5 +247,5 @@
 				case 'n' :
 					sscanf(str + 2, "%f %f %f", &x, &y, &z);
-					normals.push_back(Vector3(x, y, z));
+					normals.push_back(SimpleVec(x, y, z));
 					break;
 				case 't':
@@ -228,5 +255,5 @@
 				default:
 					sscanf(str + 1, "%f %f %f", &x, &y, &z);
-					vertices.push_back(Vector3(x, y, z));
+					vertices.push_back(SimpleVec(x, y, z));
 					//cout <<"v " << x << " " << y << " "<< z << " ";
 				}
@@ -242,6 +269,6 @@
 					        faceVertices, faceNormals, faceTexcoords);
 
-				if (((line % 1000) == 999) && 
-					!faceVertices.empty())
+				if (0 &&
+					(((line % 1000) == 999) && !faceVertices.empty()))
 				{
 					++ mNumShapes;
@@ -299,6 +326,6 @@
 	str.write(reinterpret_cast<char *>(&vertexCount), sizeof(int));
   
-	str.write(reinterpret_cast<char *>(geom->mVertices), sizeof(Vector3) * vertexCount);
-	str.write(reinterpret_cast<char *>(geom->mNormals), sizeof(Vector3) * vertexCount);
+	str.write(reinterpret_cast<char *>(geom->mVertices), sizeof(SimpleVec) * vertexCount);
+	str.write(reinterpret_cast<char *>(geom->mNormals), sizeof(SimpleVec) * vertexCount);
 
 	int texCoordCount = geom->mTexcoordCount;
@@ -330,5 +357,5 @@
 	if (hasMaterial)
 	{
-		Vector3 ambient, diffuse, black;
+		SimpleVec ambient, diffuse, black;
 
 		ambient.x = ambient.y = ambient.z = 0.2f;
@@ -337,8 +364,8 @@
 
 		// only write rgb part of the material
-		str.write(reinterpret_cast<char *>(&ambient), sizeof(Vector3));
-		str.write(reinterpret_cast<char *>(&diffuse), sizeof(Vector3));
-		str.write(reinterpret_cast<char *>(&black), sizeof(Vector3));
-		str.write(reinterpret_cast<char *>(&black), sizeof(Vector3));
+		str.write(reinterpret_cast<char *>(&ambient), sizeof(SimpleVec));
+		str.write(reinterpret_cast<char *>(&diffuse), sizeof(SimpleVec));
+		str.write(reinterpret_cast<char *>(&black), sizeof(SimpleVec));
+		str.write(reinterpret_cast<char *>(&black), sizeof(SimpleVec));
 	}
 }
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/main.cpp
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/main.cpp	(revision 2963)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/main.cpp	(revision 3012)
@@ -15,18 +15,9 @@
 	cout << "converting obj to dem format" << endl;
 
-/*	if (!converter.Convert(model_path + argv[1], model_path + argv[2]))
+	if (!converter.Convert(model_path + argv[1], model_path + argv[2]))
 	{
 		cerr << "conversion failed" << endl;
 		exit(0);
 	}
-*/
-	//if (!converter.Convert(model_path + "toyplane.obj", model_path + "toyplane.dem"))
-	//	cerr << "conversion failed" << endl;
-
-	//if (!converter.Convert(model_path + "sky.obj", model_path + "sky.dem"))
-	//	cerr << "conversion failed" << endl;
-
-	if (!converter.Convert(model_path + "city_full.obj", model_path + "city_full.dem"))
-		cerr << "conversion failed" << endl;
 
 	cout << "conversion successful" << endl;
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/ObjConverter.h
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/ObjConverter.h	(revision 2961)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/ObjConverter.h	(revision 3012)
@@ -2,16 +2,17 @@
 #define _OBJCONVERTER_H
 
+#include "SimpleVec.h"
 #include <string>
 #include <vector>
 
-struct Vector3
+/*struct SimpleVec
 {
-	Vector3() {}
-	Vector3(float _x, float _y, float _z): x(_x), y(_y), z(_z) {}
+	SimpleVec() {}
+	SimpleVec(float _x, float _y, float _z): x(_x), y(_y), z(_z) {}
 
 	float x, y, z;
-};
+};*/
 
-typedef std::vector<Vector3> VertexArray;
+typedef std::vector<SimpleVec> VertexArray;
 typedef std::pair<float, float> Texcoord;
 
@@ -36,6 +37,6 @@
 	struct Geometry
 	{
-		Vector3 *mVertices;
-		Vector3 *mNormals;
+		SimpleVec *mVertices;
+		SimpleVec *mNormals;
 		Texcoord *mTexcoords;
 
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/SimpleVec.cpp
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/SimpleVec.cpp	(revision 3012)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/SimpleVec.cpp	(revision 3012)
@@ -0,0 +1,103 @@
+#include "SimpleVec.h"
+#include <float.h>
+
+
+
+// Given min a vector to minimize and a candidate vector, replace
+// elements of min whose corresponding elements in Candidate are
+// smaller.  This function is used for finding objects' bounds,
+// among other things.
+void Minimize(SimpleVec &min, const SimpleVec &Candidate)
+{
+	if (Candidate.x < min.x)
+		min.x = Candidate.x;
+	if (Candidate.y < min.y)
+		min.y = Candidate.y;
+	if (Candidate.z < min.z)
+		min.z = Candidate.z;
+}
+
+// Given min a vector to minimize and a candidate vector, replace
+// elements of min whose corresponding elements in Candidate are
+// larger.  This function is used for finding objects' bounds,
+// among other things.
+void Maximize(SimpleVec &max, const SimpleVec &Candidate)
+{
+	if (Candidate.x > max.x)
+		max.x = Candidate.x;
+	if (Candidate.y > max.y)
+		max.y = Candidate.y;
+	if (Candidate.z > max.z)
+		max.z = Candidate.z;
+}
+
+// Project the vector onto the YZ, XZ, or XY plane depending on which.
+// which      Coordinate plane to project onto
+// 0          YZ
+// 1          XZ
+// 2          XY
+// This function is used by the polygon intersection code.
+
+void SimpleVec::ExtractVerts(float *px, float *py, int which) const
+{
+	switch (which) {
+	case 0:
+		*px = y;
+		*py = z;
+		break;
+	case 1:
+		*px = x;
+		*py = z;
+		break;
+	case 2:
+		*px = x;
+		*py = y;
+		break;
+	}
+}
+
+// returns the axis, where the vector has the largest value
+int
+SimpleVec::DrivingAxis(void) const
+{
+	int axis = 0;
+	float val = fabs(x);
+
+	if (fabs(y) > val) {
+		val = fabs(y);
+		axis = 1;
+	}
+
+	if (fabs(z) > val)
+		axis = 2;
+
+	return axis;
+}
+
+
+// returns the axis, where the vector has the smallest value
+int SimpleVec::TinyAxis(void) const
+{
+	int axis = 0;
+	float val = fabs(x);
+
+	if (fabs(y) < val) {
+		val = fabs(y);
+		axis = 1;
+	}
+
+	if (fabs(z) < val)
+		axis = 2;
+
+	return axis;
+}
+
+
+bool SimpleVec::CheckValidity() const
+{
+#ifdef _WIN32
+	return !(_isnan(x) || _isnan(y) || _isnan(z));
+#else
+	return !(isnan(x) || isnan(y) || isnan(z));
+#endif  
+}
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/SimpleTri.cpp
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/SimpleTri.cpp	(revision 3012)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/SimpleTri.cpp	(revision 3012)
@@ -0,0 +1,41 @@
+#include "SimpleTri.h"
+
+
+using namespace std;
+
+
+SimpleTri::SimpleTri(const SimpleVec &a, const SimpleVec &b, const SimpleVec &c) 
+{
+	Init(a, b, c);
+}
+
+
+void SimpleTri::Init(const SimpleVec &a, const SimpleVec &b, const SimpleVec &c) 
+{
+	mVertices[0] = a;
+	mVertices[1] = b;
+	mVertices[2] = c;
+}
+
+
+SimpleVec SimpleTri::GetNormal() const 
+{
+	const SimpleVec v1 = mVertices[0] - mVertices[1];
+	const SimpleVec v2 = mVertices[2] - mVertices[1];
+
+	return Normalize(CrossProd(v2, v1));
+}
+
+
+SimpleVec SimpleTri::GetCenter() const 
+{
+	return (mVertices[0] + mVertices[1] + mVertices[2]) / 3.0f;
+}
+
+
+float SimpleTri::GetArea() const 
+{
+	SimpleVec v1 = mVertices[0] - mVertices[1], v2=mVertices[2] - mVertices[1];
+	return 0.5f * Magnitude(CrossProd(v2, v1));
+}
+
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/SimpleVec.h
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/SimpleVec.h	(revision 3012)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/SimpleVec.h	(revision 3012)
@@ -0,0 +1,489 @@
+#ifndef _SimpleVec_h__
+#define _SimpleVec_h__
+
+
+#include <math.h>
+#include <vector>
+#include <iostream>
+
+
+/** Vector class.
+*/
+class SimpleVec
+{
+public:
+
+	///////////
+	//-- members;
+
+	float x; 
+	float y;
+	float z;
+
+
+	/////////////////////////
+
+	void  SetX(float q) { x = q; }
+	void  SetY(float q) { y = q; }
+	void  SetZ(float q) { z = q; }
+
+	float GetX() const { return x; }
+	float GetY() const { return y; }
+	float GetZ() const { return z; }
+
+
+	//////////////
+	//-- constructors
+
+	SimpleVec() { }
+
+	SimpleVec(float x, float y, float z): x(x), y(y), z(z)
+	{}
+
+	explicit SimpleVec(float v): x(v), y(v), z(v){}
+	/** Copy constructor.
+	*/
+	SimpleVec(const SimpleVec &v): x(v.x), y(v.y), z(v.z)
+	{}
+
+	// Functions to get at the std::vector components
+	float& operator[] (const int inx) 
+	{
+		return (&x)[inx];
+	}
+
+	operator const float*() const 
+	{ 
+		return (const float*) this; 
+	}
+
+	const float &operator[] (const int inx) const 
+	{
+		return *(&x + inx);
+	}
+
+	void ExtractVerts(float *px, float *py, int which) const;
+  
+	void SetValue(float a, float b, float c)
+	{  
+		x = a; y = b; z = c; 
+	}
+
+	void SetValue(float a) 
+	{ 
+		x = y = z = a; 
+	}
+ 
+	
+	/** Returns the axis, where the std::vector has the largest value.
+	*/
+	int DrivingAxis(void) const;
+	/** returns the axis, where the std::vector has the smallest value
+	*/
+	int TinyAxis(void) const;
+	/** Returns largest component in this vector
+	*/
+	inline float MaxComponent(void) const 
+	{
+		return (x > y) ? ( (x > z) ? x : z) : ( (y > z) ? y : z);
+	}
+	/** Returns copy of this vector where all components are positiv.
+	*/
+	inline SimpleVec Abs(void) const 
+	{
+		return SimpleVec(fabs(x), fabs(y), fabs(z));
+	}
+	/** normalizes the std::vector of unit size corresponding to given std::vector
+	*/
+	inline void Normalize();
+	/** Returns false if this std::vector has a nan component.
+	*/
+	bool CheckValidity() const;
+	/**
+	Find a right handed coordinate system with (*this) being
+	the z-axis. For a right-handed system, U x V = (*this) holds.
+	This implementation is here to avoid inconsistence and confusion
+	when construction coordinate systems using ArbitraryNormal():
+	In fact:
+	V = ArbitraryNormal(N);
+	U = CrossProd(V,N);
+	constructs a right-handed coordinate system as well, BUT:
+	1) bugs can be introduced if one mistakenly constructs a 
+	left handed sytems e.g. by doing
+	U = ArbitraryNormal(N);
+	V = CrossProd(U,N);
+	2) this implementation gives non-negative base vectors
+	for (*this)==(0,0,1) |  (0,1,0) | (1,0,0), which is
+	good for debugging and is not the case with the implementation
+	using ArbitraryNormal()
+
+	===> Using ArbitraryNormal() for constructing coord systems 
+	is obsoleted by this method (<JK> 12/20/03).   
+	*/
+	void RightHandedBase(SimpleVec& U, SimpleVec& V) const;
+	
+	
+	// Unary operators
+
+	SimpleVec operator+ () const;
+	SimpleVec operator- () const;
+
+	// Assignment operators
+	
+	SimpleVec& operator+= (const SimpleVec &A);
+	SimpleVec& operator-= (const SimpleVec &A);
+	SimpleVec& operator*= (const SimpleVec &A);
+	SimpleVec& operator*= (float A);
+	SimpleVec& operator/= (float A);
+
+	static inline SimpleVec UNIT_X() { return SimpleVec(1, 0, 0); }
+	static inline SimpleVec UNIT_Y() { return SimpleVec(0, 1, 0); }
+	static inline SimpleVec UNIT_Z() { return SimpleVec(0, 0, 1); }
+	static inline SimpleVec ZERO() { return SimpleVec(0, 0, 0); }
+
+
+	//////////
+	//-- friends
+	
+	/**
+	===> Using ArbitraryNormal() for constructing coord systems 
+	===> is obsoleted by RightHandedBase() method (<JK> 12/20/03).   
+
+	Return an arbitrary normal to `v'.
+	In fact it tries v x (0,0,1) an if the result is too small,
+	it definitely does v x (0,1,0). It will always work for
+	non-degenareted std::vector and is much faster than to use
+	TangentVectors.
+
+	@param v(in) The std::vector we want to find normal for.
+	@return The normal std::vector to v.
+	*/
+	friend inline SimpleVec ArbitraryNormal(const SimpleVec &v); 
+
+	/// Transforms a std::vector to the global coordinate frame.
+	/**
+	Given a local coordinate frame (U,V,N) (i.e. U,V,N are 
+	the x,y,z axes of the local coordinate system) and
+	a std::vector 'loc' in the local coordiante system, this
+	function returns a the coordinates of the same std::vector
+	in global frame (i.e. frame (1,0,0), (0,1,0), (0,0,1).
+	*/
+	friend inline SimpleVec ToGlobalFrame(const SimpleVec& loc,
+		                                const SimpleVec& U,
+										const SimpleVec& V,
+										const SimpleVec& N);
+
+	/// Transforms a std::vector to a local coordinate frame.
+	/**
+	Given a local coordinate frame (U,V,N) (i.e. U,V,N are 
+	the x,y,z axes of the local coordinate system) and
+	a std::vector 'loc' in the global coordiante system, this
+	function returns a the coordinates of the same std::vector
+	in the local frame.
+	*/
+	friend inline SimpleVec ToLocalFrame(const SimpleVec& loc,
+                                	   const SimpleVec& U,
+									   const SimpleVec& V,
+									   const SimpleVec& N);
+
+	/// the magnitude=size of the std::vector
+	friend inline float Magnitude(const SimpleVec &v);
+	/// the squared magnitude of the std::vector .. for efficiency in some cases
+	friend inline float SqrMagnitude(const SimpleVec &v);
+	/// Magnitude(v1-v2)
+	friend inline float Distance(const SimpleVec &v1, const SimpleVec &v2);
+	/// SqrMagnitude(v1-v2)
+	friend inline float SqrDistance(const SimpleVec &v1, const SimpleVec &v2);
+	/// creates the std::vector of unit size corresponding to given std::vector
+	friend inline SimpleVec Normalize(const SimpleVec &A);
+	
+
+	// construct view vectors .. DirAt is the main viewing direction
+	// Viewer is the coordinates of viewer location, UpL is the std::vector.
+	friend void ViewVectors(const SimpleVec &DirAt, 
+							const SimpleVec &Viewer,
+							const SimpleVec &UpL, 
+							SimpleVec &ViewV,
+							SimpleVec &ViewU, 
+							SimpleVec &ViewN);
+
+	// Given the intersection point `P', you have available normal `N'
+	// of unit length. Let us suppose the incoming ray has direction `D'.
+	// Then we can construct such two vectors `U' and `V' that
+	// `U',`N', and `D' are coplanar, and `V' is perpendicular
+	// to the vectors `N','D', and `V'. Then 'N', 'U', and 'V' create
+	// the orthonormal base in space R3.
+	friend void TangentVectors(SimpleVec &U, SimpleVec &V, // output
+							   const SimpleVec &normal, // input
+							   const SimpleVec &dirIncoming);
+
+
+	// Binary operators
+	
+	friend inline SimpleVec operator+ (const SimpleVec &A, const SimpleVec &B);
+	friend inline SimpleVec operator- (const SimpleVec &A, const SimpleVec &B);
+	friend inline SimpleVec operator* (const SimpleVec &A, const SimpleVec &B);
+	friend inline SimpleVec operator* (const SimpleVec &A, float B);
+	friend inline SimpleVec operator* (float A, const SimpleVec &B);
+	friend inline SimpleVec operator/ (const SimpleVec &A, const SimpleVec &B);
+
+	friend inline int operator< (const SimpleVec &A, const SimpleVec &B);
+	friend inline int operator<= (const SimpleVec &A, const SimpleVec &B);
+
+	friend inline SimpleVec operator/ (const SimpleVec &A, float B);
+	friend inline int operator== (const SimpleVec &A, const SimpleVec &B);
+	friend inline float DotProd(const SimpleVec &A, const SimpleVec &B);
+	friend inline SimpleVec CrossProd (const SimpleVec &A, const SimpleVec &B);
+
+	friend std::ostream& operator<< (std::ostream &s, const SimpleVec &A);
+	friend std::istream& operator>> (std::istream &s, SimpleVec &A);
+
+	friend void Minimize(SimpleVec &min, const SimpleVec &candidate);
+	friend void Maximize(SimpleVec &max, const SimpleVec &candidate);
+
+	friend inline int EpsilonEqualV3(const SimpleVec &v1, const SimpleVec &v2, float thr);
+	friend inline int EpsilonEqualV3(const SimpleVec &v1, const SimpleVec &v2);
+};
+
+
+inline SimpleVec ArbitraryNormal(const SimpleVec &N)
+{
+	float dist2 = N.x * N.x + N.y * N.y;
+
+	if (dist2 > 0.0001f) 
+	{
+		float inv_size = 1.0f / sqrtf(dist2);
+		return SimpleVec(N.y * inv_size, -N.x * inv_size, 0); // N x (0,0,1)
+	}
+
+	float inv_size = 1.0f / sqrtf(N.z * N.z + N.x * N.x);
+	return SimpleVec(-N.z * inv_size, 0, N.x * inv_size); // N x (0,1,0)
+}
+
+
+
+inline float Magnitude(const SimpleVec &v) 
+{
+	return sqrtf(v.x * v.x + v.y * v.y + v.z * v.z);
+}
+
+
+inline float SqrMagnitude(const SimpleVec &v) 
+{
+	return v.x * v.x + v.y * v.y + v.z * v.z;
+}
+
+
+inline float Distance(const SimpleVec &v1, const SimpleVec &v2)
+{
+	//return sqrtf(sqrt(v1.x - v2.x) + sqrt(v1.y - v2.y) + sqrt(v1.z - v2.z));
+	return Magnitude(v1 - v2);
+}
+
+
+inline float SqrDistance(const SimpleVec &v1, const SimpleVec &v2)
+{
+	//return sqrt(v1.x - v2.x) + sqrt(v1.y - v2.y) + sqrt(v1.z - v2.z);
+	return SqrMagnitude(v1 - v2);
+}
+
+
+inline SimpleVec Normalize(const SimpleVec &A)
+{
+	return A * (1.0f / Magnitude(A));
+}
+
+
+inline float DotProd(const SimpleVec &A, const SimpleVec &B)
+{
+	return A.x * B.x + A.y * B.y + A.z * B.z;
+}
+
+
+// angle between two vectors with respect to a surface normal in the
+// range [0 .. 2 * pi]
+inline float Angle(const SimpleVec &A, const SimpleVec &B, const SimpleVec &norm)
+{
+	SimpleVec cross = CrossProd(A, B);
+
+	float signedAngle;
+
+	if (DotProd(cross, norm) > 0)
+		signedAngle = atan2(-Magnitude(CrossProd(A, B)), DotProd(A, B));
+	else
+		signedAngle = atan2(Magnitude(CrossProd(A, B)), DotProd(A, B));
+
+	if (signedAngle < 0)
+		return 2 * 3.145f + signedAngle;
+
+	return signedAngle;
+}
+
+
+inline SimpleVec SimpleVec::operator+() const
+{
+	return *this;
+}
+
+
+inline SimpleVec SimpleVec::operator-() const
+{
+  return SimpleVec(-x, -y, -z);
+}
+
+
+inline SimpleVec &SimpleVec::operator+=(const SimpleVec &A)
+{
+	x += A.x;  y += A.y;  z += A.z;
+	return *this;
+}
+
+
+inline SimpleVec& SimpleVec::operator-=(const SimpleVec &A)
+{
+	x -= A.x;  y -= A.y;  z -= A.z;
+	
+	return *this;
+}
+
+
+inline SimpleVec& SimpleVec::operator*= (float A)
+{
+	x *= A;  y *= A;  z *= A;
+	return *this;
+}
+
+
+inline SimpleVec& SimpleVec::operator/=(float A)
+{
+	float a = 1.0f / A;
+	
+	x *= a;  y *= a;  z *= a;
+	
+	return *this;
+}
+
+
+inline SimpleVec& SimpleVec::operator*= (const SimpleVec &A)
+{
+  x *= A.x;  y *= A.y;  z *= A.z;
+  return *this;
+}
+
+
+inline SimpleVec operator+ (const SimpleVec &A, const SimpleVec &B)
+{
+	return SimpleVec(A.x + B.x, A.y + B.y, A.z + B.z);
+}
+
+
+inline SimpleVec operator- (const SimpleVec &A, const SimpleVec &B)
+{
+	return SimpleVec(A.x - B.x, A.y - B.y, A.z - B.z);
+}
+
+
+inline SimpleVec operator* (const SimpleVec &A, const SimpleVec &B)
+{
+	return SimpleVec(A.x * B.x, A.y * B.y, A.z * B.z);
+}
+
+
+inline SimpleVec operator* (const SimpleVec &A, float B)
+{
+  return SimpleVec(A.x * B, A.y * B, A.z * B);
+}
+
+
+inline SimpleVec operator* (float A, const SimpleVec &B)
+{
+	return SimpleVec(B.x * A, B.y * A, B.z * A);
+}
+
+
+inline SimpleVec operator/ (const SimpleVec &A, const SimpleVec &B)
+{
+	return SimpleVec(A.x / B.x, A.y / B.y, A.z / B.z);
+}
+
+
+inline SimpleVec operator/ (const SimpleVec &A, float B)
+{
+	float b = 1.0f / B;
+	return SimpleVec(A.x * b, A.y * b, A.z * b);
+}
+
+
+inline int operator< (const SimpleVec &A, const SimpleVec &B)
+{
+	return A.x < B.x && A.y < B.y && A.z < B.z;
+}
+
+
+inline int operator<= (const SimpleVec &A, const SimpleVec &B)
+{
+	return A.x <= B.x && A.y <= B.y && A.z <= B.z;
+}
+
+
+// Might replace floating-point == with comparisons of
+// magnitudes, if needed.
+inline int operator== (const SimpleVec &A, const SimpleVec &B)
+{ 
+	return (A.x == B.x) && (A.y == B.y) && (A.z == B.z);
+}
+
+
+inline SimpleVec CrossProd (const SimpleVec &A, const SimpleVec &B)
+{
+	return SimpleVec(A.y * B.z - A.z * B.y,
+		           A.z * B.x - A.x * B.z,
+				   A.x * B.y - A.y * B.x);
+}
+
+
+inline void SimpleVec::Normalize()
+{
+	float sqrmag = x * x + y * y + z * z;
+	
+	if (sqrmag > 0.0f)
+		(*this) *= 1.0f / sqrtf(sqrmag);
+}
+
+
+// Overload << operator for C++-style output
+inline std::ostream& operator<< (std::ostream &s, const SimpleVec &A)
+{
+	return s << "(" << A.x << ", " << A.y << ", " << A.z << ")";
+}
+
+
+// Overload >> operator for C++-style input
+inline std::istream& operator>> (std::istream &s, SimpleVec &A)
+{
+	char a;
+	// read "(x, y, z)"
+	return s >> a >> A.x >> a >> A.y >> a >> A.z >> a;
+}
+
+
+inline int EpsilonEqualV3(const SimpleVec &v1, const SimpleVec &v2, float thr)
+{
+	if (fabsf(v1.x-v2.x) > thr)
+		return false;
+	if (fabsf(v1.y-v2.y) > thr)
+		return false;
+	if (fabsf(v1.z-v2.z) > thr)
+		return false;
+	
+	return true;
+}
+
+
+inline int EpsilonEqualV3(const SimpleVec &v1, const SimpleVec &v2)
+{
+	return EpsilonEqualV3(v1, v2, 1e-6f);
+}
+
+
+#endif
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/SimpleTri.h
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/SimpleTri.h	(revision 3012)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/SimpleTri.h	(revision 3012)
@@ -0,0 +1,53 @@
+#ifndef __SIMPLETRI_H
+#define __SIMPLETRI_H
+
+#include <iostream>
+#include "SimpleVec.h"
+
+
+struct SimpleTri 
+{
+	SimpleTri() {};
+	SimpleTri(const SimpleVec &a, const SimpleVec &b, const SimpleVec &c);
+
+	void Init(const SimpleVec &a, const SimpleVec &b, const SimpleVec &c);
+
+	SimpleVec GetNormal() const;
+
+	SimpleVec GetCenter() const;
+
+	float GetSpatialAngle(const SimpleVec &point) const;
+
+	float GetArea() const;
+	
+	  
+	friend std::ostream& operator<< (std::ostream &s, const SimpleTri &A);
+	friend std::istream& operator>> (std::istream &s, SimpleTri &A);
+
+
+	///////////////////
+
+	/// the triangle vertices
+	SimpleVec mVertices[3];
+};
+
+
+// Overload << operator for C++-style output
+inline std::ostream&
+operator<< (std::ostream &s, const SimpleTri &A)
+{
+  return s << "(" << A.mVertices[0] << ", " << A.mVertices[1] << ", " << A.mVertices[2] << ")";
+}
+
+// Overload >> operator for C++-style input
+inline std::istream&
+operator>> (std::istream &s, SimpleTri &A)
+{
+  char a;
+  // read "(x, y, z)"
+  return s >> a >> A.mVertices[0] >> a >> A.mVertices[1] >> a >> A.mVertices[2] >> a;
+}
+
+
+#endif
+
Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter.vcproj
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter.vcproj	(revision 2961)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter.vcproj	(revision 3012)
@@ -197,4 +197,12 @@
 				>
 			</File>
+			<File
+				RelativePath=".\Converter\SimpleTri.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\Converter\SimpleVec.cpp"
+				>
+			</File>
 		</Filter>
 		<Filter
@@ -211,4 +219,12 @@
 				>
 			</File>
+			<File
+				RelativePath=".\Converter\SimpleTri.h"
+				>
+			</File>
+			<File
+				RelativePath=".\Converter\SimpleVec.h"
+				>
+			</File>
 		</Filter>
 	</Files>
