Index: trunk/VUT/GtpVisibilityPreprocessor/src/VspBspTree.h
===================================================================
--- trunk/VUT/GtpVisibilityPreprocessor/src/VspBspTree.h	(revision 440)
+++ trunk/VUT/GtpVisibilityPreprocessor/src/VspBspTree.h	(revision 441)
@@ -349,8 +349,4 @@
 		/// rays piercing this node
 		RayInfoContainer *mRays;
-		/// area of current node
-		float mArea;
-		/// geometry of current node induced by split planes
-		VspBspNodeGeometry *mGeometry;
 
 		/// pvs size
@@ -371,7 +367,5 @@
 		mViewCell(NULL),
 		mRays(NULL),
-		mPvs(0),
-		mArea(0.0),
-		mGeometry(NULL)
+		mPvs(0)
 		{}
 		
@@ -381,7 +375,5 @@
 						 ViewCell *viewCell,
 						 RayInfoContainer *rays,
-						 int pvs,
-						 float area,
-						 VspBspNodeGeometry *cell): 
+						 int pvs): 
 		mNode(node), 
 		mPolygons(polys), 
@@ -389,7 +381,5 @@
 		mViewCell(viewCell),
 		mRays(rays),
-		mPvs(pvs),
-		mArea(area),
-		mGeometry(cell)
+		mPvs(pvs)
 		{}
     };
@@ -762,5 +752,5 @@
 
 	/// if area or accumulated ray lenght should be used for PVS heuristics
-	bool mPvsUseArea;
+	bool mPvsUseLen;
 
 private:
Index: trunk/VUT/GtpVisibilityPreprocessor/src/RenderSimulator.h
===================================================================
--- trunk/VUT/GtpVisibilityPreprocessor/src/RenderSimulator.h	(revision 440)
+++ trunk/VUT/GtpVisibilityPreprocessor/src/RenderSimulator.h	(revision 441)
@@ -37,4 +37,9 @@
 		return s;
 	}  
+
+	SimulationStatistics()
+	{
+		Reset();
+	}
 };
 
Index: trunk/VUT/GtpVisibilityPreprocessor/src/ViewCellBsp.h
===================================================================
--- trunk/VUT/GtpVisibilityPreprocessor/src/ViewCellBsp.h	(revision 440)
+++ trunk/VUT/GtpVisibilityPreprocessor/src/ViewCellBsp.h	(revision 441)
@@ -364,8 +364,5 @@
 		/// rays piercing this node
 		BoundedRayContainer *mRays;
-		/// area of current node
-		float mArea;
-		BspNodeGeometry *mGeometry;
-
+		
 		/// pvs size
 		int mPvs;
@@ -385,7 +382,5 @@
 		mViewCell(NULL),
 		mRays(NULL),
-		mPvs(0),
-		mArea(0.0),
-		mGeometry(NULL)
+		mPvs(0)
 		{}
 		
@@ -395,7 +390,5 @@
 						 ViewCell *viewCell,
 						 BoundedRayContainer *rays,
-						 int pvs,
-						 float area,
-						 BspNodeGeometry *cell): 
+						 int pvs): 
 		mNode(node), 
 		mPolygons(polys), 
@@ -403,7 +396,5 @@
 		mViewCell(viewCell),
 		mRays(rays),
-		mPvs(pvs),
-		mArea(area),
-		mGeometry(cell)
+		mPvs(pvs)
 		{}
     };
@@ -412,10 +403,10 @@
 
 	/** Default constructor creating an empty tree.
-		@param viewCell view cell corresponding to unbounded space
 	*/ 
-	BspTree(BspViewCell *viewCell);
-
+	BspTree();
+	
 	~BspTree();
 
+	
 	const BspTreeStatistics &GetStatistics() const; 
   
@@ -506,19 +497,11 @@
 	BspLeaf *GetRandomLeaf(const bool onlyUnmailed = false);
 
-	/** Returns true if merge criteria are reached.
-	*/
-    bool ShouldMerge(BspLeaf *front, BspLeaf *back) const;
-
-	/** Merges view cells based on some criteria
-	    E.g., empty view cells can pe purged, view cells which have 
-		a very similar PVS can be merged to one larger view cell.
-
-		@returns true if merge was successful.
-	*/
-	bool MergeViewCells(BspLeaf *front, BspLeaf *back) const;
-
 	/** Traverses tree and counts all view cells as well as their PVS size.
 	*/
 	void EvaluateViewCellsStats(BspViewCellsStatistics &stat) const;
