#pragma once

#include <wx/hashmap.h>

#include "BinTrees.h"
#include "BinTreesUtils.h"
#include "BinTreesBuilders.h"

#include "3dmath.h"

#include "smartptr.h"
#include "scene.h"
#include "geometrynode.h"
#include <vector>
#include <algorithm>

namespace bTree
{

	// Don't forget that ~FinalBVHNodeType must remove the node (if it is leaf) from tree's map
	template <class FinalBVHNodeType, class FinalBVHTreeType> class BVHNodeBase: public bTree::BinTreeNodeWithAABB<FinalBVHNodeType>
	{
	private:
		BVHNodeBase();									// No default constructor, I need at least pointer to tree
		BVHNodeBase(const BVHNodeBase &);				// No copy constructor (it is just not implemented)
		BVHNodeBase &operator = (const BVHNodeBase &);	// No assign operator, how would I assign a node from different tree?

	public:
		struct BVHNodeBaseCreateData
		{
			// This struct contains data to create node
			VRUT::smart_pointer<VRUT::GeometryNode> geom_node;
			Matrix world_matrix;
			VRUT::AABB geom_AABB;
		};

	protected:
		// Hide some attributes and methods
		using BinTreeNodeWithAABB<FinalBVHNodeType>::aabb;
		using BinTreeNodeWithAABB<FinalBVHNodeType>::parent;
		using BinTreeNodeWithAABB<FinalBVHNodeType>::lChild;
		using BinTreeNodeWithAABB<FinalBVHNodeType>::rChild;
		// Unhide them for insert/remove/etc. methods
		friend void bTree::BinTreeRemoveNode<FinalBVHNodeType>(FinalBVHNodeType *node, FinalBVHNodeType *& out_parent, FinalBVHNodeType *& out_sibling, FinalBVHNodeType *&in_out_root);
		friend void bTree::BinTreeReplaceNode<FinalBVHNodeType>(FinalBVHNodeType *what, FinalBVHNodeType *place);
		friend void bTree::BinTreeInsertNode<FinalBVHNodeType>(FinalBVHNodeType &what, FinalBVHNodeType &place, FinalBVHNodeType &aux, FinalBVHNodeType *&in_out_root);
		template <class TreeNodeType, class NodeGetter> friend void bTree::BinTreeOptimizeIteration(TreeNodeType *& root, int ratio);		// TODO Change this template so that only TreeNodeType=BVHNode could use it

		// Bounding sphere (approximate)
		VRUT::BSphere bSphere;

		VRUT::smart_pointer<VRUT::GeometryNode> geom_node;
		
		// Node world matrix, this matrix is updated when updateBVNode is called
		Matrix world_matrix;
		VRUT::AABB untransformedAABB;

		FinalBVHTreeType *const tree;			// Parent tree

		// Creates internal node, should be called from child classes only
		BVHNodeBase(FinalBVHTreeType *tree, FinalBVHNodeType *parent)
			: BinTreeNodeWithAABB<FinalBVHNodeType>(parent, nullptr, nullptr), tree(tree)		{}

		// Creates leaf node, should be called from child classes only
		BVHNodeBase(FinalBVHTreeType *tree, FinalBVHNodeType *parent, BVHNodeBaseCreateData &data)
			: BinTreeNodeWithAABB<FinalBVHNodeType>(parent, nullptr, nullptr), geom_node(data.geom_node), world_matrix(data.world_matrix), untransformedAABB(data.geom_AABB), tree(tree)
		{
			updateBVNode();
		}

		bool hasData() const
		{
			return geom_node.getPtr() != nullptr;
		}

		void updateBVNode()
		{
			if (this->IsLeaf())
			{
				this->aabb=untransformedAABB.Transform(&world_matrix);
			}
			else
			{
				this->aabb=this->lChild->aabb;
				this->aabb.Merge(this->rChild->aabb);
			}
			bSphere.Center = this->aabb.Center();
			bSphere.Radius = this->aabb.Radius();
			this->SetAABBUndirty();
		}

	public:
		const VRUT::BSphere &GetBSphere() const			{	return bSphere;				}

		const VRUT::GeometryNode *GetGeomNode() const	{	return geom_node.getPtr();	}
		VRUT::smart_pointer<VRUT::GeometryNode> GetGeomNodeSmtPtr() const		{	return geom_node;	}
		
		const Matrix &GetWorldMatrix() const			{	return world_matrix;		}
		void SetWorldMatrix(const Matrix &mat)			{	world_matrix = mat;			}
		void SetUntransformedAABB(const VRUT::AABB &aabb)			{	untransformedAABB = aabb; this->DirtyAABBAndWorldMatrixThisAndUptree();			}

		std::vector<unsigned char>		PerCameraLastCullingPlaneIndex;

		FinalBVHTreeType *GetTree()					{	return tree;	}
		const FinalBVHTreeType *GetTree() const		{	return tree;	}
	};

