A simple Octree based Map class. This is a snippet from
a larger code base and will not compile by itself. These files
demonstrate the loading and rendering of an octree based
the camera's frustum.




map.h:

#ifndef _MAP_H
#define _MAP_H

#ifdef _WIN32
	#include 	// If you dont have this, gl.h will not compile
#endif

#include 

#include 

#include "renderable.h"
#include "material.h"

using std::stack;

const float MOFVERSION = 1.3f;	// Control for MOF versioning

struct MeshVertex
{
		GLfloat pos [3],	// 3d position
				norm[3],	// Normal vector
				uv  [2];	// Texture coordinates u,v
};

struct MeshFace
{
	GLuint  index [3];		// 3 indexes into the list of verticies
	GLfloat normal[3];		// Face normal vector
};

struct Octet
{
	Octet();
	~Octet();
	
	Octet *child[8];

	unsigned int numFaces;
	
	GLfloat *data,
			center[3],
			radius;

	GLuint vboID;
};

class Map : public Renderable
{
	public:
			
		Map();
		~Map();
		
		void Render		(const unsigned int &time) const;

		bool Load	(const char *filename);
		void Unload	();

	private:
		
		Octet *head;	// Head of the octree
		
		unsigned int numVerts,
					 numFaces;

		Material	material;
		MeshVertex	*verts;
		MeshFace	*faces;

		void DeleteOctets	(Octet *&node);
		void LoadOctets		(Octet *&node, FILE *&infile);
		void GenLists		(Octet *&node);
		void DrawOctets		(const Octet *node, const GLfloat *frustum) const;
		bool LoadMof		(const char *filename);
		bool NodeInFrustum	(const GLfloat *frustum, const Octet *node) const;
};

#endif


map.cpp:

#include "map.h"

#include 
#include 

#include "camera.h"
#include "console.h"
#include "glextensions.h"
#include "state.h"

Octet::Octet()
	: numFaces(0), data(0),	vboID(0)
{
	memset(child, 0, sizeof(Octet *)*8);
}

Octet::~Octet()
{
	delete [] data;
	if(GL_ARB_vertex_buffer_object_supported && glIsBufferARB(vboID) == GL_TRUE)
	{
		glDeleteBuffersARB(1, &vboID);
	}
}

Map::Map()
	: head(0), numVerts(0), numFaces(0), verts(0), faces(0)
{

}

Map::~Map()
{
	Unload();
}

void Map::Render(const unsigned int &time) const
{
	glColor3f(1.0f, 1.0f, 1.0f);	
	
	StateMgr::Inst()->StateEnable(GL_CULL_FACE);
	StateMgr::Inst()->StateEnable(GL_TEXTURE_2D);
		
		material.Apply();
		DrawOctets (head, CamMgr::Inst()->GetFrustum());
		
	StateMgr::Inst()->StateDisable(GL_TEXTURE_2D);
	StateMgr::Inst()->StateDisable(GL_CULL_FACE);
}

void Map::DeleteOctets(Octet *&node)
{
	if(node)
	{
		for(int x = 0; x < 8; x++)
		{
			if(node->child[x])
			{
				DeleteOctets(node->child[x]);
			}
		}
		delete node;
	}
}

bool Map::Load(const char *filename)
{
	if(head)	// If there is already a map loaded...
	{
		Unload();
	}
	
	if(LoadMof(filename))
	{	
		GenLists(head);
		return true;
	}
	else
	{
		Unload();
		ConsoleMgr::Inst()->AddText("* Unable to load \'%s\'", filename);
		return false;
	}
}

void Map::Unload()
{
	material.Unload();
	delete [] verts;	verts = 0;
	delete [] faces;	faces = 0;

	numVerts = 0;
	numFaces = 0;
	
	if(head)
	{
		DeleteOctets(head);
	}
	
	head = 0;
}

bool Map::LoadMof(const char *filename)
{
	FILE *infile;

	infile = fopen(filename, "rb");

	if(infile)
	{
		float version;

		fread(&version,	sizeof(float), 1, infile);
		
		if(version == MOFVERSION)
		{
			material.Read(infile);						
			material.LoadTexture();

			fread(&numVerts,	sizeof(unsigned int),	1,	infile);	// Number of verticies
			fread(&numFaces,	sizeof(unsigned int),	1,	infile);	// Number of faces
			
			verts = new MeshVertex	[numVerts];
			faces = new MeshFace	[numFaces];

			fread(verts, sizeof(MeshVertex),	numVerts,	infile);	// List of MeshVertex's
			fread(faces, sizeof(MeshFace),		numFaces,	infile);	// List of MeshFace's

			LoadOctets(head, infile);

			fclose(infile);
			return true;
		}
		else
		{
			ConsoleMgr::Inst()->AddText("* Map version mismatch");
			fclose(infile);
			return false;
		}
	}
	else
	{
		return false;
	}
}