+
+	/** Returns view cell corresponding to unbounded space.
+	*/
+	BspViewCell *GetRootCell() const;
 
 	/** Parses the environment and stores the global BSP tree parameters
@@ -601,7 +584,5 @@
 	float SplitPlaneCost(const Plane3 &candidatePlane, 
 						 const BoundedRayContainer &rays,
-						 const int pvs,
-						 const float area,
-						 const BspNodeGeometry &cell) const;
+						 const int pvs) const;
 
 	/** Filters next view cell down the tree and inserts it into the appropriate leaves
@@ -834,5 +815,7 @@
 	/// number of candidates for split planes evaluated using the rays
 	int mMaxRayCandidates;
-	
+	/// maximum tests for split plane evaluation with a single candidate
+	int mMaxTests;
+
 	float mCtDivCi;
 
@@ -856,10 +839,6 @@
 	float mBalancedViewCellsFactor;
 
-	//-- thresholds used for view cells merge
-	int mMinPvsDif;
-	int mMinPvs;
-	int mMaxPvs;
 	/// if area or accumulated ray lenght should be used for PVS heuristics
-	bool mPvsUseArea;
+	bool mPvsUseLen;
 
 private:
Index: trunk/VUT/GtpVisibilityPreprocessor/src/VspBspTree.cpp
===================================================================
--- trunk/VUT/GtpVisibilityPreprocessor/src/VspBspTree.cpp	(revision 439)
+++ trunk/VUT/GtpVisibilityPreprocessor/src/VspBspTree.cpp	(revision 441)
@@ -222,5 +222,5 @@
 mRoot(NULL), 
 mStoreLeavesWithRays(false),
-mPvsUseArea(true)
+mPvsUseLen(true)
 {
 	Randomize(); // initialise random generator for heuristics
@@ -485,5 +485,5 @@
 
 	VspBspTraversalData tData(mRoot, polys, 0, mRootCell, rays, 
-						   ComputePvsSize(*rays), cell->GetArea(), cell);
+						   ComputePvsSize(*rays));
 
 	tStack.push(tData);
@@ -515,5 +515,4 @@
 		(((int)data.mRays->size() <= mTermMinRays) ||
 		 (data.mPvs <= mTermMinPvs) ||
-		 (data.mArea <= mTermMinArea) ||
 		 (data.mDepth >= mTermMaxDepth) ||
 		 (data.GetAvgRayContribution() < mTermMaxRayContribution));
@@ -548,5 +547,5 @@
 		DEL_PTR(tData.mPolygons);
 		DEL_PTR(tData.mRays);
-		DEL_PTR(tData.mGeometry);
+		//DEL_PTR(tData.mGeometry);
 		
 		return leaf;
@@ -557,7 +556,7 @@
 	
 	VspBspTraversalData tFrontData(NULL, new PolygonContainer(), tData.mDepth + 1, mRootCell, 
-								new RayInfoContainer(), 0, 0, new VspBspNodeGeometry());
+								new RayInfoContainer(), 0);
 	VspBspTraversalData tBackData(NULL, new PolygonContainer(), tData.mDepth + 1, mRootCell, 
-							   new RayInfoContainer(), 0, 0, new VspBspNodeGeometry());
+							   new RayInfoContainer(), 0);
 
 	// create new interior node and two leaf nodes
@@ -583,5 +582,5 @@
 	DEL_PTR(tData.mPolygons);
 	DEL_PTR(tData.mRays);
-	DEL_PTR(tData.mGeometry);		
+	//DEL_PTR(tData.mGeometry);		
 
 	return interior;
@@ -616,17 +615,4 @@
 	frontData.mPvs = ComputePvsSize(*frontData.mRays);
 	backData.mPvs = ComputePvsSize(*backData.mRays);
-
-	// split geometry and compute area
-	if (1)
-	{
-		tData.mGeometry->SplitGeometry(*frontData.mGeometry, 
-									   *backData.mGeometry, 
-									   *this, 
-									   interior->mPlane);
-	
-		
-		frontData.mArea = frontData.mGeometry->GetArea();
-		backData.mArea = backData.mGeometry->GetArea();
-	}
 
 	// compute accumulated ray length
@@ -1006,22 +992,7 @@
 
 	if (mSplitPlaneStrategy & PVS)
-	{
 		// create unique ids for pvs heuristics
 		GenerateUniqueIdsForPvs();
-
-		if (mPvsUseArea) // use front and back cell areas to approximate volume
-		{	
-			// construct child geometry with regard to the candidate split plane
-			VspBspNodeGeometry frontCell;
-			VspBspNodeGeometry backCell;
-
-			data.mGeometry->SplitGeometry(frontCell, backCell, *this, candidatePlane);
-		
-			pFront = frontCell.GetArea();
-			pBack = backCell.GetArea();
-
-			pOverall = data.mArea;
-		}
-	}
+	
 			
 	RayInfoContainer::const_iterator rit, rit_end = data.mRays->end();
@@ -1055,15 +1026,19 @@
 			AddObjToPvs(ray->mOriginObject, cf, frontPvs, backPvs);
 			
-			if (!mPvsUseArea) // use front and back cell areas to approximate volume
-			{	
-				const float len = (*rit).SegmentLength();
-				pOverall += len;
-
-				// use length of rays to approximate volume
-				if (cf == 1)
-					pFront += len;
-				if (cf == -1)
-					pBack += len;
-				if (cf == 0)
+			float len = 1;
+
+			if (mPvsUseLen) // use front and back cell areas to approximate volume
+				len = (*rit).SqrSegmentLength();
+			
+			pOverall += len;
+
+			// use length of rays to approximate volume
+			if (cf == 1)
+				pFront += len;
+			if (cf == -1)
+				pBack += len;
+			if (cf == 0)
+			{
+				if (mPvsUseLen)
 				{
 					float newLen = len * 
@@ -1071,4 +1046,5 @@
 						((*rit).GetMaxT() - (*rit).GetMinT());
 
+				
 					if (candidatePlane.Side((*rit).ExtrapOrigin()) <= 0)
 					{
@@ -1081,5 +1057,10 @@
 						pBack += len - newLen;
 					}
-				}				
+				}
+				else
+				{
+					++ pFront;
+					++ pBack;
+				}
 			}
 		}
@@ -1094,11 +1075,12 @@
 		val += mBalancedRaysFactor * fabs(sumBalancedRays) /  raysSize;
 
-	float denom = pOverall * (float)data.mPvs * 2.0f + Limits::Small;
-	if ((mSplitPlaneStrategy & PVS) && data.mArea && data.mPvs)
+	const float denom = pOverall * (float)data.mPvs * 2.0f + Limits::Small;
+
+	if (mSplitPlaneStrategy & PVS)
 	{
 		val += mPvsFactor * (frontPvs * pFront + (backPvs * pBack)) / denom;
 
 		// give penalty to unbalanced split
-		if (1)
+		if (0)
 		if (((pFront * 0.2 + Limits::Small) > pBack) || (pFront < (pBack * 0.2 + Limits::Small)))
 			val += 0.5;
@@ -1217,6 +1199,4 @@
 		++ mStat.maxRayContribNodes;
 	
-	if (data.mGeometry->GetArea() <= mTermMinArea) 
-		++ mStat.minAreaNodes;
 
 #ifdef _DEBUG
Index: trunk/VUT/GtpVisibilityPreprocessor/src/ViewCellsManager.h
===================================================================
--- trunk/VUT/GtpVisibilityPreprocessor/src/ViewCellsManager.h	(revision 440)
+++ trunk/VUT/GtpVisibilityPreprocessor/src/ViewCellsManager.h	(revision 441)
@@ -45,11 +45,27 @@
 						  AxisAlignedBox3 *sceneBbox = NULL) = 0;
 
-	/** Casts bundle of rays to the view cells and stores contributions in PVS.
-	*/
-	int CastRays(const RayContainer &rays);
-
-	/** Casts ray to the view cells and stores contributions in PVS.
-	*/
-	virtual int CastRay(const Ray &ray) = 0;
+	/** Computes sample contributions of the rays to the view cells PVS.
+	
+		@param rays bundle of rays used to find intersections with view cells and 
+		adding the contribution
+		@param castRays true if ray should be cast to gain the information, false if rays
+		already hold the view cells intersection information and need not be recast.
+		@param sampleContributions returns the number of sample contributions
+		@param contributingSamples returns the number of contributingSamples
+	*/
+	void  ComputeSampleContributions(const RayContainer &rays, 
+									 const bool castRays,
+									 int &sampleContributions,
+									 int &contributingSamples);
+
+
+	/** Computes sample contribution of a simgle ray to the view cells PVS.
+		@param ray finds intersections with view cells and holds the contribution
+		@param castRay true if ray should be cast to gain the information, false if ray
+		is already holding the information and need not be recast.
+
+		@returns number of sample contributions
+	*/
+	virtual int ComputeSampleContributions(Ray &ray, const bool castRay = true) = 0;
 
 	/** Post processes view cells givemŽa number of rays.
@@ -91,5 +107,5 @@
 		@returns new view cell based on the merging.
 	*/
-	ViewCell *Merge(ViewCell &front, ViewCell &back) const;
+	ViewCell *MergeViewCells(ViewCell &front, ViewCell &back) const;
 	
 	/** Generates view cell of type specified by this manager
@@ -136,11 +152,9 @@
 	virtual bool ViewCellsConstructed() const = 0;
 	
+	
+
 protected:
-	/** Adds sample constributions to the view cell PVS.
-		@returns number of sample contributions
-	*/
-	virtual int AddSampleContributions(const Ray &ray,
-									   Intersectable *sObject,
-									   Intersectable *tObject) = 0;
+	
+	
 
 	/** Initialises the render time simulator.
@@ -163,5 +177,12 @@
 	int mPostProcessSamples;
 	int mVisualizationSamples;
+
+	//-- thresholds used for view cells merge
+	int mMinPvsDif;
+	int mMinPvs;
+	int mMaxPvs;
 };
+
+
 
 /**
@@ -179,5 +200,5 @@
 				  AxisAlignedBox3 *sceneBbox);
 
-	int CastRay(const Ray &rays);
+	int ComputeSampleContributions(Ray &ray, const bool castRay = false);
 
 	int PostProcess(const ObjectContainer &objects, 
@@ -189,6 +210,4 @@
 	int GetType() const;
 	
-	/** Generates view cell of type specified by this manager
-	*/
 	ViewCell *GenerateViewCell(Mesh *mesh = NULL) const;
 
@@ -197,5 +216,11 @@
 protected:
 
-	int	AddSampleContributions(const Ray &ray, Intersectable *sObject, Intersectable *tObject);
+	/** Merges view cells front and back leaf view cell.
+	*/
+	bool MergeBspLeafViewCells(BspLeaf *front, BspLeaf *back) const;
+
+	/** Returns true if front and back leaf should be merged.
+	*/
+	bool ShouldMerge(BspLeaf *front, BspLeaf *back) const;
 
 	/// the BSP tree.