	// This template assumes FinalBVHNodeType is a child class of BVHNodeBase
	// Most functions are protected and with *_internal suffix, which means they should be called from child classes.
	// This is necessary if child classes wants to add some functionality like mutexes etc.
	// FinalBVHNodeType should have two constructors: FinalBVHNodeType(BVHTree *_tree, FinalBVHNodeType *parent) which
	// creates an internal node, and FinalBVHNodeType(BVHTree *_tree, FinalBVHNodeType *parent, BVHNodeBaseCreateData &data)
	// which creates a leaf node.
	template <class FinalBVHNodeType, class FinalBVHTreeType, class SceneType = VRUT::smart_pointer_v2<VRUT::Scene>>
	class BVHTreeBase: public bTree::BinTree<FinalBVHNodeType>
	{
	private:
		bool runningDeleteTree;			// If true, all items will be removed from the tree, so there is no need to remove it one by one

		void startDeletingTree()
		{
			runningDeleteTree = true;
		}
		void finishDeletingTree()
		{
			geomNodeIdToBVHNodeMap.clear();
			runningDeleteTree = false;
		}

	public:
#ifdef __WXMSW__
		WX_DECLARE_HASH_MAP(VRUT::NODE_ID, FinalBVHNodeType *, wxIntegerHash, wxIntegerEqual, GeomNodeIDToBVHNodeMap);
#else
		typedef std::map<VRUT::NODE_ID, FinalBVHNodeType *> GeomNodeIDToBVHNodeMap;
#endif

		static bool noDirtyStopper(FinalBVHNodeType *node)		{		return !node->IsAABBDirty();		}

	protected:
		BVHTreeBase(SceneType &scene, FinalBVHNodeType *_root): BinTree<FinalBVHNodeType>(_root), runningDeleteTree(false), scene(scene)
		{
			assert(scene);			// Scene must be set
		}

		// Hide some attributes and methods
		using BinTree<FinalBVHNodeType>::root;
		using BinTree<FinalBVHNodeType>::SafeDeleteRoot;

		GeomNodeIDToBVHNodeMap geomNodeIdToBVHNodeMap;

		SceneType &scene;

		void removeNodeFromMapByID_internal(VRUT::NODE_ID node_id)
		{
			if (!runningDeleteTree)		geomNodeIdToBVHNodeMap.erase(node_id);
		}
		void removeNodeFromMapNoID_internal(FinalBVHNodeType *node)
		{
			if (!runningDeleteTree)
			{
				// Search for a node that is in the map, but we don't know its ID (it has changed, etc.)
				for (auto iter = geomNodeIdToBVHNodeMap.begin(); iter != geomNodeIdToBVHNodeMap.end(); ++iter)
				{
					if (iter->second == node)
					{
						geomNodeIdToBVHNodeMap.erase(iter);
						break;
					}
				}
			}
		}
		void removeNodeFromMap_internal(FinalBVHNodeType *node)
		{
			if (!runningDeleteTree)
			{
				assert(node);
				if (node->GetGeomNode())
				{
					if (node->GetGeomNode()->GetID() != VRUT::NODE_ID_NONE)
						removeNodeFromMapByID_internal(node->GetGeomNode()->GetID());
					else
						removeNodeFromMapNoID_internal(node);
				}
			}
		}
		void insertNodeIntoMap_internal(VRUT::NODE_ID node_id, FinalBVHNodeType *node)
		{
			geomNodeIdToBVHNodeMap.insert(typename GeomNodeIDToBVHNodeMap::value_type(node_id,  node));
		}