void Map::LoadOctets(Octet *&node, FILE *&infile)
{
	node = new Octe

	GLubyte children;
		
	fread(&children,		sizeof(GLubyte),	1,	infile);	// Number of children
	fread( node->center,	sizeof(GLfloat),	3,	infile);	// 3d point, center of the node
	fread(&node->radius,	sizeof(GLfloat),	1,	infile);	// Radius
	fread(&node->numFaces,	sizeof(GLfloat),	1,	infile);	// Number of faces in the node. (0 if its a parent)	

	if(node->numFaces)	// If this isn't 0, this node is a leaf, and we need to ouput which faces are in this node
	{
		node->data = new GLfloat[24*node->numFaces];
		fread(node->data, sizeof(GLfloat), 24*node->numFaces, infile);
	}
	else				// If it isn't a leaf, it has children which need loading.
	{
		for(GLubyte x = 0; x < children; ++x)
		{
			LoadOctets(node->child[x], infile);
		}
	}
}

void Map::GenLists(Octet *&node)
{
	if(node)
	{
		if(node->numFaces > 0)
		{
			
			if(GL_ARB_vertex_buffer_object_supported)
			{
				if(node->vboID)
				{
					glDeleteBuffersARB(1, &node->vboID);
				}
				glGenBuffersARB(1, &node->vboID);
				glBindBufferARB(GL_ARRAY_BUFFER_ARB, node->vboID);
				glBufferDataARB(GL_ARRAY_BUFFER_ARB, node->numFaces*24*sizeof(GLfloat), node->data, GL_STATIC_DRAW_ARB);
			}
		}
		else
		{
			for(unsigned int x = 0; x < 8; ++x)
			{
				GenLists(node->child[x]);
			}
		}
	}
}

void Map::DrawOctets(const Octet *node, const GLfloat *frustum) const
{
	if(node && frustum)
	{
		if(NodeInFrustum(frustum, node))
		{
			if(node->numFaces)
			{
				if(GL_ARB_vertex_buffer_object_supported /*&& glIsBufferARB(node->vboID) == GL_TRUE*/)
				{
					glBindBufferARB(GL_ARRAY_BUFFER_ARB, node->vboID);
					glInterleavedArrays(GL_T2F_N3F_V3F, 0, 0);
				}
				else
				{
					glInterleavedArrays(GL_T2F_N3F_V3F, 0, node->data);
				}
				
				glDrawArrays(GL_TRIANGLES, 0, node->numFaces*3);
			}
			else
			{
				for(unsigned int x = 0; x < 8; ++x)
				{
					DrawOctets(node->child[x], frustum);
				}
			}
		}
	}
}

bool Map::NodeInFrustum(const GLfloat *frustum, const Octet *node) const
{
	for(unsigned int p = 0; p < 6; p++ )
	{
		unsigned int i = p*4;
		
		if(frustum[i] * (node->center[0] - node->radius) + frustum[i+1] * (node->center[1] - node->radius) + frustum[i+2] * (node->center[2] - node->radius) + frustum[i+3] > 0)
			continue;	
		if(frustum[i] * (node->center[0] + node->radius) + frustum[i+1] * (node->center[1] - node->radius) + frustum[i+2] * (node->center[2] - node->radius) + frustum[i+3] > 0)
			continue;
		if(frustum[i] * (node->center[0] - node->radius) + frustum[i+1] * (node->center[1] + node->radius) + frustum[i+2] * (node->center[2] - node->radius) + frustum[i+3] > 0)
			continue;
		if(frustum[i] * (node->center[0] + node->radius) + frustum[i+1] * (node->center[1] + node->radius) + frustum[i+2] * (node->center[2] - node->radius) + frustum[i+3] > 0)
			continue;
		if(frustum[i] * (node->center[0] - node->radius) + frustum[i+1] * (node->center[1] - node->radius) + frustum[i+2] * (node->center[2] + node->radius) + frustum[i+3] > 0)
			continue;
		if(frustum[i] * (node->center[0] + node->radius) + frustum[i+1] * (node->center[1] - node->radius) + frustum[i+2] * (node->center[2] + node->radius) + frustum[i+3] > 0)
			continue;
		if(frustum[i] * (node->center[0] - node->radius) + frustum[i+1] * (node->center[1] + node->radius) + frustum[i+2] * (node->center[2] + node->radius) + frustum[i+3] > 0)
			continue;
		if(frustum[i] * (node->center[0] + node->radius) + frustum[i+1] * (node->center[1] + node->radius) + frustum[i+2] * (node->center[2] + node->radius) + frustum[i+3] > 0)
			continue;
		
		return false;
	}
	return true;
}