@@ -247,11 +272,11 @@
 	 KdNode *GetNodeForPvs(KdLeaf *leaf);
 
-	 int AddSampleContributions(const Ray &ray, Intersectable *sObject, Intersectable *tObject);
-
-	/// the BSP tree.
-	KdTree *mKdTree;
-
-	/// depth of the KD tree nodes with represent the view cells
-	int mKdPvsDepth;
+	 int ComputeSampleContributions(Ray &ray, const bool castRay = true);
+
+	 /// the BSP tree.
+	 KdTree *mKdTree;
+
+	 /// depth of the KD tree nodes with represent the view cells
+	 int mKdPvsDepth;
 };
 
@@ -271,5 +296,5 @@
 				  AxisAlignedBox3 *sceneBbox);
 
-	int CastRay(const Ray &rays);
+	int ComputeSampleContributions(Ray &ray, const bool castRay = true);
 
 	int PostProcess(const ObjectContainer &objects, 
@@ -285,6 +310,4 @@
 
 protected:
-
-	int	AddSampleContributions(const Ray &ray, Intersectable *sObject, Intersectable *tObject);
 
 	/// the BSP tree.
Index: trunk/VUT/GtpVisibilityPreprocessor/src/Environment.cpp
===================================================================
--- trunk/VUT/GtpVisibilityPreprocessor/src/Environment.cpp	(revision 438)
+++ trunk/VUT/GtpVisibilityPreprocessor/src/Environment.cpp	(revision 441)
@@ -1175,8 +1175,13 @@
 								 "true");
 
-  RegisterOption("ViewCells.hierarchy",
+  RegisterOption("ViewCells.type",
 		 optString,
-		 "-view_cells_hierarchy",
+		 "-view_cells_type",
 		 "bspTree");
+
+   RegisterOption("ViewCells.loadFromFile",
+		 optBool,
+		 "-view_cells_load_from_file",
+		 "false");
 
   RegisterOption("ViewCells.maxViewCells",
@@ -1329,4 +1334,9 @@
 	  "-bsp_max_plane_candidates=",
 	  "20");
+
+  RegisterOption("BspTree.maxTests",
+	  optInt,
+	  "-bsp_max_tests=",
+	  "5000");
 
   RegisterOption("BspTree.Visualization.samples",
Index: trunk/VUT/GtpVisibilityPreprocessor/src/ViewCellBsp.cpp
===================================================================
--- trunk/VUT/GtpVisibilityPreprocessor/src/ViewCellBsp.cpp	(revision 440)
+++ trunk/VUT/GtpVisibilityPreprocessor/src/ViewCellBsp.cpp	(revision 441)
@@ -263,12 +263,14 @@
 /****************************************************************/
 
-BspTree::BspTree(BspViewCell *viewCell): 
-mRootCell(viewCell), 
+BspTree::BspTree():  
 mRoot(NULL), 
 mStoreLeavesWithRays(false),
-mPvsUseArea(true),
+mPvsUseLen(false),
 mGenerateViewCells(true)
 {
 	Randomize(); // initialise random generator for heuristics
+
+	// the view cell corresponding to unbounded space
+	mRootCell = new BspViewCell();
 
 	//-- termination criteria for autopartition
@@ -307,12 +309,9 @@
 	environment->GetIntValue("BspTree.splitPlaneStrategy", mSplitPlaneStrategy);
 	environment->GetFloatValue("BspTree.AxisAligned.splitBorder", mSplitBorder);
+	environment->GetIntValue("BspTree.maxTests", mMaxTests);
 
 	environment->GetFloatValue("BspTree.Construction.sideTolerance", Vector3::sDistTolerance);
 	Vector3::sDistToleranceSqrt = Vector3::sDistTolerance * Vector3::sDistTolerance;
 
-	// post processing stuff
-	environment->GetIntValue("ViewCells.PostProcessing.minPvsDif", mMinPvsDif);
-	environment->GetIntValue("ViewCells.PostProcessing.minPvs", mMinPvs);
-	environment->GetIntValue("ViewCells.PostProcessing.maxPvs", mMaxPvs);
 
     Debug << "BSP max depth: " << mTermMaxDepth << endl;
@@ -410,4 +409,10 @@
 {
 	DEL_PTR(mRoot);
+	DEL_PTR(mRootCell);
+}
+
+BspViewCell *BspTree::GetRootCell() const
+{
+	return mRootCell;
 }
 
@@ -433,6 +438,6 @@
 		mRoot = new BspLeaf();
 
-	tStack.push(BspTraversalData(mRoot, polys, 0, mRootCell, new BoundedRayContainer(), 0, 
-								 mBox.SurfaceArea(), new BspNodeGeometry()));
+	tStack.push(BspTraversalData(mRoot, polys, 0, mRootCell, 
+		new BoundedRayContainer(), 0));
 
 	while (!tStack.empty())
@@ -470,7 +475,5 @@
 										   mRootCell,	
 										   tData.mRays,
-										   tData.mPvs,
-										   mBox.SurfaceArea(),
-										   new BspNodeGeometry());
+										   tData.mPvs);
 
 				BspTraversalData backData(interior->GetBack(), 
@@ -479,7 +482,5 @@
 										  mRootCell,	
 										  tData.mRays,
-										  tData.mPvs,
-										  mBox.SurfaceArea(),
-										  new BspNodeGeometry());
+										  tData.mPvs);
 
 				if (!mGenerateViewCells)
@@ -735,5 +736,5 @@
 
 	BspTraversalData tData(mRoot, polys, 0, mRootCell, rays, 
-						   ComputePvsSize(*rays), cell->GetArea(), cell);
+						   ComputePvsSize(*rays));
 
 	tStack.push(tData);
@@ -755,4 +756,5 @@
 	}
 
+	Debug << "here2" << endl;
 	cout << "finished\n";
 
@@ -766,5 +768,4 @@
 		 ((int)data.mRays->size() <= mTermMinRays) ||
 		 (data.mPvs <= mTermMinPvs) ||
-		 (data.mArea <= mTermMinArea) ||
 		 (data.mDepth >= mTermMaxDepth) ||
 		 (data.GetAvgRayContribution() < mTermMaxRayContribution));
@@ -815,6 +816,5 @@
 		DEL_PTR(tData.mPolygons);
 		DEL_PTR(tData.mRays);
-		DEL_PTR(tData.mGeometry);
-		
+			
 		return leaf;
 	}
@@ -824,7 +824,7 @@
 	
 	BspTraversalData tFrontData(NULL, new PolygonContainer(), tData.mDepth + 1, mRootCell, 
-								new BoundedRayContainer(), 0, 0, new BspNodeGeometry());
+								new BoundedRayContainer(), 0);
 	BspTraversalData tBackData(NULL, new PolygonContainer(), tData.mDepth + 1, mRootCell, 
-							   new BoundedRayContainer(), 0, 0, new BspNodeGeometry());
+							   new BoundedRayContainer(), 0);
 
 	// create new interior node and two leaf nodes
@@ -860,6 +860,5 @@
 	DEL_PTR(tData.mPolygons);
 	DEL_PTR(tData.mRays);
-	DEL_PTR(tData.mGeometry);		
-
+	
 	return interior;
 }
@@ -901,15 +900,28 @@
 	
 	BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode);
+
+	Debug << "*********************" << endl;
+	long startTime = GetTime();
+	
 	// select subdivision plane
 	BspInterior *interior = 
 		new BspInterior(SelectPlane(leaf, tData)); 
-
+	Debug << "time used for split plane selection: " << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
 #ifdef _DEBUG
 	Debug << interior << endl;
 #endif
 	
+
+	Debug << "number of rays: " << tData.mRays->size() << endl;
+	Debug << "number of polys: " << tData.mPolygons->size() << endl;
+
+	startTime = GetTime();
+	
 	// subdivide rays into front and back rays
 	SplitRays(interior->mPlane, *tData.mRays, *frontData.mRays, *backData.mRays);
 	
