Index: /GTP/trunk/Lib/Vis/Preprocessing/src/ViewCellsManager.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/ViewCellsManager.h	(revision 1773)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/ViewCellsManager.h	(revision 1786)
@@ -38,4 +38,5 @@
 class BvHierarchy;
 class ViewCellsTree;
+class ViewCell;
 
 struct AxisAlignedPlane;
@@ -64,4 +65,54 @@
   // some characteristic values could be stored as well
 };
+
+
+class LocalMergeNode
+{
+public:
+	virtual ~LocalMergeNode() {};
+	virtual bool IsLeaf() const = 0;
+};
+
+
+class LocalMergeLeaf: public LocalMergeNode
+{
+public:
+	LocalMergeLeaf(ViewCell *vc): mViewCell(vc) {};
+	virtual ~LocalMergeLeaf() {};
+	virtual bool IsLeaf() const { return true; }
+
+	ViewCell *mViewCell;
+};
+
+
+class LocalMergeInterior: public LocalMergeNode
+{
+public:
+	
+	virtual ~LocalMergeInterior() {DEL_PTR(mLeft); DEL_PTR(mRight);}
+	virtual bool IsLeaf() const { return false; }
+
+	LocalMergeNode *mLeft;
+	LocalMergeNode *mRight;
+};
+
+
+class LocalMergeTree
+{
+public:
+
+	LocalMergeTree(const ViewCellContainer &viewCells);
+	
+	void Merge(ObjectPvs &mergedPvs);
+
+protected:
+
+	void Merge(LocalMergeNode *node, ObjectPvs &mergedPvs);
+	LocalMergeNode *Subdivide(const int leftIdx, const int rightIdx);
+
+	LocalMergeNode *mRoot;
+	const ViewCellContainer &mViewCells;
+};
+
 
 /**	Manages different higher order operations on the view cells.
@@ -452,4 +503,9 @@
 	bool GetExportPvs() const;
 
+	/** Efficiently merges the view cells in the container.
+	*/
+	void MergeViewCellsEfficient(ObjectPvs &pvs, const ViewCellContainer &viewCells) const;
+
+
 	/////////////////////////////
 	// static members
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/Environment.cpp
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/Environment.cpp	(revision 1785)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/Environment.cpp	(revision 1786)
@@ -2505,4 +2505,19 @@
 					"false");
 
+	RegisterOption("BvHierarchy.Construction.Initial.minObjects",
+					optInt,
+					"bvh_construction_use_initial_min_objects=",
+					"100000");
+
+	RegisterOption("BvHierarchy.Construction.Initial.minArea",
+					optFloat,
+					"bvh_construction_use_initial_min_area=",
+					"0.0001");
+
+	RegisterOption("BvHierarchy.Construction.Initial.maxAreaRatio",
+					optFloat,
+					"bvh_construction_use_initial_max_area_ratio=",
+					"0.1");
+
 	RegisterOption("BvHierarchy.minRaysForVisibility",
 					optInt,
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/Preprocessor.cpp
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/Preprocessor.cpp	(revision 1785)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/Preprocessor.cpp	(revision 1786)
@@ -247,4 +247,9 @@
 	FaceContainer faces;
 
+	if (parents)
+		cout << "using face parents" << endl;
+	else
+		cout << "not using face parents" << endl;
+
 	while (1)
 	{
@@ -370,4 +375,49 @@
 	}
 	return result;
+}
+
+
+Intersectable *Preprocessor::GetParentObject(const int index) const
+{
+	if (index == -1)
+		return NULL;
+	
+	if (!mFaceParents.empty())
+	{
+		if (index >= (int)mFaceParents.size())
+		{
+			cerr<<"Warning: triangle  index out of range! "<<index<<endl;
+			return NULL;
+		}
+		else
+		{
+			return mFaceParents[index].mObject;
+		}
+	}
+	else
+	{
+		if (index >= (int)mObjects.size())
+		{
+			cerr<<"Warning: triangle  index out of range! "<<index<<endl;
+			return NULL;
+		}
+		else
+		{
+			return mObjects[index];
+		}
+	}
+}
+
+
+Vector3 Preprocessor::GetParentNormal(const int index) const
+{
+	if (!mFaceParents.empty())
+	{
+		return mFaceParents[index].mObject->GetNormal(mFaceParents[index].mFaceIndex);
+	}	
+	else
+	{
+		return mObjects[index]->GetNormal(0);
+	}
 }
 
@@ -392,5 +442,5 @@
 	int rayCastMethod;
 	Environment::GetSingleton()->GetIntValue("Preprocessor.rayCastMethod", rayCastMethod);
-	vector<FaceParentInfo> *fi = (rayCastMethod == RayCaster::INTEL_RAYCASTER) ?
+	vector<FaceParentInfo> *fi = ((rayCastMethod == RayCaster::INTEL_RAYCASTER) || (!mLoadMeshes)) ?
 		&mFaceParents : NULL;
 
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/HierarchyManager.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/HierarchyManager.h	(revision 1779)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/HierarchyManager.h	(revision 1786)
@@ -524,4 +524,6 @@
 	void ComputePvs(const ObjectPvs &pvs, float &rc, int &pvsEntries);
 	void GetPvsIncrementally(ViewCell *vc, ObjectPvs &pvs) const;