		void deleteTree_internal()
		{
			startDeletingTree();
			this->SafeDeleteRoot();		// If there was no startDeletingTree, then every node would remove itself from map, which is unnecessary since map is cleared
			finishDeletingTree();
		}

		FinalBVHNodeType *createLeftInternal_internal(FinalBVHNodeType *parent)
		{
			parent->SafeDeleteLChild();
			parent->lChild = new FinalBVHNodeType((FinalBVHTreeType *)this, parent);			// This typecast is safe since the caller is of type FinalBVHTreeType
			return parent->lChild;
		}
		FinalBVHNodeType *createRightInternal_internal(FinalBVHNodeType *parent)
		{
			parent->SafeDeleteRChild();
			parent->rChild = new FinalBVHNodeType((FinalBVHTreeType *)this, parent);			// This typecast is safe since the caller is of type FinalBVHTreeType
			return parent->rChild;
		}
		void createRootInternal_internal()
		{
			deleteTree_internal();
			this->root = new FinalBVHNodeType((FinalBVHTreeType *)this, nullptr);				// This typecast is safe since the caller is of type FinalBVHTreeType
		}
		FinalBVHNodeType *createLeftLeaf_internal(FinalBVHNodeType *parent, typename FinalBVHNodeType::BVHNodeBaseCreateData &data)
		{
			assert(data.geom_node && (data.geom_node->GetID() != VRUT::NODE_ID_NONE));

			parent->SafeDeleteLChild();
			FinalBVHNodeType *node = new FinalBVHNodeType((FinalBVHTreeType *)this, parent, data);		// This typecast is safe since the caller is of type FinalBVHTreeType

			parent->lChild = node;
			insertNodeIntoMap_internal(data.geom_node->GetID(), node);
			return node;
		}
		FinalBVHNodeType *createRightLeaf_internal(FinalBVHNodeType *parent, typename FinalBVHNodeType::BVHNodeBaseCreateData &data)
		{
			assert(data.geom_node && (data.geom_node->GetID() != VRUT::NODE_ID_NONE));

			parent->SafeDeleteRChild();
			FinalBVHNodeType *node = new FinalBVHNodeType((FinalBVHTreeType *)this, parent, data);		// This typecast is safe since the caller is of type FinalBVHTreeType

			parent->rChild = node;
			insertNodeIntoMap_internal(data.geom_node->GetID(),  node);
			return node;
		}
		void createRootLeaf_internal(typename FinalBVHNodeType::BVHNodeBaseCreateData &data)
		{
			assert(data.geom_node && (data.geom_node->GetID() != VRUT::NODE_ID_NONE));

			deleteTree_internal();
			this->root = new FinalBVHNodeType((FinalBVHTreeType *)this, nullptr, data);		// This typecast is safe since the caller is of type FinalBVHTreeType

			insertNodeIntoMap_internal(data.geom_node->GetID(), this->root);
		}

		FinalBVHNodeType *createNode_internal(typename FinalBVHNodeType::BVHNodeBaseCreateData &data)
		{
			assert(data.geom_node && (data.geom_node->GetID() != VRUT::NODE_ID_NONE));
			FinalBVHNodeType *new_node = new FinalBVHNodeType((FinalBVHTreeType *)this, nullptr, data);		// This typecast is safe since the caller is of type FinalBVHTreeType
			return new_node;
		}