+	Debug << "time used for rays splitting: " << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
+
+	startTime = GetTime();
 	// subdivide polygons with plane
 	mStat.splits += interior->SplitPolygons(*tData.mPolygons, 
@@ -918,20 +930,9 @@
 											coincident);
 
+	Debug << "time used for polygon splitting: " << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
+
     // compute pvs
 	frontData.mPvs = ComputePvsSize(*frontData.mRays);
 	backData.mPvs = ComputePvsSize(*backData.mRays);
-
-	// split geometry and compute area
-	if (1)
-	{
-		tData.mGeometry->SplitGeometry(*frontData.mGeometry, 
-									   *backData.mGeometry, 
-									   *this, 
-									   interior->mPlane);
-	
-		
-		frontData.mArea = frontData.mGeometry->GetArea();
-		backData.mArea = backData.mGeometry->GetArea();
-	}
 
 	// compute accumulated ray length
@@ -1308,9 +1309,27 @@
 	const int frontAndBackId = ViewCell::sMailId;
 
-	PolygonContainer::const_iterator it, it_end = polys.end();
-
-	for (it = polys.begin(); it != it_end; ++ it)
-	{
-		const int classification = (*it)->ClassifyPlane(candidatePlane);
+	bool useRand;;
+	int limit;
+
+	// choose test polyongs randomly if over threshold
+	if ((int)polys.size() > mMaxTests)
+	{
+		useRand = true;
+		limit = mMaxTests;
+	}
+	else
+	{
+		useRand = false;
+		limit = (int)polys.size();
+	}
+	
+
+	for (int i = 0; i < limit; ++ i)
+	{
+		const int testIdx = useRand ? Random(limit) : i;
+
+		Polygon3 *poly = polys[testIdx];
+
+        const int classification = poly->ClassifyPlane(candidatePlane);
 
 		if (mSplitPlaneStrategy & BALANCED_POLYS)
@@ -1323,5 +1342,5 @@
 		{
 			if (classification == Polygon3::COINCIDENT)
-				sumPolyArea += (*it)->GetArea();
+				sumPolyArea += poly->GetArea();
 			//totalArea += area;
 		}
@@ -1329,5 +1348,5 @@
 		if (mSplitPlaneStrategy & BLOCKED_RAYS)
 		{
-			const float blockedRays = (float)(*it)->mPiercingRays.size();
+			const float blockedRays = (float)poly->mPiercingRays.size();
 		
 			if (classification == Polygon3::COINCIDENT)
@@ -1340,5 +1359,5 @@
 		if (mSplitPlaneStrategy & BALANCED_VIEW_CELLS)
 		{
-			MeshInstance *viewCell = (*it)->mParent;
+			MeshInstance *viewCell = poly->mParent;
 		
 			// assure that we only count a view cell 
@@ -1434,7 +1453,5 @@
 float BspTree::SplitPlaneCost(const Plane3 &candidatePlane, 
 							  const BoundedRayContainer &rays,
-							  const int pvs,
-							  const float area,
-							  const BspNodeGeometry &cell) const
+							  const int pvs) const
 {
 	float val = 0;
@@ -1442,8 +1459,4 @@
 	float sumBalancedRays = 0;
 	float sumRaySplits = 0;
-	
-	int backId = 0;
-	int frontId = 0;
-	int frontAndBackId = 0;
 
 	int frontPvs = 0;
@@ -1451,7 +1464,7 @@
 
 	// probability that view point lies in child
-	float pOverall = 0;
-	float pFront = 0;
-	float pBack = 0;
+	float pOverall = 1;
+	float pFront = 0.5;
+	float pBack = 0.5;
 
 	if (mSplitPlaneStrategy & PVS)
@@ -1459,27 +1472,30 @@
 		// create unique ids for pvs heuristics
 		GenerateUniqueIdsForPvs();
-
-		if (mPvsUseArea) // use front and back cell areas to approximate volume
-		{	
-			// construct child geometry with regard to the candidate split plane
-			BspNodeGeometry frontCell;
-			BspNodeGeometry backCell;
-
-			cell.SplitGeometry(frontCell, backCell, *this, candidatePlane);
-		
-			pFront = frontCell.GetArea();
-			pBack = backCell.GetArea();
-
-			pOverall = area;
-		}
 	}
 			
-	BoundedRayContainer::const_iterator rit, rit_end = rays.end();
-
-	for (rit = rays.begin(); rit != rays.end(); ++ rit)
-	{
-		Ray *ray = (*rit)->mRay;
-		const float minT = (*rit)->mMinT;
-		const float maxT = (*rit)->mMaxT;
+	bool useRand;;
+	int limit;
+
+	// choose test polyongs randomly if over threshold
+	if ((int)rays.size() > mMaxTests)
+	{
+		useRand = true;
+		limit = mMaxTests;
+	}
+	else
+	{
+		useRand = false;
+		limit = (int)rays.size();
+	}
+
+	for (int i = 0; i < limit; ++ i)
+	{
+		const int testIdx = useRand ? Random(limit) : i;
+	
+		BoundedRay *bRay = rays[testIdx];
+
+		Ray *ray = bRay->mRay;
+		const float minT = bRay->mMinT;
+		const float maxT = bRay->mMaxT;
 
 		Vector3 entP, extP;
@@ -1511,53 +1527,41 @@
 			AddObjToPvs(ray->sourceObject.mObject, cf, frontPvs, backPvs);
 			
-			if (!mPvsUseArea) // use front and back cell areas to approximate volume
-			{	
-				float len = Distance(entP, extP);
-				pOverall += len;
-
-				// use length of rays to approximate volume
-				switch (cf)
+			float len = 1;
+			if (0){
+			if (mPvsUseLen)
+				len = SqrDistance(entP, extP);
+							
+			// use length of rays to approximate volume
+			if (Ray::BACK && Ray::COINCIDENT)
+				pBack += len;
+			if (Ray::FRONT && Ray::COINCIDENT)
+				pFront += len;
+			if (Ray::FRONT_BACK || Ray::BACK_FRONT)
+			{
+				if (mPvsUseLen)
 				{
-					case Ray::COINCIDENT:
-						pBack += len;
-						pFront += len;						
-						break;
-					case Ray::BACK:
-						pBack += len;
-						break;
-					case Ray::FRONT:
-						pFront += len;
-						break;
-					case Ray::FRONT_BACK:
-						{
-							// find intersection of ray segment with plane
-							const Vector3 extp = ray->Extrap(maxT);
-							const float t = candidatePlane.FindT(ray->GetLoc(), extp);
-					
-							const float newT = t * maxT;
-							float newLen = Distance(ray->Extrap(newT), extp);
-
-							pFront += len - newLen;
-							pBack += newLen;
-						}
-						break;
-					case Ray::BACK_FRONT:
-						{
-							// find intersection of ray segment with plane
-							const Vector3 extp = ray->Extrap(maxT);
-							const float t = candidatePlane.FindT(ray->GetLoc(), extp);
-					
-							const float newT = t * maxT;
-							float newLen = Distance(ray->Extrap(newT), extp);
-
-							pFront += len;
-							pBack += len - newLen;
-						}
-						break;
-					default:
-						Debug << "Should not come here 2" << endl;
-						break;
+					const Vector3 extp = ray->Extrap(maxT);
+					const float t = candidatePlane.FindT(ray->GetLoc(), extp);
+				
+					const float newT = t * maxT;
+					const float newLen = SqrDistance(ray->Extrap(newT), extp);
+
+					if (Ray::FRONT_BACK)
+					{
+						pFront += len - newLen;
+						pBack += newLen;
+					}
+					else
+					{
+						pBack += len - newLen;
+						pFront += newLen;
+					}
 				}
-			}
+				else
+				{
+					++ pFront;
+					++ pBack;
+				}
+			}}
 		}
 	}
@@ -1572,14 +1576,16 @@
 
 	float denom = pOverall * (float)pvs * 2.0f + Limits::Small;
-	if ((mSplitPlaneStrategy & PVS) && area && pvs)
+
+	if (mSplitPlaneStrategy & PVS)
 	{
 		val += mPvsFactor * (frontPvs * pFront + (backPvs * pBack)) / denom;
 
 		// give penalty to unbalanced split
-		if (0)
+		if (1)
 		if (((pFront * 0.2 + Limits::Small) > pBack) || (pFront < (pBack * 0.2 + Limits::Small)))
 			val += 0.5;
 	}
 
+	
 #ifdef _DEBUG
 	Debug << "totalpvs: " << pvs << " ptotal: " << pOverall
@@ -1664,6 +1670,5 @@
 		(mSplitPlaneStrategy & PVS))
 	{
-		val += SplitPlaneCost(candidatePlane, *data.mRays, data.mPvs, 
-							  data.mArea, *data.mGeometry);
+		val += SplitPlaneCost(candidatePlane, *data.mRays, data.mPvs);
 	}
 
@@ -1736,6 +1741,6 @@
 		++ mStat.maxRayContribNodes;
 	
-	if (data.mGeometry->GetArea() <= mTermMinArea) 
-		++ mStat.minAreaNodes;
+	//if (data.mGeometry->GetArea() <= mTermMinArea) 
+	//	++ mStat.minAreaNodes;
 
 #ifdef _DEBUG
@@ -1950,64 +1955,4 @@
 	}
 }
