Index: GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreOcclusionCullingSceneManager.cpp
===================================================================
--- GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreOcclusionCullingSceneManager.cpp	(revision 2098)
+++ GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreOcclusionCullingSceneManager.cpp	(revision 2102)
@@ -210,4 +210,5 @@
 		mFilename = val.c_str();
 		
+		// load terrain instead of scene
 		if (mFilename == "terrain")
 		{
@@ -884,5 +885,5 @@
 		if (!mViewCellsLoaded)
 		{
-			// try ro loaded view cells
+			// try to load view cells
 			mViewCellsLoaded = LoadViewCells(mViewCellsFilename);	
 		}
@@ -892,5 +893,4 @@
 		
 		// only use this option if view cells are available
-
 		mUseViewCells = *static_cast<const bool *>(val);
 
Index: GTP/trunk/Lib/Vis/Preprocessing/src/HashPvs.h
===================================================================
--- GTP/trunk/Lib/Vis/Preprocessing/src/HashPvs.h	(revision 2102)
+++ GTP/trunk/Lib/Vis/Preprocessing/src/HashPvs.h	(revision 2102)
@@ -0,0 +1,145 @@
+#ifndef __HASHPVS_H
+#define __HASHPVS_H
+
+#include <hash_map>
+#include <vector>
+#include "common.h"
+#include <math.h>
+#include "PvsBase.h"
+
+
+using namespace std;
+
+namespace GtpVisibilityPreprocessor {
+
+class KdNode;
+class BspNode;
+class Ray;
+class Intersectable;
+class ViewCell;
+
+
+/** Template class representing the Potentially Visible Set (PVS) 
+	mainly from a view cell, but also e.g., from objects.
+*/
+template<typename T>
+class HashPvs: public PvsBase<T>
+{
+	template<typename T>
+		friend class PvsIterator2;
+
+public:
+
+	HashPvs() {};
+	//virtual ~HashPvs() {};
+
+	int GetSize() const;
+	bool Empty() const;
+
+	/** Adds sample to PVS.
+		@returns contribution of sample (0 or 1)
+	*/
+	float AddSample(T sample);
+
+	/** Adds sample to PVS without checking for presence of the sample
+		warning: pvs remains unsorted!
+	*/
+	void AddSampleDirty(T sample);
+
+	/** Adds sample dirty (on the end of the vector) but
+		first checks if sample is already in clean part of the pvs.
+	*/
+	bool AddSampleDirtyCheck(T sample);
+
+	/** Sort pvs entries - this should always be called after a
+		sequence of AddSampleDirty calls 
+	*/
+	void Sort();
+
+	/** Clears the pvs.
+	*/
+	void Clear(const bool trim = true);
+
+	//static void Merge(PvsBase &mergedPvs, const PvsBase &a, const PvsBase &b);
+
+	bool IsDirty() const;
+
+	bool RequiresResort() const;
+
+	//typename PvsIterator<T> GetIterator() const;
+
+protected:
+
+	/// vector of PVS entries
+	vector<T> mEntries; 
+
+	/// Number of samples used to create the PVS
+	int mSamples;
+};
+
+
+template <typename T>
+int HashPvs<T>::GetSize() const
+{
+	return 0;
+}
+
+
+template <typename T>
+bool HashPvs<T>::Empty() const
+{
+	return false;
+}
+
+
+template <typename T>
+float HashPvs<T>::AddSample(T sample)
+{
+	return 0;
+}
+	
+
+template <typename T>
+void HashPvs<T>::AddSampleDirty(T sample)
+{
+}
+
+
+template <typename T>
+bool HashPvs<T>::AddSampleDirtyCheck(T sample)
+{
+	return false;
+}
+
+
+template <typename T>
+void HashPvs<T>::Sort()
+{
+}
+
+
+template <typename T>
+void HashPvs<T>::Clear(const bool trim = true)
+{
+}
+
+
+template <typename T>
+bool HashPvs<T>::IsDirty() const
+{
+	return false;
+}
+
+
+template <typename T>
+bool HashPvs<T>::RequiresResort() const
+{
+	return false;
+}
+
+//typename PvsIterator<T> GetIterator() const;
+
+}
+
+#endif
+
Index: GTP/trunk/Lib/Vis/Preprocessing/src/HashPvs.cpp
===================================================================
--- GTP/trunk/Lib/Vis/Preprocessing/src/HashPvs.cpp	(revision 2102)
+++ GTP/trunk/Lib/Vis/Preprocessing/src/HashPvs.cpp	(revision 2102)
@@ -0,0 +1,178 @@
+#include <iostream>
+#include <stack>
+#include "Pvs.h"
+#include "Intersectable.h"
+#include "IntersectableWrapper.h"
+#include "KdTree.h"
+#include "common.h"
+#include "BvHierarchy.h"
+
+
+namespace GtpVisibilityPreprocessor {
+
+int MailablePvsData::sMailId = 1;
+int MailablePvsData::sReservedMailboxes = 1;
+
+
+int KdPvs::Compress()
+{
+	return 0; // TODO
+}
+
+/** the pvs is the number of different objects in the node leaves
+	We eliminate already accounted kd nodes and objects using mailboxing. 
+*/
+static int EvalKdNodeContribution(KdIntersectable *kdobj)
+{
+	int pvs = 0;
+	stack<KdNode *> tStack;
+
+	tStack.push(kdobj->GetItem());
+
+	while (!tStack.empty())
+	{
+		KdNode *node = tStack.top();
+		tStack.pop();
+
+		// already processed node (=> objects already in pvs)?
+		if (!node->Mailed())
+		{
+			node->Mail();
+
+			if (node->IsLeaf())
+			{
+				KdLeaf *leaf = static_cast<KdLeaf *>(node);
+                       
+				// add #objects exclusivly in this node
+				pvs += (int)(leaf->mObjects.size() - leaf->mMultipleObjects.size());
+
+				// Objects already accounted for can only be found among those
+				// which are referenced in more than one leaf
+				ObjectContainer::const_iterator oit, oit_end = leaf->mMultipleObjects.end();
+						
+				for (oit = leaf->mMultipleObjects.begin(); oit != oit_end; ++ oit)
+				{
+					Intersectable *object = *oit;						
+                            
+					if (!object->Mailed())
+					{
+						object->Mail();
+						++ pvs;
+					}
+				}
+			}
+			else // traverse tree
+			{
+				KdInterior *interior = static_cast<KdInterior *>(node);
+
+				tStack.push(interior->mFront);
+				tStack.push(interior->mBack);
+			}
+		}
+	}
+
+	return pvs;
+}
+
+
+/** Returns the the number of new (unmailed) objects in the leaves of the node.
+	We eliminate already accounted bvh nodes and objects using mailboxing. 
+*/
+static float EvalBvhNodeContribution(BvhNode *bvhObj)
+{
+	BvhNode *node;
+
+	// hack for choosing which node to account for
+	if (bvhObj->IsLeaf())
+		node = static_cast<BvhLeaf *>(bvhObj)->GetActiveNode();
+	else
+		node = bvhObj;
+
+	// early exit
+	if (node->IsLeaf())	
+	{	
+		BvhLeaf *leaf = static_cast<BvhLeaf *>(node);
+		// objects already accounted for
+		if (leaf->Mailed())
+			return 0;
+
+		leaf->Mail();
+		return BvHierarchy::EvalAbsCost(leaf->mObjects);
+	}			 
+
+	// compute leaf pvs
+	float pvs = 0;
+	stack<BvhNode *> tStack;
+	tStack.push(node);
+
+	while (!tStack.empty())
+	{
+		node = tStack.top();
+		tStack.pop();
+
+		// already processed node (=> objects already in pvs)?
+		if (!node->Mailed())
+		{
+			node->Mail();
+
+			if (node->IsLeaf())
+			{
+				BvhLeaf *leaf = static_cast<BvhLeaf *>(node);
+
+				// add #objects exclusivly in this node
+				pvs += BvHierarchy::EvalAbsCost(leaf->mObjects);
+			}
+			else // traverse tree
+			{
+				BvhInterior *interior = static_cast<BvhInterior *>(node);
+
+				tStack.push(interior->GetFront());
+				tStack.push(interior->GetBack());
+			}
+		}
+	}
+
+	return pvs;
+}
+
+
+float ObjectPvs::EvalPvsCost() const
+{
+	float pvs = 0;
+
+	Intersectable::NewMail();
+	KdLeaf::NewMail();
+
+	ObjectPvsEntries::const_iterator it, it_end = mEntries.end();
+
+	for (it = mEntries.begin(); it != it_end; ++ it)
+	{
+		Intersectable *obj = (*it).mObject;
+	
+		switch (obj->Type())
+		{
+			case Intersectable::KD_INTERSECTABLE:
+				{
+					// found kd node
+					KdIntersectable *kdObj = static_cast<KdIntersectable *>(obj);
+					pvs += EvalKdNodeContribution(kdObj);	
+					break;
+				}
+			case Intersectable::BVH_INTERSECTABLE:
+				{
+					BvhNode *bvhObj = static_cast<BvhNode *>(obj);
+					pvs += EvalBvhNodeContribution(bvhObj);
+					break;
+				}
+			default:
+				// hack: should use assigned cost here
+				++ pvs;
+				
+				break;
+		}
+	}
+
+	return pvs;
+}
+
+}