		void insertNode_internal(FinalBVHNodeType *node)
		{
			FinalBVHNodeType *aux_node = new FinalBVHNodeType((FinalBVHTreeType *)this, nullptr);			// This typecast is safe since the caller is of type FinalBVHTreeType

			bTree::BinTreeInsertNodeOptim(node, aux_node, this->root);
			insertNodeIntoMap_internal(node->GetGeomNode()->GetID(), node);
		}

		void removeNodeUnsafe_internal(FinalBVHNodeType *node, FinalBVHNodeType *& out_sibling)
		{
			if (!node)		return;

			// Assert we own the node
			assert(node->tree == (FinalBVHTreeType*)this);			// This typecast is safe since the caller is of type FinalBVHTreeType

			FinalBVHNodeType *parent;
			bTree::BinTreeRemoveNode(node, parent, out_sibling, this->root);
			SAFE_DELETE(parent);
		}
		void removeNodeSafe_internal(FinalBVHNodeType *node, FinalBVHNodeType *& out_sibling)
		{
			removeNodeUnsafe_internal(node, out_sibling);
			SAFE_DELETE(node);			// Node's destructor should remove the node form map
		}

		FinalBVHNodeType *getNodeByGeometryNodeID_internal(VRUT::NODE_ID geom_node_id)
		{
			auto iter = geomNodeIdToBVHNodeMap.find(geom_node_id);
			return (iter != geomNodeIdToBVHNodeMap.end()) ? (iter->second) : nullptr;
		}
		const FinalBVHNodeType *getNodeByGeometryNodeID_internal(VRUT::NODE_ID geom_node_id) const
		{
			auto iter = geomNodeIdToBVHNodeMap.find(geom_node_id);
			return (iter != geomNodeIdToBVHNodeMap.end()) ? (iter->second) : nullptr;
		}

		void updateTree_internal(FinalBVHNodeType *node, int expected_depth_of_tree)
		{
			assert(scene);		// This should have been checked in constructor

			if (!node || !node->IsAABBDirty())		return;

			std::vector<FinalBVHNodeType *> dirty_nodes;

			// Get all dirty nodes
			typename bTree::BinTreeFoldBasicWrappers<FinalBVHNodeType>::template GetAllLeafNodes<std::vector<FinalBVHNodeType *> >::Wrapper get_leaves(dirty_nodes);
			bTree::BinTreeStopperWrapper<FinalBVHNodeType, BVHTreeBase<FinalBVHNodeType, FinalBVHTreeType, SceneType>::noDirtyStopper> fnc;
			bTree::BinTreeMapWithStopperVector(node, get_leaves, fnc, expected_depth_of_tree);
			if (dirty_nodes.size() > 0)
			{
				// Transform BVH nodes array into VRUT::GeometryNode array
				std::vector<VRUT::smart_pointer<VRUT::GeometryNode> > geom_nodes_of_dirty_nodes(dirty_nodes.size());
				// Note: if lambda function does not work, create static method e.g.
				// "static VRUT::smart_pointer<VRUT::GeometryNode> GetGeomNodeSmtPtrStatic(FinalBVHNodeType *node)		{	return node->geom_node;		}" and use it
				std::transform(dirty_nodes.begin(), dirty_nodes.end(), geom_nodes_of_dirty_nodes.begin(), [](FinalBVHNodeType *node) {return node->GetGeomNodeSmtPtr();});

				// Get matrices of nodes
				std::vector<Matrix> geom_node_matrices;
				scene->GetWorldTransMatrices(geom_nodes_of_dirty_nodes, geom_node_matrices);

				// Update matrices
				for (unsigned int i = 0; i < dirty_nodes.size(); i++)
				{
					dirty_nodes[i]->SetWorldMatrix(geom_node_matrices[i]);
				}

				// Update tree
				std::for_each(dirty_nodes.begin(), dirty_nodes.end(), [](FinalBVHNodeType *node) {node->UpdateBVUptreeOfDirty();});
				//for (auto iter = dirty_nodes.begin(); iter != dirty_nodes.end(); ++iter)
				//{
				//	(*iter)->UpdateBVUptreeOfDirty();
				//}
			}
		}