-
-bool BspTree::MergeViewCells(BspLeaf *front, BspLeaf *back) const
-{
-	BspViewCell *viewCell = 
-NULL;//todo		dynamic_cast<BspViewCell *>(ViewCell::Merge(*front->mViewCell, *back->mViewCell));
-	
-	if (!viewCell)
-		return false;
-
-	// change view cells of all leaves associated with the
-	// previous view cells
-
-	BspViewCell *fVc = front->mViewCell;
-	BspViewCell *bVc = back->mViewCell;
-
-	vector<BspLeaf *> fLeaves = fVc->mBspLeaves;
-	vector<BspLeaf *> bLeaves = bVc->mBspLeaves;
-
-	vector<BspLeaf *>::const_iterator it;
-	
-	for (it = fLeaves.begin(); it != fLeaves.end(); ++ it)
-	{
-		(*it)->SetViewCell(viewCell);
-		viewCell->mBspLeaves.push_back(*it);
-	}
-	for (it = bLeaves.begin(); it != bLeaves.end(); ++ it)
-	{
-		(*it)->SetViewCell(viewCell);
-		viewCell->mBspLeaves.push_back(*it);
-	}
-	
-	DEL_PTR(fVc);
-	DEL_PTR(bVc);
-
-	return true;
-}
-
-bool BspTree::ShouldMerge(BspLeaf *front, BspLeaf *back) const
-{
-	ViewCell *fvc = front->mViewCell;
-	ViewCell *bvc = back->mViewCell;
-
-	if ((fvc == mRootCell) || (bvc == mRootCell) || (fvc == bvc))
-		return false;
-
-	int fdiff = fvc->GetPvs().Diff(bvc->GetPvs());
-
-	if (fvc->GetPvs().GetSize() + fdiff < mMaxPvs)
-	{
-		if ((fvc->GetPvs().GetSize() < mMinPvs) ||	
-			(bvc->GetPvs().GetSize() < mMinPvs) ||
-			((fdiff < mMinPvsDif) && (bvc->GetPvs().Diff(fvc->GetPvs()) < mMinPvsDif)))
-		{
-			return true;
-		}
-	}
-	
-	return false;
-}
-
 
 BspTreeStatistics &BspTree::GetStat()
@@ -2457,6 +2402,11 @@
 					if (frontPoly->Valid())
 						front.mPolys.push_back(frontPoly);
+					else
+						DEL_PTR(frontPoly);
+
 					if (backPoly->Valid())
 						back.mPolys.push_back(backPoly);
+					else
+						DEL_PTR(backPoly);
 				}
 				
@@ -2510,6 +2460,10 @@
 
 					planePoly->Split(plane, *frontPoly, *backPoly);
+					
+					// don't need anymore
 					DEL_PTR(planePoly);
-
+					DEL_PTR(frontPoly);
+
+					// back polygon is belonging to geometry
 					if (backPoly->Valid())
 						planePoly = backPoly;
Index: trunk/VUT/GtpVisibilityPreprocessor/src/Preprocessor.cpp
===================================================================
--- trunk/VUT/GtpVisibilityPreprocessor/src/Preprocessor.cpp	(revision 440)
+++ trunk/VUT/GtpVisibilityPreprocessor/src/Preprocessor.cpp	(revision 441)
@@ -175,4 +175,6 @@
 		int bspConstructionSamples = 0;
 
+		mBspTree = new BspTree();
+
 		environment->GetIntValue("BspTree.Construction.samples", bspConstructionSamples);
 		mViewCellsManager = new BspViewCellsManager(mBspTree, bspConstructionSamples);
@@ -212,5 +214,5 @@
 
 	bool loadViewCells = false;
-	environment->GetBoolValue("ViewCell.Construction.loadFromFile", loadViewCells);
+	environment->GetBoolValue("ViewCells.loadFromFile", loadViewCells);
 
 	//-- load view cells from file if requested
Index: trunk/VUT/GtpVisibilityPreprocessor/src/Ray.cpp
===================================================================
--- trunk/VUT/GtpVisibilityPreprocessor/src/Ray.cpp	(revision 436)
+++ trunk/VUT/GtpVisibilityPreprocessor/src/Ray.cpp	(revision 441)
@@ -229,5 +229,6 @@
 		dir = vssRay.GetDir() / dist;
 
-	intersections.push_back(Intersection(dist, vssRay.mTerminationObject, 0));
+	if (vssRay.mTerminationObject)
+		intersections.push_back(Intersection(dist, vssRay.mTerminationObject, 0));
 
 	Precompute();
Index: trunk/VUT/GtpVisibilityPreprocessor/src/VssRay.h
===================================================================
--- trunk/VUT/GtpVisibilityPreprocessor/src/VssRay.h	(revision 438)
+++ trunk/VUT/GtpVisibilityPreprocessor/src/VssRay.h	(revision 441)
@@ -77,13 +77,13 @@
 
 	if (!ray.intersections.empty())
-	  {
+	{
 		mTermination = ray.Extrap(ray.intersections[0].mT);
 		mTerminationObject = ray.intersections[0].mObject;
-	  }
+	}
 	else
-	  {
+	{
 		mTermination = ray.Extrap(1e6);//TODO: should be Limits::Infinity
 		mTerminationObject = NULL;
-	  }
+	}
 
 	Precompute();
Index: trunk/VUT/GtpVisibilityPreprocessor/src/SamplingPreprocessor.h
===================================================================
--- trunk/VUT/GtpVisibilityPreprocessor/src/SamplingPreprocessor.h	(revision 440)
+++ trunk/VUT/GtpVisibilityPreprocessor/src/SamplingPreprocessor.h	(revision 441)
@@ -37,13 +37,16 @@
 
 	/** Casts a bundle of sample rays into the scene.
+		@param sampleContributions the number of sample contributions
+		@param contributingSamples the number of samples contributing
 	*/
-	int CastRays(const RayContainer &rays,
-				 int &sampleContribtion, 
-				 int &contributingSamples);
+	void
+	CastRays(const RayContainer &rays,
+			 int &sampleContributions, 
+			 int &contributingSamples);
 	