+	void PullUpPvsIncrementally(ViewCell *viewCell) const;
+	void GetPvsRecursive(ViewCell *vc, ObjectPvs &pvs) const;
 protected:
 
@@ -636,4 +638,6 @@
 
 	ViewCellContainer mOldViewCells;
+
+	ObjectPvs mOldPvs;
 };
 
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/Preprocessor.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/Preprocessor.h	(revision 1785)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/Preprocessor.h	(revision 1786)
@@ -121,23 +121,23 @@
 	bool ExportKdTree(const string filename);
 
-  virtual int
-  GenerateRays(const int number,
-			   const SamplingStrategy &strategy,
-			   SimpleRayContainer &rays);
-  
-  virtual int GenerateRays(const int number,
-						   const int raysType,
-						   SimpleRayContainer &rays);
-  
-  bool GenerateRayBundle(SimpleRayContainer &rayBundle,
-						 const SimpleRay &mainRay,
-						 const int number,
-						 const int shuffleType) const;
-  
-  virtual void CastRays(SimpleRayContainer &rays,
-						VssRayContainer &vssRays,
-						const bool castDoubleRays,
-						const bool pruneInvalidRays = true);
-  
+	virtual int
+		GenerateRays(const int number,
+		const SamplingStrategy &strategy,
+		SimpleRayContainer &rays);
+
+	virtual int GenerateRays(const int number,
+		const int raysType,
+		SimpleRayContainer &rays);
+
+	bool GenerateRayBundle(SimpleRayContainer &rayBundle,
+		const SimpleRay &mainRay,
+		const int number,
+		const int shuffleType) const;
+
+	virtual void CastRays(SimpleRayContainer &rays,
+		VssRayContainer &vssRays,
+		const bool castDoubleRays,
+		const bool pruneInvalidRays = true);
+
 	/** Returns a view cells manager of the given name.
 	*/
@@ -148,6 +148,8 @@
 	bool InitRayCast(const string externKdTree, const string internKdTree);
 
-bool ExportObj(const string filename, const ObjectContainer &objects);
-
+	bool ExportObj(const string filename, const ObjectContainer &objects);
+
+	Intersectable *GetParentObject(const int index) const;
+Vector3 GetParentNormal(const int index) const;
 	////////////////////////////////////////////////
 
@@ -202,5 +204,5 @@
 	bool mExportObj;
 
-  ofstream mStats;
+	ofstream mStats;
 
   GlRendererBuffer *renderer;
@@ -214,11 +216,9 @@
 	bool ExportBinaryObj(const string filename, SceneGraphNode *root);
 
-
 	void SetupRay(Ray &ray, const Vector3 &point, const Vector3 &direction) const;
 
 	void EvalPvsStat();
 
-  virtual void
-  EvalViewCellHistogram();
+	virtual void EvalViewCellHistogram();
 
 	/////////////////////////
@@ -229,6 +229,5 @@
 	/// samples used for construction of the VSP OSP tree.
 	int mVspOspConstructionSamples;
-	/** Simulates rendering of the scene.
-	*/
+	/// Simulates rendering of the scene.
 	RenderSimulator *mRenderSimulator;
 
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/BvHierarchy.cpp
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/BvHierarchy.cpp	(revision 1785)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/BvHierarchy.cpp	(revision 1786)
@@ -52,5 +52,7 @@
 BvhNode::BvhNode(): 
 mParent(NULL), 
-mTimeStamp(0)
+mTimeStamp(0),
+mRenderCost(-1)
+
 {
 	
@@ -60,5 +62,6 @@
 mParent(NULL), 
 mBoundingBox(bbox), 
-mTimeStamp(0)
+mTimeStamp(0),
+mRenderCost(-1)
 {
 }
@@ -68,5 +71,6 @@
 mBoundingBox(bbox), 
 mParent(parent), 
-mTimeStamp(0)
+mTimeStamp(0),
+mRenderCost(-1)
 {
 }
@@ -301,6 +305,7 @@
 	Environment::GetSingleton()->GetIntValue("BvHierarchy.maxTests", mMaxTests);
 	//	Environment::GetSingleton()->GetBoolValue("BvHierarchy.Construction.useInitialSubdivision", mApplyInitialPartition);
-	
-	mInitialObjectsSize = 50;
+	Environment::GetSingleton()->GetIntValue("BvHierarchy.Construction.Initial.minObjects", mInitialMinObjects);
+	Environment::GetSingleton()->GetFloatValue("BvHierarchy.Construction.Initial.maxAreaRatio", mInitialMaxAreaRatio);
+	Environment::GetSingleton()->GetFloatValue("BvHierarchy.Construction.Initial.minArea", mInitialMinArea);
 
 	//mMemoryConst = (float)(sizeof(VspLeaf) + sizeof(VspViewCell));
@@ -334,4 +339,8 @@
 	Debug << "bvh mem const: " << mMemoryConst << endl;
 	Debug << "apply initial partition: " << mApplyInitialPartition << endl;
+	Debug << "min objects: " << mInitialMinObjects << endl;
+	Debug << "max area ratio: " << mInitialMaxAreaRatio << endl;
+	Debug << "min area: " << mInitialMinArea << endl;
+
 	Debug << endl;
 }
@@ -496,5 +505,5 @@
 		BvhSubdivisionCandidate *backCandidate = 
 				new BvhSubdivisionCandidate(tBackData);