		template <class NodeGetter> void optimize_internal(int ratio, int maxIterations, int threshold, int randomThreshold)
		{
			bTree::BinTreeOptimize<FinalBVHNodeType, NodeGetter>(this->root, ratio, maxIterations, threshold, randomThreshold);
		}

	public:
		// TODO Should there be const version of this method? If it should, should is return Scene * or const Scene *?
		SceneType &GetScene()		{	return scene;	}
	};

	template <class FinalBVHNodeType> class BVHTreeNoLock: public BVHTreeBase<FinalBVHNodeType, BVHTreeNoLock<FinalBVHNodeType>, VRUT::smart_pointer_v2<VRUT::Scene> >
	{
	private:
		BVHTreeNoLock(const BVHTreeNoLock &);				// No copy constructor
		BVHTreeNoLock &operator =(const BVHTreeNoLock &);	// No assign operator

	protected:
		void removeNodeFromMap(FinalBVHNodeType *node)		{	this->removeNodeFromMap_internal(node);		}

		FinalBVHNodeType *createLeftInternal(FinalBVHNodeType *parent)		{	return this->createLeftInternal_internal(parent);			}
		FinalBVHNodeType *createRightInternal(FinalBVHNodeType *parent)		{	return this->createRightInternal_internal(parent);		}
		FinalBVHNodeType *createLeftLeaf(FinalBVHNodeType *parent, typename FinalBVHNodeType::BVHNodeBaseCreateData &data)				{	return this->createLeftLeaf_internal(parent, data);		}
		FinalBVHNodeType *createRightLeaf(FinalBVHNodeType *parent, typename FinalBVHNodeType::BVHNodeBaseCreateData &data)				{	return this->createRightLeaf_internal(parent, data);		}

		// Node needs access to create* methods
#ifdef __WXMSW__
		friend FinalBVHNodeType;
#else
		// g++ of version < 4.7 does not implement "friend FinalBVHNodeType" and "friend class FinalBVHNodeType" is not allowed
		// (because of C++ standard), so I must use the following hack. Note that g++ 4.7 and newer should allow "friend FinalBVHNodeType".
		template <class T> struct MyFriendType
		{
			typedef T Type;
		};
		friend class MyFriendType<FinalBVHNodeType>::Type;
#endif

	public:
		BVHTreeNoLock(VRUT::smart_pointer_v2<VRUT::Scene> &scene): BVHTreeBase<FinalBVHNodeType, BVHTreeNoLock<FinalBVHNodeType> >(scene, nullptr) {}
		~BVHTreeNoLock()		{	this->deleteTree_internal();		}

		FinalBVHNodeType *GetNodeByGeometryNodeID(VRUT::NODE_ID geom_node_id)				{	return this->getNodeByGeometryNodeID_internal(geom_node_id);		}
		const FinalBVHNodeType *GetNodeByGeometryNodeID(VRUT::NODE_ID geom_node_id) const	{	return this->getNodeByGeometryNodeID_internal(geom_node_id);		}

		FinalBVHNodeType *CreateRootInternal()												{	this->createRootInternal_internal();		return this->root;	}
		FinalBVHNodeType *CreateRootLeaf(typename FinalBVHNodeType::BVHNodeBaseCreateData &data)		{	this->createRootLeaf_internal(data);		return this->root;	}

		void DeleteTree()			{	this->deleteTree_internal();		}

		/// Inserts new node into tree and into map
		FinalBVHNodeType *InsertNode(typename FinalBVHNodeType::BVHNodeBaseCreateData &data)
		{
			FinalBVHNodeType *new_node = this->createNode_internal(data);
			this->insertNode_internal(new_node);
			if (new_node->GetParent())			new_node->GetParent()->UpdateBVUptree();
			return new_node;
		}

		/// Removes the node from the tree and from map
		void RemoveNode(FinalBVHNodeType *node)
		{
			if (!node)			return;

			FinalBVHNodeType *sibling = nullptr;
			this->removeNodeSafe_internal(node, sibling);
			if (sibling)		sibling->UpdateBVUptree();
		}

		/// Removes the node with a scene node of given ID from the tree and from map.
		/// Unlike RemoveNode(FinalBVHNodeType *node), this method removes the node from GeomNodeIDToBVHNodeMap
		/// before deleting the node, saving lenghty search done in node's destructor
		void RemoveNode(VRUT::NODE_ID geom_node_id)
		{
			FinalBVHNodeType *node = this->GetNodeByGeometryNodeID(geom_node_id);
			if (!node)			return;

			FinalBVHNodeType *sibling = nullptr;
			node->geom_node = nullptr;
			this->removeNodeFromMapByID_internal(geom_node_id);
			this->removeNodeSafe_internal(node, sibling);
			if (sibling)		sibling->UpdateBVUptree();
		}

		/// Optimizes the tree
		template <class NodeGetter> void Optimize(int ratio)
		{
			this->optimize_internal(ratio);
		}

		void UpdateTree()
		{
			this->updateTree_internal(this->GetRoot(), 50);
		}
	};