-	/** Casts a ray into the scene.
+	/** Casts a single ray into the scene.
+		@returns sample contributions
 	*/
-	int
-	CastRay(const Ray &ray);
+	int CastRay(Ray &ray);
 	
 	/** Verify if the exact visibility for this object was established.
@@ -55,23 +58,22 @@
 		along the visibility skeleton.
 	*/
-	int CastEdgeSamples(
-									Intersectable *object,
-									const Vector3 &point,
-									MeshInstance *mi,
-									const int samples
-									);
+	int 
+	CastEdgeSamples(
+					Intersectable *object,
+					const Vector3 &point,
+					MeshInstance *mi,
+					const int samples
+					);
 
 	/** Processes the view cells during a pass.
-		@param ray the current ray
-
+		@param newRays the newly cast rays
+		@param sampleContributions returns the accumulated contribution of the samples
 		@param contributingSamples returns the samples contributing to pvs
-		@param sampleContributions returns the accumulated 
-		contribution of the samples
-*/
+	*/
 	
-	void ProcessViewCells(const Ray &ray,
+	void ProcessViewCells(const RayContainer &newRays,
 						  const ObjectContainer &objects,
-						  int &contributingSamples,
-						  int &sampleContributions);
+						  int &sampleContributions,
+						  int &contributingSamples);
 
 	/** Adds objects samples to kd and bsp view cells.
Index: trunk/VUT/GtpVisibilityPreprocessor/src/SamplingPreprocessor.cpp
===================================================================
--- trunk/VUT/GtpVisibilityPreprocessor/src/SamplingPreprocessor.cpp	(revision 440)
+++ trunk/VUT/GtpVisibilityPreprocessor/src/SamplingPreprocessor.cpp	(revision 441)
@@ -27,6 +27,6 @@
 void
 SamplingPreprocessor::SetupRay(Ray &ray, 
-															 const Vector3 &point, 
-															 const Vector3 &direction,
+							   const Vector3 &point, 
+							   const Vector3 &direction,
 							   const int type,
 							   const Ray::Intersection &origin)
@@ -57,25 +57,35 @@
 
  
-int
+void
 SamplingPreprocessor::CastRays(const RayContainer &rays, 
 							   int &sampleContributions, 
 							   int &contributingSamples)
-	{ 	
+{ 	
 	// cast ray to KD tree to find intersection with other objects
 	RayContainer::const_iterator it, it_end = rays.end();
  
 	for (it = rays.begin(); it != it_end; ++it)
-        mKdTree->CastRay((*it));
-
-	sampleContributions = mViewCellsManager->CastRays(rays);
+        mKdTree->CastRay(*(*it));
+
+	// for KD tree, intersecting view cells are already known, so no 
+	// additional ray must be cast to them
+	const bool castRaysToViewCells = 
+		(mViewCellsManager->GetType() != ViewCellsManager::KD);
+
+	mViewCellsManager->ComputeSampleContributions(rays, 
+												  castRaysToViewCells,
+												  sampleContributions, 
+												  contributingSamples);
 }
 
 int
-SamplingPreprocessor::CastRay(const Ray &ray)
+SamplingPreprocessor::CastRay(Ray &ray)
 {
 	// cast ray to KD tree to find intersection with other objects
 	mKdTree->CastRay(ray);
 
-	return mViewCellsManager->CastRay(ray);
+	bool castRayToViewCells = mViewCellsManager->GetType() != ViewCellsManager::KD;
+
+	return mViewCellsManager->ComputeSampleContributions(ray, castRayToViewCells);
 }
 
@@ -134,9 +144,9 @@
 int
 SamplingPreprocessor::CastEdgeSamples(
-																			Intersectable *object,
-																			const Vector3 &point,
-																			MeshInstance *mi,
-																			const int samples
-																			)
+									  Intersectable *object,
+									  const Vector3 &point,
+									  MeshInstance *mi,
+									  const int samples
+									  )
 {
 	Ray ray;
@@ -156,5 +166,5 @@
 		float t = RandomValue(0.0f,1.0f);
 		Vector3 target = t*poly.mVertices[edge] + (1.0f-t)*poly.mVertices[(edge + 1)%
-																																		 poly.mVertices.size()];
+			poly.mVertices.size()];
 		SetupRay(ray, point, target - point, Ray::LOCAL_RAY, Ray::Intersection(0, object, 0));
 		if (!mesh->CastRay(ray, mi)) {
@@ -288,6 +298,5 @@
 				for (int k=0; k < mSamplesPerPass; k++) {
 					bool reverseSample = false;
-					
-
+				
 					if (nodeToSample) {
 						AxisAlignedBox3 box = mKdTree->GetBox(nodeToSample);
@@ -313,5 +322,5 @@
 					Ray::Intersection source = 
 						Ray::Intersection(0, reverseSample ? NULL : object, faceIndex);
-					
+			
 					// construct a ray
 					SetupRay(*ray, point, direction, Ray::LOCAL_RAY, source);
@@ -323,10 +332,4 @@
 						passSampleContributions += sampleContributions;
 					}*/
-		
-					//-------------------
-					ProcessViewCells(ray,
-									 objects,
-									 passContributingSamples,
-									 passSampleContributions);
 				}
 			} else {
@@ -340,8 +343,13 @@
 		}
 	
-		CastRays(passRays, passSampleContributions, passContributingSamples);
+		//-------------------
+		// cast rays for view cells construction
+		ProcessViewCells(passRays,
+						 objects,
+						 passSampleContributions,
+						 passContributingSamples);
+
 		CLEAR_CONTAINER(passRays);
-		passRays.clear();
-
+		
 		totalSamples += passSamples; 
 		
@@ -349,7 +357,7 @@
 		//      HoleSamplingPass();
     
-		mPass++;
+		mPass ++;
         
-			pvsSize += passSampleContributions;
+		pvsSize += passSampleContributions;
 		
 		float avgRayContrib = (passContributingSamples > 0) ? 
@@ -393,5 +401,5 @@
 	cout << "\nevaluating bsp view cells render time before merge ... ";
 		 
-	SimulationStatistics ss = mViewCellsManager->SimulateRendering();
+	const SimulationStatistics ss = mViewCellsManager->SimulateRendering();
 		 
 	cout << " finished" << endl;
@@ -400,21 +408,30 @@
 		 
 	mViewCellsManager->Visualize(objects, mSampleRays);	
-  
-  return true;
-}
-
-void SamplingPreprocessor::ProcessViewCells(const Ray &ray,
+    
+	return true;
+}
+
+void SamplingPreprocessor::ProcessViewCells(const RayContainer &newRays,
 											const ObjectContainer &objects,
-											int &contributingSamples,
-											int &sampleContributions)
-{
+											int &sampleContributions,
+											int &contributingSamples)
+{
+	// cast rays to view cells
+	CastRays(newRays, sampleContributions, contributingSamples);
+
 	// save rays for view cells construction
 	if (!mViewCellsManager->ViewCellsConstructed())
+	{
+		RayContainer::const_iterator it, it_end = newRays.end();
+
+		if ((int)mVssSampleRays.size() < mViewCellsManager->GetConstructionSamples())
 		{
-		if ((int)mSampleRays.size() < mViewCellsManager->GetConstructionSamples())
-			mVssSampleRays.push_back(new VssRay(ray));
+			for (it = newRays.begin(); it != it_end; ++ it)
+				mVssSampleRays.push_back(new VssRay(*(*it)));
+		}
 		else
 		{
 			mViewCellsManager->Construct(objects, mVssSampleRays);
+	
 			// construct view cells using the collected samples
 			cout << "building view cells from " << (int)mSampleRays.size() << " samples " << endl;
@@ -432,5 +449,8 @@
 			 ((int)mSampleRays.size() < mViewCellsManager->GetVisualizationSamples()))
 	{
-		mSampleRays.push_back(new Ray(ray));
-	}
-}
+		RayContainer::const_iterator it, it_end = newRays.end();
+
+		for (it = newRays.begin(); it != it_end; ++ it)
+				mSampleRays.push_back(new Ray(*(*it)));
+	}
+}
Index: trunk/VUT/GtpVisibilityPreprocessor/src/ViewCellsManager.cpp
===================================================================
--- trunk/VUT/GtpVisibilityPreprocessor/src/ViewCellsManager.cpp	(revision 440)
+++ trunk/VUT/GtpVisibilityPreprocessor/src/ViewCellsManager.cpp	(revision 441)
@@ -13,5 +13,4 @@
 
 
-
 ViewCellsManager::ViewCellsManager():
 mRenderSimulator(NULL),