-
+		
 		EvalSubdivisionCandidate(*frontCandidate);
 		EvalSubdivisionCandidate(*backCandidate);
@@ -2150,6 +2159,5 @@
 	
 	if (mApplyInitialPartition)
-	{
-		cout << "§§§§§§§§here41 "<<oSubdivisionCandidate->mParentData.mSortedObjects[3]->size()<<endl;
+	{cout << "here29"<<endl;
 		ApplyInitialSubdivision(oSubdivisionCandidate, tQueue);		
 	}
@@ -2158,4 +2166,5 @@
 		tQueue.Push(oSubdivisionCandidate);
 	}
+	cout << "!!size: " << GetStatistics().Leaves() << endl;
 }
 
@@ -2510,22 +2519,24 @@
 	{cout << "here2"<<endl;
 		SubdivisionCandidate *candidate = tempQueue.Top();
-		tQueue.Pop();
+		tempQueue.Pop();
 
 		BvhSubdivisionCandidate *bsc = 
 			dynamic_cast<BvhSubdivisionCandidate *>(candidate);
-		cout << "§§§§§§§§here49 "<< bsc->mParentData.mSortedObjects[3]->size()<<endl;
-cout << "here87 "<<((BvhSubdivisionCandidate *)firstCandidate)->mParentData.mNode->mObjects.size()<<endl;
-		const bool globalCriteriaMet = 
-			GlobalTerminationCriteriaMet(bsc->mParentData);
-cout << "here5"<<endl;
+		cout << "§§§§§§§§here49 "<< bsc->mParentData.mSortedObjects[3]->size() << " " << mInitialMinObjects << endl;
+
+		const bool globalCriteriaMet = GlobalTerminationCriteriaMet(bsc->mParentData);
+
 		if (!InitialTerminationCriteriaMet(bsc->mParentData))
-		{cout << "here9"<<bsc->mParentData.mNode->mObjects.size()<<endl;
+		{
+			cout << "here12"<<endl;
+			cout << "here9"<<bsc->mParentData.mNode->mObjects.size()<<endl;
 			BvhNode *node = Subdivide(tempQueue, bsc, globalCriteriaMet);
-cout << "here12"<<endl;
+
 			// not needed anymore
 			delete bsc;
 		}
 		else // initial preprocessing  finished for this candidate
-		{cout << "here15"<<endl;
+		{cout << "here14"<<endl;
+			// add to "real" traversal queue
 			tQueue.Push(bsc);
 		}
@@ -2544,24 +2555,25 @@
 
 	ObjectContainer::const_iterator oit, oit_end = objects->end();
-    cout<<"$$$$$$$$$$$$$$$$$$$"<<endl;
+    cout<<"here104"<<endl;
 	for (oit = objects->begin(); oit != objects->end(); ++ oit)
 	{
 		//cout << (*oit)->GetBox().SurfaceArea() << " ";
 	}
-cout<<"$$$$$$$$$$$$$$$$$$$"<<endl;
-	float maxAreaDiff = 0.0f;
+
+	float maxAreaDiff = -1.0f;
 
 	ObjectContainer::const_iterator backObjectsStart = objects->begin();
 
     for (oit = objects->begin(); oit != (objects->end() - 1); ++ oit)
-	{
+	{//cout << "h";
 		Intersectable *objS = *oit;
 		Intersectable *objL = *(oit + 1);
 		
 		const float areaDiff = 
-			fabs(objS->GetBox().SurfaceArea() - objL->GetBox().SurfaceArea());
+				objL->GetBox().SurfaceArea() - objS->GetBox().SurfaceArea();
 
 		if (areaDiff > maxAreaDiff)
 		{
+			//cout << "here5 " << areaDiff << " " << maxAreaDiff << endl;
 			maxAreaDiff = areaDiff;
 			backObjectsStart = oit + 1;
@@ -2583,12 +2595,46 @@
 
 
+inline static float AreaRatio(Intersectable *smallObj, Intersectable *largeObj)
+{
+	const float areaSmall = smallObj->GetBox().SurfaceArea();
+	const float areaLarge = largeObj->GetBox().SurfaceArea();
+
+	return areaSmall / (areaLarge - areaSmall + Limits::Small);
+}
+
+
 bool BvHierarchy::InitialTerminationCriteriaMet(const BvhTraversalData &tData) const
 {
 	return (0
-		    || ((int)tData.mNode->mObjects.size() < mInitialObjectsSize)
-			|| (tData.mNode->mObjects.back()->GetBox().SurfaceArea() < mMinInitialSurfaceArea)
+		    || ((int)tData.mNode->mObjects.size() < mInitialMinObjects)
+			|| (tData.mNode->mObjects.back()->GetBox().SurfaceArea() < mInitialMinArea)
+			|| (AreaRatio(tData.mNode->mObjects.front(), tData.mNode->mObjects.back()) > mInitialMaxAreaRatio)
 			);
 }
 
 
-}
+// HACK
+float BvHierarchy::GetRenderCostIncrementially(BvhNode *node) const
+{
+	if (node->mRenderCost < 0)
+	{
+		//cout <<"p";
+		if (node->IsLeaf())
+		{
+			BvhLeaf *leaf = dynamic_cast<BvhLeaf *>(node);
+			node->mRenderCost = EvalAbsCost(leaf->mObjects);
+		}
+		else
+		{
+			BvhInterior *interior = dynamic_cast<BvhInterior *>(node);
+		
+			node->mRenderCost = GetRenderCostIncrementially(interior->GetFront()) + 
+								GetRenderCostIncrementially(interior->GetBack());
+		}
+	}
+
+	return node->mRenderCost;
+}
+
+
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/ViewCellsManager.cpp
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/ViewCellsManager.cpp	(revision 1785)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/ViewCellsManager.cpp	(revision 1786)
@@ -2591,4 +2591,11 @@
 
 
+void ViewCellsManager::MergeViewCellsEfficient(ObjectPvs &pvs, const ViewCellContainer &viewCells) const
+{
+	LocalMergeTree mergeTree(viewCells);
+	mergeTree.Merge(pvs);
+}
+
+#if 1
 PvsFilterStatistics
 ViewCellsManager::ApplyFilter2(ViewCell *viewCell,
@@ -2602,5 +2609,5 @@
   AxisAlignedBox3 vbox = GetViewCellBox(viewCell);
   Vector3 center = vbox.Center();
-  // COpy the PVS
+  // copy the PVS
   ObjectPvs basePvs = viewCell->GetPvs();
   Intersectable::NewMail();
@@ -2740,6 +2747,149 @@
   return stats;
 }
+#else
+PvsFilterStatistics
+ViewCellsManager::ApplyFilter2(ViewCell *viewCell,
+							   const bool useViewSpaceFilter,
+							   const float filterSize,
+							   ObjectPvs &pvs
+							   )
+{cout << "x";
+  PvsFilterStatistics stats;
+
+  AxisAlignedBox3 vbox = GetViewCellBox(viewCell);
+  Vector3 center = vbox.Center();
+  // copy the PVS
+  ObjectPvs basePvs = viewCell->GetPvs();
+  Intersectable::NewMail();
+
+  ObjectPvsIterator pit = basePvs.GetIterator();
+
+#if !USE_KD_PVS
+  // first mark all object from this pvs
+  while (pit.HasMoreEntries()) {		
+	ObjectPvsEntry entry = pit.Next();
+	
+	Intersectable *object = entry.mObject;
+	object->Mail();
+  }
+#endif
+
+  int pvsSize = 0;
+  int nPvsSize = 0;
+  float samples = (float)basePvs.GetSamples();
   
+  Debug<<"f #s="<<samples<<"pvs size = "<<basePvs.GetSize();
+  //  cout<<"Filter size = "<<filterSize<<endl;
+  //  cout<<"vbox = "<<vbox<<endl;
+  //  cout<<"center = "<<center<<endl;
+
+
+   // Minimal number of local samples to take into account
+   // the local sampling density.
+   // The size of the filter is a minimum of the conservative
+   // local sampling density estimate (#rays intersecting teh viewcell and
+   // the object)
+   // and gobal estimate for the view cell
+   // (total #rays intersecting the viewcell)
+#define MIN_LOCAL_SAMPLES 5
+
+  float viewCellRadius = 0.5f*Magnitude(vbox.Diagonal());
   
+  // now compute the filter box around the current viewCell
+  
+  if (useViewSpaceFilter) {
+	//	float radius = Max(viewCellRadius/100.0f, avgRadius - viewCellRadius);
+	float radius = viewCellRadius/100.0f;
+	vbox.Enlarge(radius);
+	cout<<"vbox = "<<vbox<<endl;
+	ViewCellContainer viewCells;
+	ComputeBoxIntersections(vbox, viewCells);
+	ObjectPvs pvs;
+	MergeViewCellsEfficient(pvs, viewCells);
+	basePvs = pvs;
+		
+	// update samples and globalC
+	samples = (float)pvs.GetSamples();
+	//	cout<<"neighboring viewcells = "<<i-1<<endl;
+	//	cout<<"Samples' = "<<samples<<endl;
+  }
+
+  // Minimal number of samples so that filtering takes place
+#define MIN_SAMPLES  100
+  if (samples > MIN_SAMPLES) {
+	float globalC = 2.0f*filterSize/sqrt(samples);
+	
+	pit = basePvs.GetIterator();
+	
+	ObjectContainer objects;
+	
+	while (pit.HasMoreEntries())
+	  {		
+		ObjectPvsEntry entry = pit.Next();
+		
+		Intersectable *object = entry.mObject;
+		// compute filter size based on the distance and the numebr of samples
+		AxisAlignedBox3 box = object->GetBox();
+		
+		float distance = Distance(center, box.Center());
+		float globalRadius = distance*globalC;
+		
+		int objectSamples = (int)entry.mData.mSumPdf;
+		float localRadius = MAX_FLOAT;
+		if (objectSamples > MIN_LOCAL_SAMPLES)
+		  localRadius = filterSize*0.5f*Magnitude(box.Diagonal())/
+			sqrt((float)objectSamples);
+		
+		//	cout<<"lr="<<localRadius<<" gr="<<globalRadius<<endl;
+		
+		// now compute the filter size
+		float radius;
+
+		if (localRadius < globalRadius) {
+		  radius = localRadius;
+		  stats.mLocalFilterCount++;
+		} else {
+		  radius = globalRadius;
+		  stats.mGlobalFilterCount++;
+		}
+
+		stats.mAvgFilterRadius += radius;
+		
+		// cout<<"box = "<<box<<endl;
+		//	cout<<"distance = "<<distance<<endl;
+		//	cout<<"radiues = "<<radius<<endl;
+		
+		box.Enlarge(Vector3(radius));
+		
+		objects.clear();
+		// $$ warning collect objects takes only unmailed ones!
+		CollectObjects(box, objects);
+		//	cout<<"collected objects="<<objects.size()<<endl;
+		ObjectContainer::const_iterator noi = objects.begin();
+		for (; noi != objects.end(); ++ noi) {
+		  Intersectable *o = *noi;
+		  // $$ JB warning: pdfs are not correct at this point!	  
+		  pvs.AddSampleDirty(o, Limits::Small);
+		}
+	  }
+	stats.mAvgFilterRadius /= (stats.mLocalFilterCount + stats.mGlobalFilterCount);
+  }
+  
+  Debug<<" nPvs size = "<<pvs.GetSize()<<endl;
+
+#if !USE_KD_PVS
+  // copy the base pvs to the new pvs
+  pit = basePvs.GetIterator();
+  while (pit.HasMoreEntries()) {		
+	ObjectPvsEntry entry = pit.Next();
+	pvs.AddSampleDirty(entry.mObject, entry.mData.mSumPdf);
+  }
+#endif
+  viewCell->SetFilteredPvsSize(pvs.GetSize());
+  
+  Intersectable::NewMail();
+  return stats;
+}
+#endif
 
   
@@ -6031,5 +6181,6 @@
 		//dummyStrat.push_back(SamplingStrategy::REVERSE_VIEWSPACE_BORDER_BASED_DISTRIBUTION);
 
-		CastPassSamples(samplesPerPass, mStrategies, evaluationSamples);
+		CastPassSamples(samplesPerPass, dummyStrat, evaluationSamples);
+		//CastPassSamples(samplesPerPass, mStrategies, evaluationSamples);
 		
 		castSamples += samplesPerPass;
@@ -6118,3 +6269,60 @@
 }
 #endif
-}
+
+
+LocalMergeTree::LocalMergeTree(const ViewCellContainer &viewCells):
+mViewCells(viewCells)
+{
+	mRoot = Subdivide(0, (int)mViewCells.size());
+}
+
+
+void LocalMergeTree::Merge(ObjectPvs &mergedPvs)
+{
+	Merge(mRoot, mergedPvs);
+}
+
+
+void LocalMergeTree::Merge(LocalMergeNode *node, ObjectPvs &mergedPvs)
+{
+	////////////////
+	//-- pvs is not stored with the interiors => reconstruct
+	if (node->IsLeaf())
+	{
+		LocalMergeLeaf *leaf = dynamic_cast<LocalMergeLeaf *>(node);
+        mergedPvs = leaf->mViewCell->GetPvs();
+	}
+	else
+	{
+		LocalMergeInterior *interior = dynamic_cast<LocalMergeInterior *>(node);
+
+		ObjectPvs leftPvs, rightPvs;
+
+		Merge(interior->mLeft, leftPvs);
+		Merge(interior->mRight, rightPvs);
+
+		ObjectPvs::Merge(mergedPvs, leftPvs, rightPvs);
+	}	
+}
+
+
+LocalMergeNode *LocalMergeTree::Subdivide(const int leftIdx, const int rightIdx)
+{
+	if (leftIdx == rightIdx)
+	{
+		return new LocalMergeLeaf(mViewCells[leftIdx]);
+	}
+
+	LocalMergeInterior *interior = new LocalMergeInterior();
+
+	const int midSplit = (leftIdx + rightIdx) / 2;
+
+	interior->mLeft = Subdivide(leftIdx, midSplit);
+	interior->mRight = Subdivide(midSplit,  rightIdx);
+
+	return interior;
+}
+
+
+
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/ViewCell.cpp
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/ViewCell.cpp	(revision 1772)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/ViewCell.cpp	(revision 1786)
@@ -529,5 +529,7 @@
 	float totalRenderCost = 0;
 
+	//////////////////
 	//-- compute statistics values of initial view cells
+
 	mViewCellsManager->EvaluateRenderStatistics(totalRenderCost,
 												mExpectedCost,
@@ -537,5 +539,5 @@
 												mAvgRenderCost);
 
-
+	/////////////
 	//-- fill merge queue
 	vector<MergeCandidate> candidates;
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/BvHierarchy.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/BvHierarchy.h	(revision 1785)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/BvHierarchy.h	(revision 1786)
@@ -207,27 +207,6 @@
 	inline void SetTimeStamp(const int timeStamp) { mTimeStamp = timeStamp; };
 
-	/////////////////////////////////////
-	//-- mailing options
-	
-// 	static void NewMail(const int reserve = 1) {
-// 		sMailId += sReservedMailboxes;
-// 		sReservedMailboxes = reserve;
-// 	}
-	
-// 	void Mail() { mMailbox = sMailId; }
-// 	bool Mailed() const { return mMailbox == sMailId; }
-
-// 	void Mail(const int mailbox) { mMailbox = sMailId + mailbox; }
-// 	bool Mailed(const int mailbox) const { return mMailbox == sMailId + mailbox; }
-
-// 	int IncMail() { return ++ mMailbox - sMailId; }
-
-// 	static int sMailId;
-// 	//int mMailbox;
-// 	static int sReservedMailboxes;
-
-
-
-	/////////////////////////////////////////////
+
+	////////////////////////
 	//-- inherited functions from Intersectable
 
@@ -266,4 +245,6 @@
 
 	///////////////////////////////////
+
+	float mRenderCost;
 
 protected:
@@ -644,4 +625,7 @@
 	void CollectObjects(const AxisAlignedBox3 &box, ObjectContainer &objects);
 
+	float GetRenderCostIncrementially(BvhNode *node) const;
+
+
 protected:
 
@@ -911,6 +895,4 @@
 	bool InitialTerminationCriteriaMet(const BvhTraversalData &tData) const;
 
-	float mMinInitialSurfaceArea;
-	int mInitialObjectsSize;
 
 protected:
@@ -1007,9 +989,13 @@
 	float mMemoryConst;
 
+	int mMaxTests;
+
 	bool mIsInitialSubdivision;
 
 	bool mApplyInitialPartition;
-
-	int mMaxTests;
+	
+	int mInitialMinObjects;
+	float mInitialMaxAreaRatio;
+	float mInitialMinArea;
 };
 
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/Pvs.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/Pvs.h	(revision 1764)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/Pvs.h	(revision 1786)
@@ -407,4 +407,17 @@
 void Pvs<T, S>::MergeInPlace(const Pvs<T, S> &a)
 {
+	// early exit
+	if (a.Empty())
+	{
+		return;
+	}
+	else if (Empty())
+	{
+		mEntries.reserve(a.GetSize());
+		mEntries = a.mEntries;
+		mSamples = a.mSamples;
+		return;
+	}
+
 	ObjectPvs interPvs;
 	
@@ -467,5 +480,9 @@
 	mEntries.clear();
 	mSamples = 0;
-	vector<PvsEntry<T,S> >().swap(mEntries);
+
+	if (trim)
+	{
+		vector<PvsEntry<T,S> >().swap(mEntries);
+	}
 }
 
@@ -473,5 +490,5 @@
 template <typename T, typename S> void Pvs<T, S>::Trim()
 {
-	vector<PvsEntry<T,S> >(mEntries).swap(mEntries);//trim vi
+	vector<PvsEntry<T,S> >(mEntries).swap(mEntries);
 }
 
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/IntersectableWrapper.cpp
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/IntersectableWrapper.cpp	(revision 1765)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/IntersectableWrapper.cpp	(revision 1786)
@@ -56,4 +56,5 @@
 	return mItem.GetNormal();
 }
+
 
 int
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/IntelRayCaster.cpp
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/IntelRayCaster.cpp	(revision 1757)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/IntelRayCaster.cpp	(revision 1786)
@@ -55,8 +55,9 @@
 
 	if (hittriangle != -1 ) {
-		if (hittriangle >= mPreprocessor.mFaceParents.size())
-			cerr<<"Warning: triangle index out of range! "<<hittriangle<<endl;
-		else {
-			hitA.mObject = mPreprocessor.mFaceParents[hittriangle].mObject;
+		Intersectable *intersect = mPreprocessor.GetParentObject(hittriangle);
+		
+		if (intersect)
+		{
+			hitA.mObject = intersect;
 			hitA.mNormal = Vector3(normal[0], normal[1], normal[2]);
 			// Get the normal of that face
@@ -77,17 +78,15 @@
 			dist);
 
-		if (hittriangle != -1 ) {
-			if (hittriangle >= mPreprocessor.mFaceParents.size())
-				cerr<<"Warning: triangle index out of range! "<<hittriangle<<endl;
-			else 
-			{
-				hitB.mObject = mPreprocessor.mFaceParents[hittriangle].mObject;
-				hitB.mNormal = Vector3(normal[0], normal[1], normal[2]);
-				// Get the normal of that face
-				//		Mesh *mesh = ((MeshInstance *)objectB)->GetMesh();
-				//		normalA = mesh->GetFacePlane(mFaceParents[forward_hit_triangles[i]].mFaceIndex).mNormal;
-				//-rays[index+i].mDirection; // $$ temporary
-				hitB.mPoint = simpleRay.Extrap(dist);
-			}
+		Intersectable *intersect = mPreprocessor.GetParentObject(hittriangle);
+		
+		if (intersect)
+		{
+			hitB.mObject = intersect;
+			hitB.mNormal = Vector3(normal[0], normal[1], normal[2]);
+			// Get the normal of that face
+			//		Mesh *mesh = ((MeshInstance *)objectB)->GetMesh();
+			//		normalA = mesh->GetFacePlane(mFaceParents[forward_hit_triangles[i]].mFaceIndex).mNormal;
+			//-rays[index+i].mDirection; // $$ temporary
+			hitB.mPoint = simpleRay.Extrap(dist);
 		}
 	}
@@ -170,53 +169,54 @@
 
 	for (i=0; i < num; i++) 
-	  {
+	{
 		Intersection hitA(rays[i].mOrigin), hitB(rays[i].mOrigin);
 
 #if DEBUG_RAYCAST
-	  Debug<<"FH\n"<<flush;
-#endif
-		
-		if (forward_hit_triangles[i] != -1 ) {
-		  if (forward_hit_triangles[i] >= mPreprocessor.mFaceParents.size())
-			cerr<<"Warning: triangle index out of range! "<<forward_hit_triangles[i]<<endl;
-		  else { 
-			hitA.mObject = mPreprocessor.mFaceParents[forward_hit_triangles[i]].mObject;
+		Debug<<"FH\n"<<flush;
+#endif
+		Intersectable *intersect = mPreprocessor.GetParentObject(forward_hit_triangles[i]);
+
+		if (intersect)
+		{
+			hitA.mObject = intersect;
 			// Get the normal of that face
-			hitA.mNormal = hitA.mObject->GetNormal(mPreprocessor.mFaceParents[forward_hit_triangles[i]].mFaceIndex);
+			hitA.mNormal = mPreprocessor.GetParentNormal(forward_hit_triangles[i]);
+
 			//-rays[index+i].mDirection; // $$ temporary
 			hitA.mPoint = rays[index+i].Extrap(forward_dist[i]);
+		}
+	
+#if DEBUG_RAYCAST
+		Debug<<"BH\n"<<flush;
+#endif
+
+		if (castDoubleRay) 
+		{
+			Intersectable *intersect = mPreprocessor.GetParentObject(backward_hit_triangles[i]);
+
+			if (intersect)
+			{ 
+				hitB.mObject = intersect;
+				hitB.mNormal = mPreprocessor.GetParentNormal(backward_hit_triangles[i]);
+
+				// normalB = rays[index+i].mDirection; // $$ temporary
+				hitB.mPoint = rays[index+i].Extrap(-backward_dist[i]);
 			}
-	  }
-#if DEBUG_RAYCAST
-	  Debug<<"BH\n"<<flush;
-#endif
-	  
-	  if (castDoubleRay && (backward_hit_triangles[i] != -1)) {
-		if (backward_hit_triangles[i] >= mPreprocessor.mFaceParents.size())
-		  cerr<<"Warning: triangle  index out of range! "<<backward_hit_triangles[i]<<endl;
-		else { 
-		  hitB.mObject = mPreprocessor.mFaceParents[backward_hit_triangles[i]].mObject;
-		  hitB.mNormal = hitB.mObject->GetNormal(mPreprocessor.mFaceParents[backward_hit_triangles[i]].mFaceIndex);
-		  
-		  // normalB = rays[index+i].mDirection; // $$ temporary
-		  hitB.mPoint = rays[index+i].Extrap(-backward_dist[i]);
-		}
-	  }
-	  
-#if DEBUG_RAYCAST
-	  Debug<<"PR\n"<<flush;
-#endif
-	  
-	  ProcessRay(
-				 rays[index + i],
-				 hitA,
-				 hitB,
-				 vssRays,
-				 sbox,
-				 castDoubleRay,
-				 pruneInvalidRays
-				 );
-	}
-	
+		}
+
+#if DEBUG_RAYCAST
+		Debug<<"PR\n"<<flush;
+#endif
+
+		ProcessRay(rays[index + i],
+				   hitA,
+				   hitB,
+				   vssRays,
+				   sbox,
+				   castDoubleRay,
+				   pruneInvalidRays
+				   );
+	}
+
 #if DEBUG_RAYCAST
 	Debug<<"C16F\n"<<flush;
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/Parser.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/Parser.h	(revision 1379)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/Parser.h	(revision 1786)
@@ -22,5 +22,5 @@
 						 const bool loadMeshes = true,
 						 std::vector<FaceParentInfo> *parents = NULL) 
-  {return false;};
+  {return false;}
 	
 };
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/HierarchyManager.cpp
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/HierarchyManager.cpp	(revision 1784)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/HierarchyManager.cpp	(revision 1786)
@@ -29,5 +29,5 @@
 #define USE_FIXEDPOINT_T 0
 
-
+#define STUPID_METHOD 0
 
 /*******************************************************************/
@@ -1787,7 +1787,11 @@
 		// hack for choosing which node to account for
 		if (intersect->IsLeaf())
+		{
 			activeNode = dynamic_cast<BvhLeaf *>(intersect)->GetActiveNode();
+		}
 		else
+		{
 			activeNode = intersect;
+		}
 
 		if (!activeNode->Mailed())
@@ -1795,9 +1799,13 @@
 			activeNode->Mail();
 
+#if STUPID_METHOD
+
 			ObjectContainer objects;
-			activeNode->CollectObjects(objects);
-
+            activeNode->CollectObjects(objects);
+			rc += mBvHierarchy->EvalAbsCost(objects);
+#else
+			rc += mBvHierarchy->GetRenderCostIncrementially(activeNode);
+#endif
 			++ pvsEntries;
-			rc += mBvHierarchy->EvalAbsCost(objects);
 		}
 	}