	// BVHNodeBaseBuilder - builds BVH, passes BVHNodeBaseCreateData to nodes
	// There are two variants - ont that builds BVH from all geometries in scene
	// and another that builds BVH from given geometries in scene.
	template <class FinalBVHNodeType, class FinalBVHTreeType, class SceneType = VRUT::smart_pointer_v2<VRUT::Scene>> class BVHNodeBaseBuilder
	{
	public:
		// Since the object itself is quite large, we use pointers to it. To avoid memory leaks, we use smart pointers.
		class Item: public VRUT::CountableThreadUnsafe
		{
		public:
			VRUT::smart_pointer<VRUT::GeometryNode>		GeomNode;
			Matrix			GeomNodeWorldMatrix;
			VRUT::AABB		GeomNodeAABB;
			VRUT::AABB		GeomNodeTransformedAABB;
			Vector3			GeomNodeTransformedAABBCenter;
		};
		typedef VRUT::smart_pointer_v2<Item>	ItemType;
		typedef std::vector<ItemType>			ItemArrayType;

	protected:
		FinalBVHTreeType &out_tree;
		SceneType scene;
		std::vector<VRUT::smart_pointer<VRUT::GeometryNode> > *input_geometries;		

		void convertData(ItemArrayType &in_items, typename FinalBVHNodeType::BVHNodeBaseCreateData &out_data)
		{
			assert(in_items.size() == 1);
			out_data.geom_node = in_items[0]->GeomNode;
			out_data.world_matrix = in_items[0]->GeomNodeWorldMatrix;
			out_data.geom_AABB = in_items[0]->GeomNodeAABB;
		}

	public:

		// Creates builder which builds BVH from all objects in scene
		BVHNodeBaseBuilder(FinalBVHTreeType &_out_tree, SceneType &scene)
			: out_tree(_out_tree), scene(scene), input_geometries(nullptr) {}

		// Creates builder which builds BVH from given objects in scene
		BVHNodeBaseBuilder(FinalBVHTreeType &_out_tree, SceneType &scene, std::vector<VRUT::smart_pointer<VRUT::GeometryNode> > &geometries)
			: out_tree(_out_tree), scene(scene), input_geometries(&geometries) {}

		FinalBVHNodeType *CreateRootInternal(ItemArrayType &items)
		{
			return out_tree.CreateRootInternal();
		}
		FinalBVHNodeType *CreateLeftInternal(FinalBVHNodeType *parent, ItemArrayType &items)
		{
			return parent->CreateLeftInternal();
		}
		FinalBVHNodeType *CreateRightInternal(FinalBVHNodeType *parent, ItemArrayType &items)
		{
			return parent->CreateRightInternal();
		}
		FinalBVHNodeType *CreateRootLeaf(ItemArrayType &items)
		{
			typename FinalBVHNodeType::BVHNodeBaseCreateData data;
			convertData(items, data);
			return out_tree.CreateRootLeaf(data);
		}
		FinalBVHNodeType *CreateLeftLeaf(FinalBVHNodeType *parent, ItemArrayType &items)
		{
			typename FinalBVHNodeType::BVHNodeBaseCreateData data;
			convertData(items, data);
			return parent->CreateLeftLeaf(data);
		}
		FinalBVHNodeType *CreateRightLeaf(FinalBVHNodeType *parent, ItemArrayType &items)
		{
			typename FinalBVHNodeType::BVHNodeBaseCreateData data;
			convertData(items, data);
			return parent->CreateRightLeaf(data);
		}

		void GetItems(ItemArrayType &out_items)
		{
			assert(scene);

			out_items.clear();

			std::vector<VRUT::smart_pointer<VRUT::GeometryNode> > all_scene_geom_nodes;
			std::vector<VRUT::smart_pointer<VRUT::GeometryNode> > *geom_nodes_to_build_from = nullptr;
			if (input_geometries)
			{
				geom_nodes_to_build_from = input_geometries;
			}
			else
			{
				scene->GetNodes(all_scene_geom_nodes, VRUT::SceneNode::GEOMETRY);
				geom_nodes_to_build_from = &all_scene_geom_nodes;
			}

			std::vector<Matrix> geom_node_matrices;
			scene->GetWorldTransMatrices(*geom_nodes_to_build_from, geom_node_matrices);

			std::vector<VRUT::smart_pointer<VRUT::Geometry> > geoms;
			scene->GetGeometries(*geom_nodes_to_build_from, geoms);

			for (size_t i = 0; i < geom_nodes_to_build_from->size(); ++i)
			{
				if (geom_nodes_to_build_from->at(i) && geoms[i])
				{
					ItemType item = new Item;
					item->GeomNode = geom_nodes_to_build_from->at(i);
					item->GeomNodeWorldMatrix = geom_node_matrices[i];

					item->GeomNodeAABB = geoms[i]->GetAABB();
					item->GeomNodeTransformedAABB = item->GeomNodeAABB.Transform(&item->GeomNodeWorldMatrix);
					item->GeomNodeTransformedAABBCenter = item->GeomNodeTransformedAABB.Center();
					out_items.push_back(item);
				}
			}
		}		

		VRUT::AABB GetAABBOfItems(const ItemArrayType &items)
		{
			VRUT::AABB out_aabb;
			for (auto iter = items.begin(); iter != items.end(); ++iter)
				out_aabb.Merge((*iter)->GeomNodeTransformedAABB);
			return out_aabb;
		}

		Vector3 GetItemCenter(const ItemType& item)
		{
			return item->GeomNodeTransformedAABBCenter;
		}

		void MergeAABBWithItemAABB(VRUT::AABB &in_out_aabb, const ItemType& item)
		{
			in_out_aabb.Merge(item->GeomNodeTransformedAABB);
		}

		static void Build(FinalBVHTreeType &tree)
		{
			FinalBVHNodeType *nothing;
			BVHNodeBaseBuilder<FinalBVHNodeType, FinalBVHTreeType, SceneType> builder(tree, tree.GetScene());
			bTree::CommonTreeBuild(nothing, builder);				// The tree itself assigns the root
		}
		static void Build(FinalBVHTreeType &tree, std::vector<VRUT::smart_pointer<VRUT::GeometryNode> > &geometries)
		{
			FinalBVHNodeType *nothing;
			BVHNodeBaseBuilder<FinalBVHNodeType, FinalBVHTreeType, SceneType> builder(tree, tree.GetScene(), geometries);
			bTree::CommonTreeBuild(nothing, builder);	// The tree itself assigns the root
		}
	};
}