@@ -20,5 +19,8 @@
 mVisualizationSamples(0)
 {
-    mUnbounded = GenerateViewCell();
+	// post processing stuff
+	environment->GetIntValue("ViewCells.PostProcessing.minPvsDif", mMinPvsDif);
+	environment->GetIntValue("ViewCells.PostProcessing.minPvs", mMinPvs);
+	environment->GetIntValue("ViewCells.PostProcessing.maxPvs", mMaxPvs);
 }
 
@@ -29,10 +31,12 @@
 mVisualizationSamples(0)
 {
-	mUnbounded = GenerateViewCell();
+	// post processing stuff
+	environment->GetIntValue("ViewCells.PostProcessing.minPvsDif", mMinPvsDif);
+	environment->GetIntValue("ViewCells.PostProcessing.minPvs", mMinPvs);
+	environment->GetIntValue("ViewCells.PostProcessing.maxPvs", mMaxPvs);
 }
 
 ViewCellsManager::~ViewCellsManager()
 {
-	DEL_PTR(mUnbounded);
 	DEL_PTR(mRenderSimulator);
 }
@@ -63,14 +67,20 @@
 }
 
-int ViewCellsManager::CastRays(const RayContainer &rays)
-{
-	int sampleContributions = 0;
+void ViewCellsManager::ComputeSampleContributions(const RayContainer &rays, 
+												  const bool castRays,
+												  int &sampleContributions,
+												  int &contributingSamples)
+{
+	// view cells not yet constructed
+	if (!ViewCellsConstructed())
+		return;
 
 	RayContainer::const_iterator it, it_end = rays.end();
 
     for (it = rays.begin(); it != it_end; ++ it)
-		sampleContributions += CastRay(*(*it));
-
-	return sampleContributions;
+	{
+		sampleContributions +=ComputeSampleContributions(*(*it), castRays);
+		contributingSamples += sampleContributions > 0;
+	}
 }
 
@@ -139,5 +149,5 @@
 }
 
-ViewCell *ViewCellsManager::Merge(ViewCell &front, ViewCell &back) const
+ViewCell *ViewCellsManager::MergeViewCells(ViewCell &front, ViewCell &back) const
 {
 	ViewCell *vc = GenerateViewCell();
@@ -158,4 +168,7 @@
 SimulationStatistics ViewCellsManager::SimulateRendering() const
 {
+	if (!ViewCellsConstructed())
+		return SimulationStatistics();
+
 	return mRenderSimulator->SimulateRendering();
 }
@@ -223,7 +236,10 @@
 								   AxisAlignedBox3 *sceneBbox)
 {
+	// if view cells were already constructed
 	if (ViewCellsConstructed())
 		return 0;
 
+	Debug << "Constructing bsp view cells" << endl;
+
 	int sampleContributions = 0;
 	
@@ -235,6 +251,9 @@
 		sampleRays.push_back(new Ray(*rays[i]));
 
-	mBspTree->Construct(objects, sampleRays);
-	
+	if (mViewCells.empty()) // no view cells loaded
+		mBspTree->Construct(objects, sampleRays);
+	else
+		mBspTree->Construct(mViewCells);
+
 	Debug << mBspTree->GetStatistics() << endl;
 	CLEAR_CONTAINER(sampleRays);
@@ -243,14 +262,59 @@
 }
 