@@ -1810,5 +1818,4 @@
 	////////////////
 	//-- pvs is not stored with the interiors => reconstruct
-	ViewCell *root = vc;
 	
 	// add pvs from leaves
@@ -1824,8 +1831,11 @@
 		if (!vc->GetPvs().Empty())
 		{
+			if (vc->IsLeaf()) cout << " l " << pvs.GetSize();
+			else cout << " i " << pvs.GetSize();
 			pvs.MergeInPlace(vc->GetPvs());
 		}
 		else if (!vc->IsLeaf()) // interior cells: go down to leaf level
 		{
+			cout <<" t";
 			ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(vc);
 			ViewCellContainer::const_iterator it, it_end = interior->mChildren.end();
@@ -1836,6 +1846,91 @@
 			}		
 		}
-	}
-}
+		else cout <<"k";
+	}
+}
+
+
+// TODO matt: implement this function for different storing methods
+void HierarchyManager::PullUpPvsIncrementally(ViewCell *viewCell) const
+{
+	////////////////
+	//-- pvs is not stored with the interiors => reconstruct
+	
+	// early exit: pvs is already pulled up to this view cell
+	if (!viewCell->GetPvs().Empty())
+		return;
+
+	// add pvs from leaves
+	stack<ViewCell *> tstack;
+	tstack.push(viewCell);
+
+	ViewCell *vc = viewCell;
+
+	while (!tstack.empty())
+	{
+		vc = tstack.top();
+		tstack.pop();
+	
+		// add newly found pvs to merged pvs: break here even for interior
+		if (!vc->GetPvs().Empty())
+		{
+			/*if (vc->IsLeaf()) 
+				cout << " l " << viewCell->GetPvs().GetSize();
+			else cout << " i " << viewCell->GetPvs().GetSize();
+			*/
+				viewCell->GetPvs().MergeInPlace(vc->GetPvs());
+		}
+		else if (!vc->IsLeaf()) // interior cells: go down to leaf level
+		{
+			//cout <<" t";
+			ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(vc);
+			ViewCellContainer::const_iterator it, it_end = interior->mChildren.end();
+
+			for (it = interior->mChildren.begin(); it != it_end; ++ it)
+			{
+				tstack.push(*it);
+			}		
+		}
+	}
+}
+
+
+
+// TODO matt: implement this function for different storing methods
+void HierarchyManager::GetPvsRecursive(ViewCell *vc, ObjectPvs &pvs) const
+{
+	////////////////
+	//-- pvs is not stored with the interiors => reconstruct
+	if (vc->IsLeaf() || !vc->GetPvs().Empty())
+	{
+		pvs = vc->GetPvs();
+	}
+	else
+	{
+		ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(vc);
+#if 0
+		ViewCellContainer::const_iterator it, it_end = interior->mChildren.end();
+		const int childPvsSize = (int)interior->mChildren.size();
+		vector<ObjectPvs> childPvs;
+		childPvs.resize((int)interior->mChildren.size());
+
+		int i = 0;
+		for (it = interior->mChildren.begin(); it != it_end; ++ it, ++ i)
+		{
+			GetPvsRecursive(*it, childPvs[i]);
+			pvs.MergeInPlace(childPvs[i]);
+		}
+#else
+
+		ObjectPvs leftPvs, rightPvs;
+
+		GetPvsRecursive(interior->mChildren[0], leftPvs);
+		GetPvsRecursive(interior->mChildren[1], rightPvs);
+
+		ObjectPvs::Merge(pvs, leftPvs, rightPvs);
+#endif
+	}
+}
+
 
 int HierarchyManager::ExtractStatistics(const int maxSplits,
@@ -1868,15 +1963,22 @@
 	ViewCell::NewMail();
 
+	cout << "\n**************viewcells: " << viewCells.size() << endl;
 	for (vit = viewCells.begin(); vit != vit_end; ++ vit)
 	{
 		ViewCell *vc = *vit;
 
+		//cout << "\nhere5: ";
 		float rc = 0;
-        ObjectPvs pvs;
-		
-		//mVspTree->mViewCellsTree->GetPvs(vc, pvs);
+        
+#if STUPID_METHOD	
+		ObjectPvs pvs;
 		GetPvsIncrementally(vc, pvs);
-		
 		vc->SetPvs(pvs);
+#else
+		//PullUpPvsIncrementally(vc);
+		ObjectPvs pvs;
+		GetPvsRecursive(vc, pvs);
+		vc->SetPvs(pvs);
+#endif
 
 		vc->Mail();
@@ -1884,11 +1986,15 @@
 		if (useFilter)
 		{
+			const long startT = GetTime();
 			ObjectPvs filteredPvs;
 			mVspTree->mViewCellsManager->ApplyFilter2(vc, false, 1.0f, filteredPvs);
+			const long endT = GetTime();
+
+			cout << "filter computed in " << TimeDiff(startT, endT) * 1e-3f << " secs" << endl;
 			ComputePvs(filteredPvs, rc, pvsEntries);
 		}
 		else
 		{
-			ComputePvs(pvs, rc, pvsEntries);
+			ComputePvs(vc->GetPvs(), rc, pvsEntries);
 		}
 
@@ -1915,4 +2021,5 @@
 	}
 
+	// store current level
 	mOldViewCells = viewCells;
 
@@ -2098,5 +2205,5 @@
 	vector<HierarchySubdivisionStats> subStatsContainer;
 
-	int splits = (1 + mHierarchyStats.Leaves() / splitsStepSize) * splitsStepSize;
+	int splits = (1 + (mHierarchyStats.Leaves() - 1) / splitsStepSize) * splitsStepSize;
 	cout << "splits: " << splits << endl;
 
@@ -2133,9 +2240,10 @@
 		
 		if (splits == 0)
+		{
 			break;
-
+		}
 		splits -= splitsStepSize;
 
-		cout << subStats.mNumSplits << " ";
+		cout << "splits: " << subStats.mNumSplits << " ";
 	}
 
