Index: CQuadtree.h
===================================================================
--- CQuadtree.h	(revision 0)
+++ CQuadtree.h	(revision 0)
@@ -0,0 +1,407 @@
+/* Copyright (C) 2013 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 0 A.D. is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_QUADTREE
+#define INCLUDED_QUADTREE
+
+#define MAX_OBJECTS 4
+
+/*!
+A templated, adaptive quadtree class
+by Don Doumakes
+
+When initialized, the tree consists of a single node which contains no game
+objects.  As game objects are added to a node, child nodes are added to
+represent smaller and smaller subdivisions of the physical space, and the
+game objects are distributed downward to the leaf nodes.  Thus the number
+of game objects in a particular node is kept below an arbitrary maximum
+(which is what makes this tree "adaptive").  As game objects are moved to
+new locations or eliminated, the process is reversed, reducing the number
+of nodes in the tree.
+
+The tree class is mostly unaware of implementation details of the game object
+class.  However, it is useful for both classes to know:
+- the x, y and z coordinates of the game object
+- the tree node to which the game object is attached  
+Therefore, the minimal game object class T must contain the following
+declarations:
+\verbatim
+class T
+{
+private:
+	int m_X;
+	int m_Y;
+	int m_Z;
+	CQuadtree<T> * m_MyNode;
+public:
+	friend class CQuadtree<T>
+};
+\endverbatim
+Fortunately, omitting these declarations is a compile-time error.
+
+To calculate the range between a given game object and its neighbors,
+- Implement a rangefinding function in the game object class.
+- Traverse the tree and call your rangefinding function from each node.
+The siblings of a given node will be physically nearest, so if the
+traversal begins at the parent node of "this node," then only the nearest
+game objects will be checked.
+*/
+
+template <class T> class CQuadtree
+{
+private:
+	/// Game objects contained by this node, along with their coordinates
+	T * m_GameObject[ MAX_OBJECTS ];
+	/// Parent node
+	CQuadtree<T> * m_Parent;
+	/// Child nodes
+    CQuadtree<T> * m_Child[2][2];
+	/// Length of map edges
+    int m_N;
+	/// Bounds of this node
+    int m_MinX, m_MaxX, m_MinY, m_MaxY;
+
+    /// Typedef for a pointer to a void member function of T
+    typedef void ( T::* p_T_member )();
+    /// Typedef for a pointer to a void member function of CQuadtree
+    typedef void ( CQuadtree<T>::* p_CQuadtree_member )();
+    /// Typedef for a pointer to an int member function of CQuadtree
+    typedef int ( CQuadtree<T>::* p_CQuadtree_memberB )();
+
+	/*!
+		Constructor for non-root nodes.
+
+		\param parent Parent node of this node
+		\param x0 Minimum x value
+		\param x1 Maximum x value
+		\param y0 Minimum y value
+		\param y1 Maximum y value
+	*/
+	CQuadtree( CQuadtree<T> * parent, int x0, int x1, int y0, int y1 )
+	{
+		m_N = parent->m_N;
+		m_Parent = parent;
+		m_MinX = x0;
+		m_MaxX = x1;
+		m_MinY = y0;
+		m_MaxY = y1;
+		memset( m_Child, 0, sizeof( CQuadtree * ) * 4 );
+		memset( m_GameObject, 0, sizeof( T * ) * MAX_OBJECTS );
+	};
+
+public:
+
+	/*!
+		Constructor for the root node.
+        \param size Length of each edge of the game world cube.  Must be a power of two.
+	*/
+	CQuadtree( int size ) : m_N( size ), 
+                            m_Parent( 0 ), 
+                            m_MinX( 0 ), 
+                            m_MaxX( size - 1 ), 
+                            m_MinY( 0 ), 
+                            m_MaxY( size - 1 )
+	{
+		if ( ( size && !( size & ( size - 1 ) ) ) == 0 )
+            throw 0; 
+
+		memset( m_Child, 0, sizeof( CQuadtree * ) * 4 );
+		memset( m_GameObject, 0, sizeof( T * ) * MAX_OBJECTS );
+
+	};
+
+	/*!
+		Getter for the parent node
+	*/
+	CQuadtree<T> * Parent()
+	{
+		return m_Parent;
+	};
+
+    /*!
+        Depth-first traversal of the tree
+
+		\param doEet Pointer to a member function of the game object class.
+    */
+    void traverse( p_T_member doEet )
+	{
+		int i, j;
+		for ( i = 0; i < 2; ++i )
+			for ( j = 0; j < 2; ++j )
+				if ( m_Child[i][j] )
+					// Traverse this child tree.
+					m_Child[i][j]->traverse( doEet );
+	
+		int k = 0;
+    	while ( k < MAX_OBJECTS && m_GameObject[k] )
+		{
+			// Call a function in the game object.
+			( m_GameObject[k]->*doEet )();
+			k++;
+		}
+	};
+
+    /*!
+        Depth-first traversal of the tree
+
+		\param doEet Pointer to a member function of this class.
+    */
+	void traverse( p_CQuadtree_member doEet )
+	{
+		int i, j;
+		for ( i = 0; i < 2; ++i )
+			for ( j = 0; j < 2; ++j )
+				if ( m_Child[i][j] )
+					// Traverse this child tree.
+					m_Child[i][j]->traverse( doEet );
+
+		// Call a function in the CQuadtree class.
+		( this->*doEet )();
+	};
+
+    /*!
+        Breadth-first traversal of the tree
+
+		\param doEet Pointer to a member function of this class.
+    */
+	void traverse( p_CQuadtree_memberB doEet )
+	{
+		// Call a function in the CQuadtree class.
+		( this->*doEet )();
+
+		int i, j;
+		for ( i = 0; i < 2; ++i )
+			for ( j = 0; j < 2; ++j )
+				if ( m_Child[i][j] )
+					// Traverse this child tree.
+					m_Child[i][j]->traverse( doEet );
+	};
+
+	/*!
+		Add a game object to this tree.
+
+		\param obj Game object to add.
+		\return Pointer to the node that contains the game object.
+	*/
+	CQuadtree<T> * addObject( T * obj )
+	{
+        // Bad input?
+        if ( !obj )
+            throw "Attempt to add null object to tree";
+        if ( obj->m_X < 0 || obj->m_X > m_N - 1 ||
+             obj->m_Y < 0 || obj->m_Y > m_N - 1 )
+            throw "Object has invalid position.";
+
+		// Is this the right subtree?
+		if ( obj->m_X < m_MinX || obj->m_X > m_MaxX ||
+		     obj->m_Y < m_MinY || obj->m_Y > m_MaxY )
+		{
+			// Nope.
+			return m_Parent->addObject( obj );
+		}
+
+		int j = 0;
+		int k = 0;
+		// Does this node have children?
+		if ( m_Child[0][0] )
+		{
+			// Yes, so choose a child node
+			// that includes (x,y).
+        	if ( obj->m_X < m_MinX + ( m_MaxX - m_MinX ) / 2 + 1 )
+				j = 0;
+			else
+				j = 1;
+        	if ( obj->m_Y < m_MinY + ( m_MaxY - m_MinY ) / 2 + 1 )
+				k = 0;
+			else
+				k = 1;
+
+			// Add the object to that node instead.
+            return m_Child[j][k]->addObject( obj );
+		}
+
+		int i = 0;
+    	while ( i < MAX_OBJECTS && m_GameObject[i] )
+			i++;
+    	if ( i < MAX_OBJECTS )
+		{
+			m_GameObject[i] = obj;
+			obj->m_MyNode = this;
+			return this;
+		}
+        else if ( m_MinX == m_MaxX )
+        {
+			// If the size of this node is 1, stop
+            // adding nodes.
+            return 0;
+        }
+		else
+		{
+			// Create new leaf nodes.
+
+			/*
+				Upper left
+				x ranges from m_MinX to halfway between m_MinX and m_MaxX.
+				y ranges from m_MinY to halfway between m_MinY and m_MaxY.
+			*/
+			m_Child[0][0] = new CQuadtree( this, 
+									m_MinX, 
+									m_MinX + ( m_MaxX - m_MinX ) / 2,
+									m_MinY,
+									m_MinY + ( m_MaxY - m_MinY ) / 2 );
+			/*
+				Upper right
+				x ranges from halfway between m_MinX and m_MaxX to m_MaxX.
+				y ranges from m_MinY to halfway between m_MinY and m_MaxY.
+			*/
+			m_Child[1][0] = new CQuadtree( this, 
+									m_MinX + ( m_MaxX - m_MinX ) / 2 + 1,
+									m_MaxX,
+									m_MinY,
+									m_MinY + ( m_MaxY - m_MinY ) / 2 );
+			/*
+				Lower left
+				x ranges from m_MinX to halfway between m_MinX and m_MaxX.
+				y ranges from halfway between m_MinY and m_MaxY to m_MaxY.
+			*/
+			m_Child[0][1] = new CQuadtree( this, 
+									m_MinX, 
+									m_MinX + ( m_MaxX - m_MinX ) / 2,
+									m_MinY + ( m_MaxY - m_MinY ) / 2 + 1,
+									m_MaxY );
+			/*
+				Lower right
+				x ranges from halfway between m_MinX and m_MaxX to m_MaxX.
+				y ranges from halfway between m_MinY and m_MaxY to m_MaxY.
+			*/
+			m_Child[1][1] = new CQuadtree( this, 
+									m_MinX + ( m_MaxX - m_MinX ) / 2 + 1,
+									m_MaxX,
+									m_MinY + ( m_MaxY - m_MinY ) / 2 + 1,
+									m_MaxY );
+
+			// Remove and re-add each existing game object at this node, to
+			// distribute them to the child nodes.
+            //
+            // Unrolling this loop produced no discernable speedup
+            // over 10000 operations.
+			for ( i = 0; i < MAX_OBJECTS; ++i )
+			{
+				if ( !m_GameObject[i] )
+					continue;
+				T * tmp = m_GameObject[i];
+				removeObject( tmp );
+				addObject( tmp );
+			}
+            return m_Child[j][k]->addObject( obj );
+		}
+	};
+
+	/*!
+		Remove an object from this node.
+		\param obj Game object to remove.
+	*/
+	void removeObject( T * obj )
+	{
+		int i = 0;
+        // Unrolling this loop produced no discernable speedup
+        // over 10000 operations.
+		for ( i = 0; i < MAX_OBJECTS; ++i )
+    		if ( m_GameObject[i] == obj )
+				break;
+	
+		if ( i < MAX_OBJECTS )
+		{
+			m_GameObject[i] = 0;
+			obj->m_MyNode = 0;
+		}
+	};
+
+	/*!
+		If the children of this node contain fewer than MAX_OBJECTS game 
+		objects, put all those game objects in this node and delete the child
+		nodes.
+		\param node The node whose children may be merged.
+	*/
+	void Merge()
+	{
+		int children = 0;
+		int objects = 0;
+		int i, j, k;
+		for ( i = 0; i < 2; ++i )
+		{
+			for ( j = 0; j < 2; ++j )
+			{
+				if ( m_Child[i][j] )
+				{
+					children++;
+					for ( k = 0; k < MAX_OBJECTS; ++k )
+						if ( m_Child[i][j]->m_GameObject[k] )
+							objects++;
+				}
+			}
+		}
+
+		if ( children == 0 )
+			return;
+		if ( objects > MAX_OBJECTS )
+			return;
+
+		// There are children and at most MAX_OBJECTS objects.
+		// Merge child nodes into this one.
+		for ( i = 0; i < 2; ++i )
+		{
+		    for ( j = 0; j < 2; ++j )
+		    {
+			    if ( m_Child[i][j] )
+			    {
+				    for ( k = 0; k < MAX_OBJECTS; ++k )
+					    if ( m_Child[i][j]->m_GameObject[k] )
+					    {
+						    // Put the object on this node.
+						    m_GameObject[objects-1] = m_Child[i][j]->m_GameObject[k];
+						    m_GameObject[objects-1]->m_MyNode = this;
+							objects--;
+					    }
+                    delete m_Child[i][j];
+				    m_Child[i][j] = 0;
+			    }
+		    }
+		}
+	};
+
+	void Debug()
+	{
+		std::cout << "Node " << std::hex << this << std::dec;
+		std::cout << "  x:" << m_MinX << "," << m_MaxX;
+		std::cout << "  y:" << m_MinY << "," << m_MaxY << "\n";
+		int i;
+		for ( i = 0; i < MAX_OBJECTS; ++i )
+			if ( m_GameObject[i] )
+				std::cout << "	Object " << std::hex << m_GameObject[i] << std::dec << "  " << m_GameObject[i]->m_X << "," << m_GameObject[i]->m_Y << "\n";
+
+		int j, k;
+		for ( j = 0; j < 2; ++j )
+			for ( k = 0; k < 2; ++k )
+				if ( m_Child[j][k] )
+					std::cout << "	Child[" << j << "][" << k << "] = " << std::hex << m_Child[j][k] << std::dec << "\n";
+		std::cout << "	Parent " << std::hex << m_Parent << std::dec << "\n";
+	};
+
+};
+
+#endif
Index: COctree.h
===================================================================
--- COctree.h	(revision 0)
+++ COctree.h	(revision 0)
@@ -0,0 +1,493 @@
+/* Copyright (C) 2013 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 0 A.D. is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_OCTREE
+#define INCLUDED_OCTREE
+
+#define MAX_OBJECTS 4
+
+/*!
+A templated, adaptive octree class
+by Don Doumakes
+
+When initialized, the tree consists of a single node which contains no game
+objects.  As game objects are added to a node, child nodes are added to
+represent smaller and smaller subdivisions of the physical space, and the
+game objects are distributed downward to the leaf nodes.  Thus the number
+of game objects in a particular node is kept below an arbitrary maximum
+(which is what makes this tree "adaptive").  As game objects are moved to
+new locations or eliminated, the process is reversed, reducing the number
+of nodes in the tree.
+
+The tree class is mostly unaware of implementation details of the game object
+class.  However, it is useful for both classes to know:
+- the x, y and z coordinates of the game object
+- the tree node to which the game object is attached  
+Therefore, the minimal game object class T must contain the following
+declarations:
+\verbatim
+class T
+{
+private:
+	int m_X;
+	int m_Y;
+	int m_Z;
+	COctree<T> * m_MyNode;
+public:
+	friend class COctree<T>
+};
+\endverbatim
+Fortunately, omitting these declarations is a compile-time error.
+
+To calculate the range between a given game object and its neighbors,
+- Implement a rangefinding function in the game object class.
+- Traverse the tree and call your rangefinding function from each node.
+The siblings of a given node will be physically nearest, so if the
+traversal begins at the parent node of "this node," then only the nearest
+game objects will be checked.
+*/
+
+template <class T> class COctree
+{
+private:
+	/// Game objects contained by this node, along with their coordinates
+	T * m_GameObject[ MAX_OBJECTS ];
+	/// Parent node
+	COctree<T> * m_Parent;
+	/// Child nodes
+    COctree<T> * m_Child[2][2][2];
+	/// Length of map edges
+    int m_N;
+	/// Bounds of this node
+    int m_MinX, m_MaxX, m_MinY, m_MaxY, m_MinZ, m_MaxZ;
+
+    /// Typedef for a pointer to a void member function of T
+    typedef void ( T::* p_T_member )();
+    /// Typedef for a pointer to a void member function of COctree
+    typedef void ( COctree<T>::* p_COctree_member )();
+    /// Typedef for a pointer to an int member function of COctree
+    typedef int ( COctree<T>::* p_COctree_memberB )();
+
+	/*!
+		Constructor for non-root nodes.
+
+		\param parent Parent node of this node
+		\param x0 Minimum x value
+		\param x1 Maximum x value
+		\param y0 Minimum y value
+		\param y1 Maximum y value
+		\param z0 Minimum z value
+		\param z1 Maximum z value
+	*/
+	COctree( COctree<T> * parent, int x0, int x1, int y0, int y1, int z0, int z1 )
+	{
+		m_N = parent->m_N;
+		m_Parent = parent;
+		m_MinX = x0;
+		m_MaxX = x1;
+		m_MinY = y0;
+		m_MaxY = y1;
+		m_MinZ = z0;
+		m_MaxZ = z1;
+		memset( m_Child, 0, sizeof( COctree * ) * 4 );
+		memset( m_GameObject, 0, sizeof( T * ) * MAX_OBJECTS );
+	};
+
+public:
+
+	/*!
+		Constructor for the root node.
+        \param size Length of each edge of the game world cube.  Must be a power of two.
+	*/
+	COctree( int size ) : m_N( size ), 
+                            m_Parent( 0 ), 
+                            m_MinX( 0 ), 
+                            m_MaxX( size - 1 ), 
+                            m_MinY( 0 ), 
+                            m_MaxY( size - 1 ),
+                            m_MinZ( 0 ), 
+                            m_MaxZ( size - 1 )
+	{
+		if ( ( size && !( size & ( size - 1 ) ) ) == 0 )
+            throw 0; 
+
+		memset( m_Child, 0, sizeof( COctree * ) * 8 );
+		memset( m_GameObject, 0, sizeof( T * ) * MAX_OBJECTS );
+
+	};
+
+	/*!
+		Getter for the parent node
+	*/
+	COctree<T> * Parent()
+	{
+		return m_Parent;
+	};
+
+    /*!
+        Depth-first traversal of the tree
+
+		\param doEet Pointer to a member function of the game object class.
+    */
+    void traverse( p_T_member doEet )
+	{
+		int i, j, k;
+		for ( i = 0; i < 2; ++i )
+			for ( j = 0; j < 2; ++j )
+				for ( k = 0; k < 2; ++k )
+					if ( m_Child[i][j][k] )
+						// Traverse this child tree.
+						m_Child[i][j][k]->traverse( doEet );
+	
+		int m = 0;
+    	while ( m < MAX_OBJECTS && m_GameObject[m] )
+		{
+			// Call a function in the game object.
+			( m_GameObject[m]->*doEet )();
+			m++;
+		}
+	};
+
+    /*!
+        Depth-first traversal of the tree
+
+		\param doEet Pointer to a member function of this class.
+    */
+	void traverse( p_COctree_member doEet )
+	{
+		int i, j, k;
+		for ( i = 0; i < 2; ++i )
+			for ( j = 0; j < 2; ++j )
+				for ( k = 0; k < 2; ++k )
+					if ( m_Child[i][j][k] )
+						// Traverse this child tree.
+						m_Child[i][j][k]->traverse( doEet );
+
+		// Call a function in the COctree class.
+		( this->*doEet )();
+	};
+
+    /*!
+        Breadth-first traversal of the tree
+
+		\param doEet Pointer to a member function of this class.
+    */
+	void traverse( p_COctree_memberB doEet )
+	{
+		// Call a function in the COctree class.
+		( this->*doEet )();
+
+		int i, j, k;
+		for ( i = 0; i < 2; ++i )
+			for ( j = 0; j < 2; ++j )
+				for ( k = 0; k < 2; ++k )
+					if ( m_Child[i][j][k] )
+						// Traverse this child tree.
+						m_Child[i][j][k]->traverse( doEet );
+	};
+
+	/*!
+		Add a game object to this tree.
+
+		\param obj Game object to add.
+		\return Pointer to the node that contains the game object.
+	*/
+	COctree<T> * addObject( T * obj )
+	{
+        // Bad input?
+        if ( !obj )
+            throw "Attempt to add null object to tree";
+        if ( obj->m_X < 0 || obj->m_X > m_N - 1 ||
+             obj->m_Y < 0 || obj->m_Y > m_N - 1 ||
+             obj->m_Z < 0 || obj->m_Z > m_N - 1 )
+            throw "Object has invalid position.";
+
+		// Is this the right subtree?
+		if ( obj->m_X < m_MinX || obj->m_X > m_MaxX ||
+		     obj->m_Y < m_MinY || obj->m_Y > m_MaxY ||
+		     obj->m_Z < m_MinZ || obj->m_Z > m_MaxZ )
+		{
+			// Nope.
+			return m_Parent->addObject( obj );
+		}
+
+		int j = 0;
+		int k = 0;
+        int m = 0;
+		// Does this node have children?
+		if ( m_Child[0][0][0] )
+		{
+			// Yes, so choose a child node
+			// that includes (x,y,z).
+        	if ( obj->m_X < m_MinX + ( m_MaxX - m_MinX ) / 2 + 1 )
+				j = 0;
+			else
+				j = 1;
+        	if ( obj->m_Y < m_MinY + ( m_MaxY - m_MinY ) / 2 + 1 )
+				k = 0;
+			else
+				k = 1;
+        	if ( obj->m_Z < m_MinZ + ( m_MaxZ - m_MinZ ) / 2 + 1 )
+				m = 0;
+			else
+				m = 1;
+
+			// Add the object to that node instead.
+            return m_Child[j][k][m]->addObject( obj );
+		}
+
+		int i = 0;
+    	while ( i < MAX_OBJECTS && m_GameObject[i] )
+			i++;
+    	if ( i < MAX_OBJECTS )
+		{
+			m_GameObject[i] = obj;
+			obj->m_MyNode = this;
+			return this;
+		}
+        else if ( m_MinX == m_MaxX )
+        {
+			// If the size of this node is 1, stop
+            // adding nodes.
+            return 0;
+        }
+		else
+		{
+			// Create new leaf nodes.
+
+			/*
+				Northwest bottom
+				x ranges from m_MinX to halfway between m_MinX and m_MaxX.
+				y ranges from m_MinY to halfway between m_MinY and m_MaxY.
+				z ranges from m_MinZ to halfway between m_MinZ and m_MaxZ.
+			*/
+			m_Child[0][0][0] = new COctree( this, 
+									m_MinX, 
+									m_MinX + ( m_MaxX - m_MinX ) / 2,
+									m_MinY,
+									m_MinY + ( m_MaxY - m_MinY ) / 2,
+									m_MinZ,
+									m_MinZ + ( m_MaxZ - m_MinZ ) / 2 );
+			/*
+				Northeast bottom
+				x ranges from halfway between m_MinX and m_MaxX to m_MaxX.
+				y ranges from m_MinY to halfway between m_MinY and m_MaxY.
+				z ranges from m_MinZ to halfway between m_MinZ and m_MaxZ.
+			*/
+			m_Child[1][0][0] = new COctree( this, 
+									m_MinX + ( m_MaxX - m_MinX ) / 2 + 1,
+									m_MaxX,
+									m_MinY,
+									m_MinY + ( m_MaxY - m_MinY ) / 2,
+									m_MinZ,
+									m_MinZ + ( m_MaxZ - m_MinZ ) / 2 );
+			/*
+				Southwest bottom
+				x ranges from m_MinX to halfway between m_MinX and m_MaxX.
+				y ranges from halfway between m_MinY and m_MaxY to m_MaxY.
+				z ranges from m_MinZ to halfway between m_MinZ and m_MaxZ.
+			*/
+			m_Child[0][1][0] = new COctree( this, 
+									m_MinX, 
+									m_MinX + ( m_MaxX - m_MinX ) / 2,
+									m_MinY + ( m_MaxY - m_MinY ) / 2 + 1,
+									m_MaxY,
+									m_MinZ,
+									m_MinZ + ( m_MaxZ - m_MinZ ) / 2 );
+			/*
+				Southeast bottom
+				x ranges from halfway between m_MinX and m_MaxX to m_MaxX.
+				y ranges from halfway between m_MinY and m_MaxY to m_MaxY.
+				z ranges from m_MinZ to halfway between m_MinZ and m_MaxZ.
+			*/
+			m_Child[1][1][0] = new COctree( this, 
+									m_MinX + ( m_MaxX - m_MinX ) / 2 + 1,
+									m_MaxX,
+									m_MinY + ( m_MaxY - m_MinY ) / 2 + 1,
+									m_MaxY,
+									m_MinZ,
+									m_MinZ + ( m_MaxZ - m_MinZ ) / 2 );
+
+			/*
+				Northwest top
+				x ranges from m_MinX to halfway between m_MinX and m_MaxX.
+				y ranges from m_MinY to halfway between m_MinY and m_MaxY.
+				z ranges from halfway between m_MinZ and m_MaxZ to m_MaxZ.
+			*/
+			m_Child[0][0][1] = new COctree( this, 
+									m_MinX, 
+									m_MinX + ( m_MaxX - m_MinX ) / 2,
+									m_MinY,
+									m_MinY + ( m_MaxY - m_MinY ) / 2,
+									m_MinZ + ( m_MaxZ - m_MinZ ) / 2 + 1,
+									m_MaxZ );
+			/*
+				Northeast top
+				x ranges from halfway between m_MinX and m_MaxX to m_MaxX.
+				y ranges from m_MinY to halfway between m_MinY and m_MaxY.
+				z ranges from halfway between m_MinZ and m_MaxZ to m_MaxZ.
+			*/
+			m_Child[1][0][1] = new COctree( this, 
+									m_MinX + ( m_MaxX - m_MinX ) / 2 + 1,
+									m_MaxX,
+									m_MinY,
+									m_MinY + ( m_MaxY - m_MinY ) / 2,
+									m_MinZ + ( m_MaxZ - m_MinZ ) / 2 + 1,
+									m_MaxZ );
+			/*
+				Southwest top
+				x ranges from m_MinX to halfway between m_MinX and m_MaxX.
+				y ranges from halfway between m_MinY and m_MaxY to m_MaxY.
+				z ranges from halfway between m_MinZ and m_MaxZ to m_MaxZ.
+			*/
+			m_Child[0][1][1] = new COctree( this, 
+									m_MinX, 
+									m_MinX + ( m_MaxX - m_MinX ) / 2,
+									m_MinY + ( m_MaxY - m_MinY ) / 2 + 1,
+									m_MaxY,
+									m_MinZ + ( m_MaxZ - m_MinZ ) / 2 + 1,
+									m_MaxZ );
+			/*
+				Southeast top
+				x ranges from halfway between m_MinX and m_MaxX to m_MaxX.
+				y ranges from halfway between m_MinY and m_MaxY to m_MaxY.
+			*/
+			m_Child[1][1][1] = new COctree( this, 
+									m_MinX + ( m_MaxX - m_MinX ) / 2 + 1,
+									m_MaxX,
+									m_MinY + ( m_MaxY - m_MinY ) / 2 + 1,
+									m_MaxY,
+									m_MinZ + ( m_MaxZ - m_MinZ ) / 2 + 1,
+									m_MaxZ );
+
+			// Remove and re-add each existing game object at this node, to
+			// distribute them to the child nodes.
+			for ( i = 0; i < MAX_OBJECTS; ++i )
+			{
+				if ( !m_GameObject[i] )
+					continue;
+				T * tmp = m_GameObject[i];
+				removeObject( tmp );
+				addObject( tmp );
+			}
+            return m_Child[j][k][m]->addObject( obj );
+		}
+	};
+
+	/*!
+		Remove an object from this node.
+		\param obj Game object to remove.
+	*/
+	void removeObject( T * obj )
+	{
+		int i = 0;
+        // Unrolling this loop produced no discernable speedup
+        // over 10000 operations.
+		for ( i = 0; i < MAX_OBJECTS; ++i )
+    		if ( m_GameObject[i] == obj )
+				break;
+	
+		if ( i < MAX_OBJECTS )
+		{
+			m_GameObject[i] = 0;
+			obj->m_MyNode = 0;
+		}
+	};
+
+	/*!
+		If the children of this node contain fewer than MAX_OBJECTS game 
+		objects, put all those game objects in this node and delete the child
+		nodes.
+		\param node The node whose children may be merged.
+	*/
+	void Merge()
+	{
+		int children = 0;
+		int objects = 0;
+		int i, j, k, m;
+		for ( i = 0; i < 2; ++i )
+		{
+			for ( j = 0; j < 2; ++j )
+			{
+				for ( k = 0; k < 2; ++k )
+				{
+					if ( m_Child[i][j][k] )
+					{
+						children++;
+						for ( m = 0; m < MAX_OBJECTS; ++m )
+							if ( m_Child[i][j][k]->m_GameObject[m] )
+								objects++;
+					}
+				}
+			}
+		}
+
+		if ( children == 0 )
+			return;
+		if ( objects > MAX_OBJECTS )
+			return;
+
+		// There are children and at most MAX_OBJECTS objects.
+		// Merge child nodes into this one.
+		for ( i = 0; i < 2; ++i )
+		{
+		    for ( j = 0; j < 2; ++j )
+		    {
+		    	for ( k = 0; k < 2; ++k )
+		    	{
+			    	if ( m_Child[i][j][k] )
+			    	{
+				    	for ( m = 0; m < MAX_OBJECTS; ++m )
+					    	if ( m_Child[i][j][k]->m_GameObject[m] )
+					    	{
+						    	// Put the object on this node.
+						    	m_GameObject[objects-1] = m_Child[i][j][k]->m_GameObject[m];
+						    	m_GameObject[objects-1]->m_MyNode = this;
+								objects--;
+					    	}
+                    	delete m_Child[i][j][k];
+				    	m_Child[i][j][k] = 0;
+					}
+			    }
+		    }
+		}
+	};
+
+	void Debug()
+	{
+		std::cout << "Node " << std::hex << this << std::dec;
+		std::cout << "  x:" << m_MinX << "," << m_MaxX;
+		std::cout << "  y:" << m_MinY << "," << m_MaxY << "\n";
+		std::cout << "  z:" << m_MinZ << "," << m_MaxZ << "\n";
+		int i;
+		for ( i = 0; i < MAX_OBJECTS; ++i )
+			if ( m_GameObject[i] )
+				std::cout << "	Object " << std::hex << m_GameObject[i] << std::dec << "  ";
+                std::cout << m_GameObject[i]->m_X << "," << m_GameObject[i]->m_Y << "," << m_GameObject[i]->m_Z <<"\n";
+
+		int j, k, m;
+		for ( j = 0; j < 2; ++j )
+			for ( k = 0; k < 2; ++k )
+				for ( m = 0; m < 2; ++m )
+					if ( m_Child[j][k][m] )
+						std::cout << "	Child[" << j << "][" << k << "][" << m << "] = " << std::hex << m_Child[j][k][m] << std::dec << "\n";
+		std::cout << "	Parent " << std::hex << m_Parent << std::dec << "\n";
+	};
+
+};
+
+#endif
Index: tests/test_CQuadtree.h
===================================================================
--- tests/test_CQuadtree.h	(revision 0)
+++ tests/test_CQuadtree.h	(revision 0)
@@ -0,0 +1,221 @@
+/* Copyright (C) 2009 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 0 A.D. is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "lib/self_test.h"
+#include "ps/CQuadtree.h"
+
+class GameObj;
+
+class GameObj 
+{
+	int m_X, m_Y;
+	int m_Foo;
+	CQuadtree<GameObj> * m_MyNode;
+
+public:
+	GameObj( int x, int y ) : m_X(x), m_Y(y), m_Foo(0), m_MyNode(0)
+	{
+	};
+
+	void IncrementFoo()
+	{
+		m_Foo++;
+	};
+
+	void shout() { std::cout << std::hex << this << std::dec << " " << m_X << "," << m_Y << "\n"; };
+
+	int Foo()
+	{
+		return m_Foo;
+	}
+
+	CQuadtree<GameObj> * GetNode()
+	{
+		return m_MyNode;
+	}
+
+	friend class CQuadtree<GameObj>;
+};
+
+class TestCQuadtree : public CxxTest::TestSuite 
+{
+public:
+	void test_constructor()
+	{
+		CQuadtree<GameObj> t( 4 );
+		TS_ASSERT( t.Parent() == 0 );
+	};
+
+	void test_add()
+	{
+		CQuadtree<GameObj> t( 4 );
+		GameObj o1( 0,1 );
+		GameObj o2( 2,3 );
+		t.addObject( &o1 );
+		t.addObject( &o2 );
+		TS_ASSERT( o1.GetNode() == &t );
+		TS_ASSERT( o2.GetNode() == &t );
+	};
+
+	void test_remove()
+	{
+		CQuadtree<GameObj> t( 4 );
+		GameObj o1( 0,1 );
+		GameObj o2( 2,3 );
+		t.addObject( &o1 );
+		t.addObject( &o2 );
+		t.removeObject( &o2 );
+		TS_ASSERT( o1.GetNode() == &t );
+		TS_ASSERT( o2.GetNode() == 0 );
+	};
+
+	void test_traverse()
+	{
+		CQuadtree<GameObj> t( 4 );
+		GameObj o1( 0,1 );
+		t.addObject( &o1 );
+		t.traverse( &GameObj::IncrementFoo );
+		TS_ASSERT( o1.Foo() == 1 );
+	};
+
+	void test_split()
+	{
+		CQuadtree<GameObj> t( 8 );
+		int n = 0;
+		GameObj * first = 0;
+		GameObj * last = 0;
+
+		GameObj * o = new GameObj( 0, 0 );
+		t.addObject( o );
+		n++;
+		first = o;
+
+		o = new GameObj( 1, 0 );
+		t.addObject( o );
+		n++;
+
+		// We don't know what MAX_OBJECTS is.
+		if ( n < MAX_OBJECTS + 1 )
+		{
+			o = new GameObj( 0, 1 );
+			t.addObject( o );
+			n++;
+		}
+
+		if ( n < MAX_OBJECTS + 1 )
+		{
+			o = new GameObj( 1, 1 );
+			t.addObject( o );
+			n++;
+		}
+
+		if ( n < MAX_OBJECTS + 1 )
+		{
+			o = new GameObj( 0, 2 );
+			t.addObject( o );
+			n++;
+		}
+
+		if ( n < MAX_OBJECTS + 1 )
+		{
+			o = new GameObj( 1, 2 );
+			t.addObject( o );
+			n++;
+		}
+
+		if ( n < MAX_OBJECTS + 1 )
+		{
+			o = new GameObj( 2, 2 );
+			t.addObject( o );
+			n++;
+		}
+
+		last = o;
+
+		TS_ASSERT( first );
+		TS_ASSERT( last );
+		TS_ASSERT( first->GetNode() != last->GetNode() );
+	};
+
+//	void test_merge()
+//	{
+//		// This test assumes MAX_OBJECTS = 2.
+//		CQuadtree<GameObj> t( 8 );
+//
+//		GameObj * o1 = new GameObj( 0, 0 );
+//		t.addObject( o1 );
+//
+//		GameObj * o2 = new GameObj( 0, 1 );
+//		t.addObject( o2 );
+//
+//		GameObj * o3 = new GameObj( 1, 1 );
+//		t.addObject( o3 );
+//		// splits, twice
+//
+//		o3->GetNode()->removeObject( o3 );
+//
+//		t.traverse( &CQuadtree<GameObj>::Merge );
+//		//t.traverse( &CQuadtree<GameObj>::Debug );
+//		TS_ASSERT( o1->GetNode() == o2->GetNode() );
+//	};
+
+	void test_limit()
+	{
+		CQuadtree<GameObj> t( 4 );
+
+		// Fill up the root node.
+		int i;
+		for ( i = 0; i < MAX_OBJECTS; ++i )
+		{
+			GameObj * o = new GameObj( 0, 0 );
+			t.addObject( o );
+		}
+		// Make it split.
+		GameObj * o2 = new GameObj( 1, 0 );
+		t.addObject( o2 );
+		// Now there's a node for 0,0 that already has MAX_OBJECTS objects.
+		// Never mind how crazy that is, for now.
+
+		// This one should fail because we can't split a node of size 1.
+		GameObj * o3 = new GameObj( 0, 0 );
+		CQuadtree<GameObj> * tmp = t.addObject( o3 );
+
+		TS_ASSERT( !tmp );
+	};
+
+//	void test_speed()
+//	{
+//		int n = 128;
+//		CQuadtree<GameObj> t(n);
+//		int i, j;
+//		int count;
+//		time_t then = time( NULL );
+//		for ( count = 0; count < 10000; ++count )
+//		{
+//			for ( i = 0; i < n; ++i )
+//			{
+//				for ( j = 0; j < n; ++j )
+//				{
+//					GameObj * o = new GameObj( i, j );
+//					t.addObject( o );
+//				}
+//			}
+//		}
+//		time_t now = time( NULL );
+//		printf( "\nelapsed time %ld sec\n", now - then );
+//	};
+};
Index: tests/test_COctree.h
===================================================================
--- tests/test_COctree.h	(revision 0)
+++ tests/test_COctree.h	(revision 0)
@@ -0,0 +1,224 @@
+/* Copyright (C) 2009 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 0 A.D. is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "lib/self_test.h"
+#include "ps/COctree.h"
+
+class GameObj2;
+
+class GameObj2 
+{
+	int m_X, m_Y, m_Z;
+	int m_Foo;
+	COctree<GameObj2> * m_MyNode;
+
+public:
+	GameObj2( int x, int y, int z ) : m_X(x), m_Y(y), m_Z(z), m_Foo(0), m_MyNode(0)
+	{
+	};
+
+	void IncrementFoo()
+	{
+		m_Foo++;
+	};
+
+	void shout() { std::cout << std::hex << this << std::dec << " " << m_X << "," << m_Y << "," << m_Z << "\n"; };
+
+	int Foo()
+	{
+		return m_Foo;
+	};
+
+	COctree<GameObj2> * GetNode()
+	{
+		return m_MyNode;
+	};
+
+	friend class COctree<GameObj2>;
+};
+
+class TestCOctree : public CxxTest::TestSuite 
+{
+public:
+	void test_constructor()
+	{
+		COctree<GameObj2> t( 4 );
+		TS_ASSERT( t.Parent() == 0 );
+	};
+
+	void test_add()
+	{
+		COctree<GameObj2> t( 4 );
+		GameObj2 o1( 0,1,0 );
+		GameObj2 o2( 2,3,0 );
+		t.addObject( &o1 );
+		t.addObject( &o2 );
+		TS_ASSERT( o1.GetNode() == &t );
+		TS_ASSERT( o2.GetNode() == &t );
+	};
+
+	void test_remove()
+	{
+		COctree<GameObj2> t( 4 );
+		GameObj2 o1( 0,1,0 );
+		GameObj2 o2( 2,3,0 );
+		t.addObject( &o1 );
+		t.addObject( &o2 );
+		t.removeObject( &o2 );
+		TS_ASSERT( o1.GetNode() == &t );
+		TS_ASSERT( o2.GetNode() == 0 );
+	};
+
+	void test_traverse()
+	{
+		COctree<GameObj2> t( 4 );
+		GameObj2 o1( 0,1,0 );
+		t.addObject( &o1 );
+		t.traverse( &GameObj2::IncrementFoo );
+		TS_ASSERT( o1.Foo() == 1 );
+	};
+
+	void test_split()
+	{
+		COctree<GameObj2> t( 8 );
+		int n = 0;
+		GameObj2 * first = 0;
+		GameObj2 * last = 0;
+
+		GameObj2 * o = new GameObj2( 0, 0, 0 );
+		t.addObject( o );
+		n++;
+		first = o;
+
+		o = new GameObj2( 1, 0, 0 );
+		t.addObject( o );
+		n++;
+
+		// We don't know what MAX_OBJECTS is.
+		if ( n < MAX_OBJECTS + 1 )
+		{
+			o = new GameObj2( 0, 1, 0 );
+			t.addObject( o );
+			n++;
+		}
+
+		if ( n < MAX_OBJECTS + 1 )
+		{
+			o = new GameObj2( 1, 1, 0 );
+			t.addObject( o );
+			n++;
+		}
+
+		if ( n < MAX_OBJECTS + 1 )
+		{
+			o = new GameObj2( 0, 2, 0 );
+			t.addObject( o );
+			n++;
+		}
+
+		if ( n < MAX_OBJECTS + 1 )
+		{
+			o = new GameObj2( 1, 2, 0 );
+			t.addObject( o );
+			n++;
+		}
+
+		if ( n < MAX_OBJECTS + 1 )
+		{
+			o = new GameObj2( 2, 2, 0 );
+			t.addObject( o );
+			n++;
+		}
+
+		last = o;
+
+		TS_ASSERT( first );
+		TS_ASSERT( last );
+		TS_ASSERT( first->GetNode() != last->GetNode() );
+	};
+
+//	void test_merge()
+//	{
+//		// This test assumes MAX_OBJECTS = 2.
+//		COctree<GameObj2> t( 8 );
+//
+//		GameObj2 * o1 = new GameObj2( 0, 0, 0 );
+//		t.addObject( o1 );
+//
+//		GameObj2 * o2 = new GameObj2( 0, 1, 0 );
+//		t.addObject( o2 );
+//
+//		GameObj2 * o3 = new GameObj2( 1, 1, 0 );
+//		t.addObject( o3 );
+//		// splits, twice
+//
+//		o3->GetNode()->removeObject( o3 );
+//
+//		t.traverse( &COctree<GameObj2>::Merge );
+//		//t.traverse( &COctree<GameObj2>::Debug );
+//		TS_ASSERT( o1->GetNode() == o2->GetNode() );
+//	};
+
+	void test_limit()
+	{
+		COctree<GameObj2> t( 4 );
+
+		// Fill up the root node.
+		int i;
+		for ( i = 0; i < MAX_OBJECTS; ++i )
+		{
+			GameObj2 * o = new GameObj2( 0, 0, 0 );
+			t.addObject( o );
+		}
+		// Make it split.
+		GameObj2 * o2 = new GameObj2( 1, 0, 0 );
+		t.addObject( o2 );
+		// Now there's a node for 0,0 that already has MAX_OBJECTS objects.
+		// Never mind how crazy that is, for now.
+
+		// This one should fail because we can't split a node of size 1.
+		GameObj2 * o3 = new GameObj2( 0, 0, 0 );
+		COctree<GameObj2> * tmp = t.addObject( o3 );
+
+		TS_ASSERT( !tmp );
+	};
+
+//	void test_speed()
+//	{
+//		int n = 128;
+//		COctree<GameObj2> t(n);
+//		int i, j, k;
+//		int count;
+//		time_t then = time( NULL );
+//		for ( count = 0; count < 10000; ++count )
+//		{
+//			for ( i = 0; i < n; ++i )
+//			{
+//				for ( j = 0; j < n; ++j )
+//				{
+//					for ( k = 0; k < n; ++k )
+//					{
+//						GameObj2 * o = new GameObj2( i, j, k );
+//						t.addObject( o );
+//					}
+//				}
+//			}
+//		}
+//		time_t now = time( NULL );
+//		printf( "\nelapsed time %ld sec\n", now - then );
+//	};
+};