-int BspViewCellsManager::CastRay(Ray &ray)
-{
-	mBspTree->CastRay(ray);
+int BspViewCellsManager::ComputeSampleContributions(Ray &ray, const bool castRay)
+{
+	// view cells not yet constructed
+	if (!ViewCellsConstructed())
+		return 0;
+
+	int contributingSamples = 0;
+
+	if (castRay)
+		mBspTree->CastRay(ray);
 	
 	//if (mBspTree->bspIntersections.empty()) return 0;
 
-	Intersectable *term = 
+	Intersectable *tObject = 
 		!ray.intersections.empty() ? ray.intersections[0].mObject : NULL;
 
-	return AddSampleContributions(ray, ray.sourceObject.mObject, term);
+	Intersectable *sObject = ray.sourceObject.mObject;
+
+	if (sObject || tObject)
+	{
+		// object can be seen from the view cell => add to view cell pvs
+		for (int j = 0; j < (int)ray.bspIntersections.size(); ++ j)
+		{ 	
+			BspLeaf *leaf = ray.bspIntersections[j].mLeaf;
+		
+			// if ray not in unbounded space
+			if (leaf->GetViewCell() != mBspTree->GetRootCell())
+			{
+				if (sObject)
+				{
+					contributingSamples += 
+						leaf->GetViewCell()->GetPvs().AddSample(sObject);
+				}
+
+				if (tObject)
+				{
+					contributingSamples += 
+						leaf->GetViewCell()->GetPvs().AddSample(tObject);
+				}
+			}
+		}
+	}
+
+	// rays passing through this viewcell
+	if (0)
+		for (int j = 1; j < ((int)ray.bspIntersections.size() - 1); ++ j) 
+		{
+			BspLeaf *leaf = ray.bspIntersections[j].mLeaf;
+
+			if (leaf->GetViewCell() != mBspTree->GetRootCell())
+				leaf->GetViewCell()->
+					AddPassingRay(ray, contributingSamples ? 1 : 0);
+		}
+
+	return contributingSamples;
 }
 
@@ -258,4 +322,11 @@
 									 const RayContainer &rays)
 {
+	if (!ViewCellsConstructed())
+	{
+		Debug << "view cells not constructed" << endl;
+		return 0;
+	}
+
+
 	//-- post processing of bsp view cells
     int vcSize = 0;
@@ -277,5 +348,5 @@
 			//exporter->ExportBspViewCellPartition(*mBspTree, 0);
 				
-			if (1)
+			if (0)
 			{
 				Material m;//= RandomMaterial();
@@ -323,7 +394,7 @@
 			BspLeaf *leaf = (*iit).mLeaf;
 
-			if (mBspTree->ShouldMerge(leaf, previousLeaf))
+			if (ShouldMerge(leaf, previousLeaf))
 			{			
-				mBspTree->MergeViewCells(leaf, previousLeaf);
+				MergeBspLeafViewCells(leaf, previousLeaf);
 
 				++ merged;
@@ -347,53 +418,11 @@
 }
 
-int BspViewCellsManager::AddSampleContributions(const Ray &ray,
-												Intersectable *sObject,
-												Intersectable *tObject)
-{
-	int contributingSamples = 0;
-	
-	// rays passing through this viewcell
-	if (0)
-		for (int j = 1; j < ((int)ray.bspIntersections.size() - 1); ++ j) 
-		{
-			BspLeaf *leaf = ray.bspIntersections[j].mLeaf;
-
-			if (leaf->GetViewCell() != mUnbounded)
-				leaf->GetViewCell()->
-					AddPassingRay(ray, contributingSamples ? 1 : 0);
-		}
-
-	if (!sObject && !tObject)
-		return 0;
-
-	// object can be seen from the view cell => add to view cell pvs
-	for (int j = 0; j < (int)ray.bspIntersections.size(); ++ j)
-	{ 	
-		BspLeaf *leaf = ray.bspIntersections[j].mLeaf;
-		
-		// if ray not in unbounded space
-		if (leaf->GetViewCell() != mUnbounded)
-		{
-			if (sObject)
-			{
-				contributingSamples += 
-					leaf->GetViewCell()->GetPvs().AddSample(sObject);
-			}
-
-			if (tObject)
-			{
-				contributingSamples += 
-					leaf->GetViewCell()->GetPvs().AddSample(tObject);
-			}
-		}
-	}
- 
-	return contributingSamples;
-}
-
 
 void BspViewCellsManager::Visualize(const ObjectContainer &objects,
 									const RayContainer &sampleRays)
 {
+	if (!ViewCellsConstructed())
+		return;
+
 	//-- recount pvs
 	BspViewCellsStatistics vcStats;
@@ -473,5 +502,5 @@
 		}
 
-		if (1)
+		if (0)
 			exporter->ExportGeometry(objects);
 
@@ -681,4 +710,66 @@
 }
 
+
+bool BspViewCellsManager::MergeBspLeafViewCells(BspLeaf *front, BspLeaf *back) const
+{
+	BspViewCell *viewCell = 
+		dynamic_cast<BspViewCell *>(MergeViewCells(*front->GetViewCell(), *back->GetViewCell()));
+	
+	if (!viewCell)
+		return false;
+
+	// change view cells of all leaves associated with the
+	// previous view cells
+
+	BspViewCell *fVc = front->GetViewCell();
+	BspViewCell *bVc = back->GetViewCell();
+
+	vector<BspLeaf *> fLeaves = fVc->mBspLeaves;
+	vector<BspLeaf *> bLeaves = bVc->mBspLeaves;
+
+	vector<BspLeaf *>::const_iterator it;
+	
+	for (it = fLeaves.begin(); it != fLeaves.end(); ++ it)
+	{
+		(*it)->SetViewCell(viewCell);
+		viewCell->mBspLeaves.push_back(*it);
+	}
+	for (it = bLeaves.begin(); it != bLeaves.end(); ++ it)
+	{
+		(*it)->SetViewCell(viewCell);
+		viewCell->mBspLeaves.push_back(*it);
+	}
+	
+	DEL_PTR(fVc);
+	DEL_PTR(bVc);
+
+	return true;
+}
+
+bool BspViewCellsManager::ShouldMerge(BspLeaf *front, BspLeaf *back) const
+{
+	ViewCell *fvc = front->GetViewCell();
+	ViewCell *bvc = back->GetViewCell();
+
+	if ((fvc == mBspTree->GetRootCell()) || (bvc == mBspTree->GetRootCell()) || (fvc == bvc))
+		return false;
+
+	int fdiff = fvc->GetPvs().Diff(bvc->GetPvs());
+
+	if (fvc->GetPvs().GetSize() + fdiff < mMaxPvs)
+	{
+		if ((fvc->GetPvs().GetSize() < mMinPvs) ||	
+			(bvc->GetPvs().GetSize() < mMinPvs) ||
+			((fdiff < mMinPvsDif) && (bvc->GetPvs().Diff(fvc->GetPvs()) < mMinPvsDif)))
+		{
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+
+
 /**********************************************************************/
 /*                   KdViewCellsManager implementation               */
@@ -698,6 +789,9 @@
 								  AxisAlignedBox3 *sceneBbox)
 {
+	// if view cells already constructed
 	if (ViewCellsConstructed())
 		return 0;
+
+	Debug << "Constructing bsp view cells" << endl;
 	
 	mKdTree->Construct();
@@ -720,4 +814,7 @@
 								   const RayContainer &sampleRays)
 {
+	if (!ViewCellsConstructed())
+		return;
+
 	const int pvsOut = min((int)objects.size(), 10);
 
@@ -801,19 +898,22 @@
 }
 
-int KdViewCellsManager::CastRay(const Ray &ray)
-{
-	if (ray.kdLeaves.empty()) 
+int KdViewCellsManager::ComputeSampleContributions(Ray &ray, const bool castRay)
+{
+	// view cells not yet constructed
+	if (!ViewCellsConstructed())
 		return 0;
 
-	Intersectable *terminator =
+	if (castRay)
+		mKdTree->CastRay(ray);
+
+	if (ray.kdLeaves.empty())
+		return 0;
+
+	Intersectable *tObject =
 		!ray.intersections.empty() ? ray.intersections[0].mObject : NULL;
 
-	return AddSampleContributions(ray, ray.sourceObject.mObject, terminator);
-}
-
-int KdViewCellsManager::AddSampleContributions(const Ray &ray,
-											   Intersectable *sObject,
-											   Intersectable *tObject)
-{
+	Intersectable *sObject =
+		ray.sourceObject.mObject;
+
 	int contributingSamples = 0;
 	
@@ -843,7 +943,8 @@
 			contributingSamples += tObject->mKdPvs.AddSample(node);
 	}
-		
+
 	return contributingSamples;
 }
+
 
 KdNode *KdViewCellsManager::GetNodeForPvs(KdLeaf *leaf)
@@ -874,4 +975,5 @@
 									 AxisAlignedBox3 *sceneBbox)
 {
+	// if view cells already constructed
 	if (ViewCellsConstructed())
 		return 0;
@@ -886,7 +988,14 @@
 }
 
-int VspKdViewCellsManager::CastRay(const Ray &rays)
-{
+int VspKdViewCellsManager::ComputeSampleContributions(Ray &ray, const bool castRay)
+{
+	// view cells not yet constructed
+	if (!ViewCellsConstructed())
+		return 0;
+
+	//if (castRay) // TODO
+
 	int sampleContributions = 0;
+
 /*
     for (int i = 0; i < (int)rays.size(); ++ i)
@@ -910,4 +1019,7 @@
 									   const RayContainer &rays)
 {
+	if (!ViewCellsConstructed())
+		return 0;
+
 	return 0;
 }
@@ -916,4 +1028,7 @@
 									  const RayContainer &sampleRays)
 {
+	if (!ViewCellsConstructed())
+		return;
+
 	if (1)
 	{
@@ -1006,47 +1121,2 @@
 	return VSP_KD;
 }
-
-int VspKdViewCellsManager::AddSampleContributions(const Ray &ray,
-												Intersectable *sObject,
-												Intersectable *tObject)
-{
-	int contributingSamples = 0;
-	/*
-	// rays passing through this viewcell
-	if (0)
-		for (int j = 1; j < ((int)ray.bspIntersections.size() - 1); ++ j) 
-		{
-			BspLeaf *leaf = ray.bspIntersections[j].mLeaf;
-
-			if (leaf->GetViewCell() != mUnbounded)
-				leaf->GetViewCell()->
-					AddPassingRay(ray, contributingSamples ? 1 : 0);
-		}
-
-	if (!sObject && !tObject)
-		return 0;
-	
-	// object can be seen from the view cell => add to view cell pvs
-	for (j=0; j < (int)ray.bspIntersections.size(); ++ j)
-	{ 	
-		BspLeaf *leaf = ray.bspIntersections[j].mLeaf;
-		
-		// if ray not in unbounded space
-		if (leaf->GetViewCell() != mUnbounded)
-		{
-			if (sObject)
-			{
-				contributingSamples += 
-					leaf->GetViewCell()->GetPvs().AddSample(sObject);
-			}
-
-			if (tObject)
-			{
-				contributingSamples += 
-					leaf->GetViewCell()->GetPvs().AddSample(tObject);
-			}
-		}
-	}
- */
-	return contributingSamples;
-}
