Index: /orxonox/branches/john/src/3dStructs.cc
===================================================================
--- /orxonox/branches/john/src/3dStructs.cc	(revision 2035)
+++ /orxonox/branches/john/src/3dStructs.cc	(revision 2035)
@@ -0,0 +1,101 @@
+#include "3dStructs.h"
+#include <GL/glut.h>
+
+/* Debugging*/
+#include <iostream.h>
+
+
+void C3dModel::Draw(int g_ViewMode)
+{
+   /* This function draws the models, currently not all functions 
+      supported */   
+
+	for(int i = 0; i < numOfObjects; i++)
+	{
+		// Make sure we have valid objects just in case. (size() is in the vector class)
+		if(pObject.size() <= 0) break;
+
+		// Get the current object that we are displaying
+			
+		// Check to see if this object has a texture map, if so bind the texture to it.
+		if(pObject[i].bHasTexture) {
+
+			// Turn on texture mapping and turn off color
+			glEnable(GL_TEXTURE_2D);
+
+			// Reset the color to normal again
+			glColor3ub(255, 255, 255);
+
+			// Bind the texture map to the object by it's materialID
+			//glBindTexture(GL_TEXTURE_2D, g_Texture[pObject->materialID]);
+		} else {
+
+			// Turn off texture mapping and turn on color
+			glDisable(GL_TEXTURE_2D);
+
+			// Reset the color to normal again
+			glColor3ub(255, 255, 255);
+		}
+
+		// This determines if we are in wireframe or normal mode
+		glBegin(g_ViewMode);					// Begin drawing with our selected mode (triangles or lines)
+
+			// Go through all of the faces (polygons) of the object and draw them
+			for(int j = 0; j < pObject[i].iNumOfFaces; j++)
+			{
+				// Go through each corner of the triangle and draw it.
+				for(int whichVertex = 0; whichVertex < 3; whichVertex++)
+				{
+					// Get the index for each point of the face
+					int index = pObject[i].pFaces[j].vertIndex[whichVertex];
+			
+					// Give OpenGL the normal for this vertex.
+					glNormal3f(pObject[i].pNormals[ index ].x, pObject[i].pNormals[ index ].y, pObject[i].pNormals[ index ].z);
+				
+					// If the object has a texture associated with it, give it a texture coordinate.
+					if(pObject[i].bHasTexture) {
+
+						// Make sure there was a UVW map applied to the object or else it won't have tex coords.
+						if(pObject[i].pTexVerts) {
+							glTexCoord2f(pObject[i].pTexVerts[ index ].x, pObject[i].pTexVerts[ index ].y);
+						}
+					} else {
+
+						// Make sure there is a valid material/color assigned to this object.
+						// You should always at least assign a material color to an object, 
+						// but just in case we want to check the size of the material list.
+						// if the size is at least one, and the material ID != -1,
+						// then we have a valid material.
+						if(pMaterials.size() && pObject[i].materialID >= 0) 
+						{
+							// Get and set the color that the object is, since it must not have a texture
+							char *pColor = pMaterials[pObject[i].materialID].color;
+
+							// Assign the current color to this model
+							glColor3ub(pColor[0], pColor[1], pColor[2]);
+						}
+					}
+
+					// Pass in the current vertex of the object (Corner of current face)
+					glVertex3f(pObject[i].pVerts[ index ].x, pObject[i].pVerts[ index ].y, pObject[i].pVerts[ index ].z);
+				}
+			}
+
+		glEnd();								// End the drawing
+	}
+}
+
+/* Just a debugging function */
+void C3dModel::PrintProperties()
+{
+   printf( "Number of objects: %i\n", numOfObjects);
+   printf( "Number of materials: %i\n", numOfMaterials);
+   for( int i; i < numOfObjects; i++ )
+   {
+      printf( "Object Number %i:\n", i );   
+      printf( "Number of Vertices: %i\n", pObject[i].iNumOfVerts);
+      printf( "Number of Faces: %i\n", pObject[i].iNumOfFaces);
+      printf( "Number of Texture Materials: %i\n", pObject[i].iNumTexVertex);
+      printf( "Has a texture: %i\n", pObject[i].bHasTexture);   
+   }
+}
Index: /orxonox/branches/john/src/3dStructs.h
===================================================================
--- /orxonox/branches/john/src/3dStructs.h	(revision 2035)
+++ /orxonox/branches/john/src/3dStructs.h	(revision 2035)
@@ -0,0 +1,95 @@
+#ifndef _3DSTRUCTS_H
+#define _3DSTRUCTS_H
+
+/* STL (Standard Template Library) Vector */
+#include <vector>
+using namespace std;
+
+/*########################### Showroom.cpp ###########################
+# This file includes all of the model structures that are needed to load
+# in a .3DS file.
+# $Author: Ben Humphrey (DigiBen), Johannes Bader
+# $Revision: 1.0
+# $Date: 5.5.04
+###################################################################### */
+
+/* This is our 3D point class.  
+   This will be used to store the vertices of our model. */
+class CVector3 
+{
+public:
+	float x, y, z;
+};
+
+/* This is our 2D point class.  
+   This will be used to store the UV coordinates. */
+class CVector2 
+{
+public:
+	float x, y;
+};
+
+/* ############## Currently not supported by Showroom */
+
+/* This holds the information for a material.  It may be a texture map of a 
+   color. Some of these are not used, but I left them because you will want to 
+   eventually read in the UV tile ratio and the UV tile offset for some 
+   models.*/
+struct tMaterialInfo
+{
+	char  strName[255];		/* The texture name */
+	char  strFile[255];		/* The texture file name */
+	char  color[3];			/* The color of the object (R, G, B) */
+	int   texureId;			/* the texture ID */
+	float uTile;				/* u tiling of texture  (Currently not used) */
+	float vTile;				/* v tiling of texture	(Currently not used) */
+	float uOffset;			   /* u offset of texture	(Currently not used) */
+	float vOffset;				/* v offset of texture	(Currently not used) */
+} ;
+
+
+/* This is the face structure.  This is is used for indexing into the vertex 
+   and texture coordinate arrays.  From this information we know which vertices
+   from our vertex array go to which face, along with the correct 
+   texture coordinates. */
+struct tFace
+{
+	int vertIndex[3];	 /* indicies for the verts that make up this triangle */
+	int coordIndex[3]; /* indicies for the tex coords to texture this face */
+};
+
+/* This holds the object information. An object is part of a model */
+struct t3dObject 
+{
+	int  iNumOfVerts;			/* The number of verts in the model */
+	int  iNumOfFaces;			/* The number of faces in the model */
+	char strName[255];		/* The name of the object	*/
+	CVector3  *pVerts;		/* The object's vertices */
+	CVector3  *pNormals;		/* The object's normals */
+	CVector2  *pTexVerts;	/* The texture's UV coordinates */
+	tFace *pFaces;				/* The faces information of the object */
+ 
+   /* Not used */
+   int  iNumTexVertex;		// The number of texture coordinates
+	int  materialID;			// The texture ID to use, which is the index into our texture array
+	bool bHasTexture;			// This is TRUE if there is a texture map for this object	
+};
+
+/* This holds the model information. A model may consist of several
+   objects */
+class C3dModel 
+{
+	public:
+      int numOfObjects;					   /* The number of objects */
+      vector<t3dObject> pObject;			/* The object list for our model */
+      
+        /* Not yet used */
+	   int numOfMaterials;  				/* The number of materials */
+	   vector<tMaterialInfo> pMaterials; 	/* The list of material information
+                                              (Textures and colors) */
+      /* Draws the Model, mode = GL_LINE_STRIP etc. */
+      void Draw( int mode );
+      void PrintProperties( void );
+};
+
+#endif
Index: /orxonox/branches/john/src/3dUnit.cc
===================================================================
--- /orxonox/branches/john/src/3dUnit.cc	(revision 2035)
+++ /orxonox/branches/john/src/3dUnit.cc	(revision 2035)
@@ -0,0 +1,64 @@
+#include "3dUnit.h"
+/* Provides function for loading a 3ds file */
+#include "3ds.h"
+/* Model structures that are needed to load in a .3DS file. */
+#include "3dStructs.h"
+
+/*########################### Showroom.cpp ###########################
+# This class generates a unit, and provides functions to load and display
+# the corresponding 3ds file.
+# $Author: Johannes Bader
+# $Revision: 1.0
+# $Date: 5.5.04
+###################################################################### */
+
+C3dUnit::C3dUnit( char* name )
+{
+    /* Creates a new 3d Object of type "name" 
+       "name" must have at most 8 characters */
+    
+    if( strlen( name ) <= 8 ) {
+        strcpy( sName, name );        
+    }
+    else {
+        printf( "Name to long, >= 8 characters: %s!", name );
+        strcpy( sName, "noname" );
+    }
+    Init();
+}
+
+C3dUnit::C3dUnit( void )
+{
+    /* No name specified */
+    strcpy( sName, "test.3ds" );
+    Init();
+}
+
+void C3dUnit::Init( void )
+{
+   b3dModelLoaded = false;
+}
+
+void C3dUnit::Import3ds( void )
+{
+   /* Class to load the *.3ds file */
+   CLoad3ds g_Load3ds;
+   /* Loads the file "name" and stores the data in CModel */
+   b3dModelLoaded = g_Load3ds.Import3DS( &CModel, sName );
+}
+
+void C3dUnit::Draw( int mode )
+{
+   /* Draws the Model. If none has been loaded, print an error */
+   if( b3dModelLoaded ) CModel.Draw( mode );
+   else printf( "No Model for Unit %s loaded!", sName );   
+}
+
+void C3dUnit::PrintProperties( void )
+{
+   /* This function displays the Properties of the Model */
+   if( b3dModelLoaded )
+      CModel.PrintProperties();
+   else printf( "No Model for Unit %s loaded!", sName );
+}
+
Index: /orxonox/branches/john/src/3dUnit.h
===================================================================
--- /orxonox/branches/john/src/3dUnit.h	(revision 2035)
+++ /orxonox/branches/john/src/3dUnit.h	(revision 2035)
@@ -0,0 +1,21 @@
+#ifndef _3DUNIT_H
+#define _3DUNIT_H
+
+#include "3dStructs.h"
+
+class C3dUnit
+{
+    private:
+        char sName[9];                /* Name of the unit (=> filename etc. )*/
+        bool b3dModelLoaded;          /* Set if model loaded */
+        void Init();                  /* Sets initial values of variables */        
+        C3dModel CModel;              /* Contains the 3d model data */ 
+    public:
+        C3dUnit( char* );
+        C3dUnit( void );
+        void Import3ds( void );
+        void Draw( int );
+        void PrintProperties( void );        
+};
+
+#endif 
Index: /orxonox/branches/john/src/3ds.cc
===================================================================
--- /orxonox/branches/john/src/3ds.cc	(revision 2035)
+++ /orxonox/branches/john/src/3ds.cc	(revision 2035)
@@ -0,0 +1,916 @@
+//***********************************************************************//
+//																		 //
+//		- "Talk to me like I'm a 3 year old!" Programming Lessons -		 //
+//                                                                       //
+//		$Author:		DigiBen		digiben@gametutorials.com			 //
+//																		 //
+//		$Program:		3DS Loader										 //
+//																		 //
+//		$Description:	Demonstrates how to load a .3ds file format		 //
+//																		 //
+//		$Date:			10/6/01											 //
+//																		 //
+//***********************************************************************//
+
+#include "3ds.h"
+#include <assert.h>
+#include <math.h>
+
+// Global
+int gBuffer[50000] = {0};					// This is used to read past unwanted data
+
+// This file handles all of the code needed to load a .3DS file.
+// Basically, how it works is, you load a chunk, then you check
+// the chunk ID.  Depending on the chunk ID, you load the information
+// that is stored in that chunk.  If you do not want to read that information,
+// you read past it.  You know how many bytes to read past the chunk because
+// every chunk stores the length in bytes of that chunk.
+
+///////////////////////////////// CLOAD3DS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+/////
+/////	This constructor initializes the tChunk data
+/////
+///////////////////////////////// CLOAD3DS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+
+CLoad3ds::CLoad3ds()
+{
+	m_FilePointer = NULL;
+}
+
+///////////////////////////////// IMPORT 3DS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+/////
+/////	This is called by the client to open the .3ds file, read it, then clean up
+/////
+///////////////////////////////// IMPORT 3DS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+
+bool CLoad3ds::Import3DS(C3dModel *pModel, char *strFileName)
+{
+	char strMessage[255] = {0};
+	tChunk currentChunk = {0};
+
+	// Open the 3DS file
+	m_FilePointer = fopen(strFileName, "rb");
+
+	// Make sure we have a valid file pointer (we found the file)
+	if(!m_FilePointer) 
+	{
+		sprintf(strMessage, "Unable to find the file: %s!", strFileName);		
+		return false;
+	}
+
+	// Once we have the file open, we need to read the very first data chunk
+	// to see if it's a 3DS file.  That way we don't read an invalid file.
+	// If it is a 3DS file, then the first chunk ID will be equal to PRIMARY (some hex num)
+
+	// Read the first chuck of the file to see if it's a 3DS file
+	ReadChunk(&currentChunk);
+
+	// Make sure this is a 3DS file
+	if (currentChunk.ID != PRIMARY)
+	{
+		sprintf(strMessage, "Unable to load PRIMARY chuck from file: %s!", strFileName);
+		return false;
+	}
+
+	// Now we actually start reading in the data.  ProcessNextChunk() is recursive
+
+	// Begin loading objects, by calling this recursive function
+	ProcessNextChunk(pModel, &currentChunk);
+
+	// After we have read the whole 3DS file, we want to calculate our own vertex normals.
+	ComputeNormals(pModel);
+
+	// Clean up after everything
+	CleanUp();
+
+	return true;
+}
+
+///////////////////////////////// CLEAN UP \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+/////
+/////	This function cleans up our allocated memory and closes the file
+/////
+///////////////////////////////// CLEAN UP \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+
+void CLoad3ds::CleanUp()
+{
+	if (m_FilePointer) {
+		fclose(m_FilePointer);					// Close the current file pointer
+		m_FilePointer = NULL;
+	}
+}
+
+
+///////////////////////////////// PROCESS NEXT CHUNK\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+/////
+/////	This function reads the main sections of the .3DS file, then dives deeper with recursion
+/////
+///////////////////////////////// PROCESS NEXT CHUNK\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+
+void CLoad3ds::ProcessNextChunk(C3dModel *pModel, tChunk *pPreviousChunk)
+{
+	t3dObject newObject = {0};					// This is used to add to our object list
+	tMaterialInfo newTexture = {0};				// This is used to add to our material list
+
+	tChunk currentChunk = {0};					// The current chunk to load
+	tChunk tempChunk = {0};						// A temp chunk for holding data		
+
+	// Below we check our chunk ID each time we read a new chunk.  Then, if
+	// we want to extract the information from that chunk, we do so.
+	// If we don't want a chunk, we just read past it.  
+
+	// Continue to read the sub chunks until we have reached the length.
+	// After we read ANYTHING we add the bytes read to the chunk and then check
+	// check against the length.
+	while (pPreviousChunk->bytesRead < pPreviousChunk->length)
+	{
+		// Read next Chunk
+		ReadChunk(&currentChunk);
+
+		// Check the chunk ID
+		switch (currentChunk.ID)
+		{
+		case VERSION:							// This holds the version of the file
+			
+			// If the file was made in 3D Studio Max, this chunk has an int that 
+			// holds the file version.  Since there might be new additions to the 3DS file
+			// format in 4.0, we give a warning to that problem.
+			// However, if the file wasn't made by 3D Studio Max, we don't 100% what the
+			// version length will be so we'll simply ignore the value
+
+			// Read the file version and add the bytes read to our bytesRead variable
+			currentChunk.bytesRead += fread(gBuffer, 1, currentChunk.length - currentChunk.bytesRead, m_FilePointer);
+
+			// If the file version is over 3, give a warning that there could be a problem
+			if ((currentChunk.length - currentChunk.bytesRead == 4) && (gBuffer[0] > 0x03)) {
+				// This 3DS file is over version 3 so it may load incorrectly
+			}
+			break;
+
+		case OBJECTINFO:						// This holds the version of the mesh
+			{	
+			// This chunk holds the version of the mesh.  It is also the head of the MATERIAL
+			// and OBJECT chunks.  From here on we start reading in the material and object info.
+
+			// Read the next chunk
+			ReadChunk(&tempChunk);
+
+			// Get the version of the mesh
+			tempChunk.bytesRead += fread(gBuffer, 1, tempChunk.length - tempChunk.bytesRead, m_FilePointer);
+
+			// Increase the bytesRead by the bytes read from the last chunk
+			currentChunk.bytesRead += tempChunk.bytesRead;
+
+			// Go to the next chunk, which is the object has a texture, it should be MATERIAL, then OBJECT.
+			ProcessNextChunk(pModel, &currentChunk);
+			break;
+		}
+		case MATERIAL:							// This holds the material information
+
+			// This chunk is the header for the material info chunks
+
+			// Increase the number of materials
+			pModel->numOfMaterials++;
+
+			// Add a empty texture structure to our texture list.
+			// If you are unfamiliar with STL's "vector" class, all push_back()
+			// does is add a new node onto the list.  I used the vector class
+			// so I didn't need to write my own link list functions.  
+			pModel->pMaterials.push_back(newTexture);
+
+			// Proceed to the material loading function
+			ProcessNextMaterialChunk(pModel, &currentChunk);
+			break;
+
+		case OBJECT:							// This holds the name of the object being read
+				
+			// This chunk is the header for the object info chunks.  It also
+			// holds the name of the object.
+
+			// Increase the object count
+			pModel->numOfObjects++;
+		
+			// Add a new tObject node to our list of objects (like a link list)
+			pModel->pObject.push_back(newObject);
+			
+			// Initialize the object and all it's data members
+			memset(&(pModel->pObject[pModel->numOfObjects - 1]), 0, sizeof(t3dObject));
+
+			// Get the name of the object and store it, then add the read bytes to our byte counter.
+			currentChunk.bytesRead += GetString(pModel->pObject[pModel->numOfObjects - 1].strName);
+			
+			// Now proceed to read in the rest of the object information
+			ProcessNextObjectChunk(pModel, &(pModel->pObject[pModel->numOfObjects - 1]), &currentChunk);
+			break;
+
+		case EDITKEYFRAME:
+
+			// Because I wanted to make this a SIMPLE tutorial as possible, I did not include
+			// the key frame information.  This chunk is the header for all the animation info.
+			// In a later tutorial this will be the subject and explained thoroughly.
+
+			//ProcessNextKeyFrameChunk(pModel, currentChunk);
+
+			// Read past this chunk and add the bytes read to the byte counter
+			currentChunk.bytesRead += fread(gBuffer, 1, currentChunk.length - currentChunk.bytesRead, m_FilePointer);
+			break;
+
+		default: 
+			
+			// If we didn't care about a chunk, then we get here.  We still need
+			// to read past the unknown or ignored chunk and add the bytes read to the byte counter.
+			currentChunk.bytesRead += fread(gBuffer, 1, currentChunk.length - currentChunk.bytesRead, m_FilePointer);
+			break;
+		}
+
+		// Add the bytes read from the last chunk to the previous chunk passed in.
+		pPreviousChunk->bytesRead += currentChunk.bytesRead;
+	}
+}
+
+
+///////////////////////////////// PROCESS NEXT OBJECT CHUNK \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+/////
+/////	This function handles all the information about the objects in the file
+/////
+///////////////////////////////// PROCESS NEXT OBJECT CHUNK \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+
+void CLoad3ds::ProcessNextObjectChunk(C3dModel *pModel, t3dObject *pObject, tChunk *pPreviousChunk)
+{
+	// The current chunk to work with
+	tChunk currentChunk = {0};
+
+	// Continue to read these chunks until we read the end of this sub chunk
+	while (pPreviousChunk->bytesRead < pPreviousChunk->length)
+	{
+		// Read the next chunk
+		ReadChunk(&currentChunk);
+
+		// Check which chunk we just read
+		switch (currentChunk.ID)
+		{
+		case OBJECT_MESH:					// This lets us know that we are reading a new object
+		
+			// We found a new object, so let's read in it's info using recursion
+			ProcessNextObjectChunk(pModel, pObject, &currentChunk);
+			break;
+
+		case OBJECT_VERTICES:				// This is the objects vertices
+			ReadVertices(pObject, &currentChunk);
+			break;
+
+		case OBJECT_FACES:					// This is the objects face information
+			ReadVertexIndices(pObject, &currentChunk);
+			break;
+
+		case OBJECT_MATERIAL:				// This holds the material name that the object has
+			
+			// This chunk holds the name of the material that the object has assigned to it.
+			// This could either be just a color or a texture map.  This chunk also holds
+			// the faces that the texture is assigned to (In the case that there is multiple
+			// textures assigned to one object, or it just has a texture on a part of the object.
+			// Since most of my game objects just have the texture around the whole object, and 
+			// they aren't multitextured, I just want the material name.
+
+			// We now will read the name of the material assigned to this object
+			ReadObjectMaterial(pModel, pObject, &currentChunk);			
+			break;
+
+		case OBJECT_UV:						// This holds the UV texture coordinates for the object
+
+			// This chunk holds all of the UV coordinates for our object.  Let's read them in.
+			ReadUVCoordinates(pObject, &currentChunk);
+			break;
+
+		default:  
+
+			// Read past the ignored or unknown chunks
+			currentChunk.bytesRead += fread(gBuffer, 1, currentChunk.length - currentChunk.bytesRead, m_FilePointer);
+			break;
+		}
+
+		// Add the bytes read from the last chunk to the previous chunk passed in.
+		pPreviousChunk->bytesRead += currentChunk.bytesRead;
+	}
+}
+
+
+///////////////////////////////// PROCESS NEXT MATERIAL CHUNK \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+/////
+/////	This function handles all the information about the material (Texture)
+/////
+///////////////////////////////// PROCESS NEXT MATERIAL CHUNK \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+
+void CLoad3ds::ProcessNextMaterialChunk(C3dModel *pModel, tChunk *pPreviousChunk)
+{
+	// The current chunk to work with
+	tChunk currentChunk = {0};
+
+	// Continue to read these chunks until we read the end of this sub chunk
+	while (pPreviousChunk->bytesRead < pPreviousChunk->length)
+	{
+		// Read the next chunk
+		ReadChunk(&currentChunk);
+
+		// Check which chunk we just read in
+		switch (currentChunk.ID)
+		{
+		case MATNAME:							// This chunk holds the name of the material
+			
+			// Here we read in the material name
+			currentChunk.bytesRead += fread(pModel->pMaterials[pModel->numOfMaterials - 1].strName, 1, currentChunk.length - currentChunk.bytesRead, m_FilePointer);
+			break;
+
+		case MATDIFFUSE:						// This holds the R G B color of our object
+			ReadColorChunk(&(pModel->pMaterials[pModel->numOfMaterials - 1]), &currentChunk);
+			break;
+		
+		case MATMAP:							// This is the header for the texture info
+			
+			// Proceed to read in the material information
+			ProcessNextMaterialChunk(pModel, &currentChunk);
+			break;
+
+		case MATMAPFILE:						// This stores the file name of the material
+
+			// Here we read in the material's file name
+			currentChunk.bytesRead += fread(pModel->pMaterials[pModel->numOfMaterials - 1].strFile, 1, currentChunk.length - currentChunk.bytesRead, m_FilePointer);
+			break;
+		
+		default:  
+
+			// Read past the ignored or unknown chunks
+			currentChunk.bytesRead += fread(gBuffer, 1, currentChunk.length - currentChunk.bytesRead, m_FilePointer);
+			break;
+		}
+
+		// Add the bytes read from the last chunk to the previous chunk passed in.
+		pPreviousChunk->bytesRead += currentChunk.bytesRead;
+	}
+}
+
+///////////////////////////////// READ CHUNK \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+/////
+/////	This function reads in a chunk ID and it's length in bytes
+/////
+///////////////////////////////// READ CHUNK \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+
+void CLoad3ds::ReadChunk(tChunk *pChunk)
+{
+	// This reads the chunk ID which is 2 bytes.
+	// The chunk ID is like OBJECT or MATERIAL.  It tells what data is
+	// able to be read in within the chunks section.  
+	pChunk->bytesRead = fread(&pChunk->ID, 1, 2, m_FilePointer);
+
+	// Then, we read the length of the chunk which is 4 bytes.
+	// This is how we know how much to read in, or read past.
+	pChunk->bytesRead += fread(&pChunk->length, 1, 4, m_FilePointer);
+}
+
+///////////////////////////////// GET STRING \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+/////
+/////	This function reads in a string of characters
+/////
+///////////////////////////////// GET STRING \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+
+int CLoad3ds::GetString(char *pBuffer)
+{
+	int index = 0;
+
+	// Read 1 byte of data which is the first letter of the string
+	fread(pBuffer, 1, 1, m_FilePointer);
+
+	// Loop until we get NULL
+	while (*(pBuffer + index++) != 0) {
+
+		// Read in a character at a time until we hit NULL.
+		fread(pBuffer + index, 1, 1, m_FilePointer);
+	}
+
+	// Return the string length, which is how many bytes we read in (including the NULL)
+	return strlen(pBuffer) + 1;
+}
+
+
+///////////////////////////////// READ COLOR \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+/////
+/////	This function reads in the RGB color data
+/////
+///////////////////////////////// READ COLOR \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+
+void CLoad3ds::ReadColorChunk(tMaterialInfo *pMaterial, tChunk *pChunk)
+{
+	tChunk tempChunk = {0};
+
+	// Read the color chunk info
+	ReadChunk(&tempChunk);
+
+	// Read in the R G B color (3 bytes - 0 through 255)
+	tempChunk.bytesRead += fread(pMaterial->color, 1, tempChunk.length - tempChunk.bytesRead, m_FilePointer);
+
+	// Add the bytes read to our chunk
+	pChunk->bytesRead += tempChunk.bytesRead;
+}
+
+
+///////////////////////////////// READ VERTEX INDECES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+/////
+/////	This function reads in the indices for the vertex array
+/////
+///////////////////////////////// READ VERTEX INDECES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+
+void CLoad3ds::ReadVertexIndices(t3dObject *pObject, tChunk *pPreviousChunk)
+{
+	unsigned short index = 0;					// This is used to read in the current face index
+
+	// In order to read in the vertex indices for the object, we need to first
+	// read in the number of them, then read them in.  Remember,
+	// we only want 3 of the 4 values read in for each face.  The fourth is
+	// a visibility flag for 3D Studio Max that doesn't mean anything to us.
+
+	// Read in the number of faces that are in this object (int)
+	pPreviousChunk->bytesRead += fread(&pObject->iNumOfFaces, 1, 2, m_FilePointer);
+
+	// Alloc enough memory for the faces and initialize the structure
+	pObject->pFaces = new tFace [pObject->iNumOfFaces];
+	memset(pObject->pFaces, 0, sizeof(tFace) * pObject->iNumOfFaces);
+
+	// Go through all of the faces in this object
+	for(int i = 0; i < pObject->iNumOfFaces; i++)
+	{
+		// Next, we read in the A then B then C index for the face, but ignore the 4th value.
+		// The fourth value is a visibility flag for 3D Studio Max, we don't care about this.
+		for(int j = 0; j < 4; j++)
+		{
+			// Read the first vertice index for the current face 
+			pPreviousChunk->bytesRead += fread(&index, 1, sizeof(index), m_FilePointer);
+
+			if(j < 3)
+			{
+				// Store the index in our face structure.
+				pObject->pFaces[i].vertIndex[j] = index;
+			}
+		}
+	}
+}
+
+
+///////////////////////////////// READ UV COORDINATES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+/////
+/////	This function reads in the UV coordinates for the object
+/////
+///////////////////////////////// READ UV COORDINATES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+
+void CLoad3ds::ReadUVCoordinates(t3dObject *pObject, tChunk *pPreviousChunk)
+{
+	// In order to read in the UV indices for the object, we need to first
+	// read in the amount there are, then read them in.
+
+	// Read in the number of UV coordinates there are (int)
+	pPreviousChunk->bytesRead += fread(&pObject->iNumTexVertex, 1, 2, m_FilePointer);
+
+	// Allocate memory to hold the UV coordinates
+	pObject->pTexVerts = new CVector2 [pObject->iNumTexVertex];
+
+	// Read in the texture coodinates (an array 2 float)
+	pPreviousChunk->bytesRead += fread(pObject->pTexVerts, 1, pPreviousChunk->length - pPreviousChunk->bytesRead, m_FilePointer);
+}
+
+
+///////////////////////////////// READ VERTICES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+/////
+/////	This function reads in the vertices for the object
+/////
+///////////////////////////////// READ VERTICES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+
+void CLoad3ds::ReadVertices(t3dObject *pObject, tChunk *pPreviousChunk)
+{
+	// Like most chunks, before we read in the actual vertices, we need
+	// to find out how many there are to read in.  Once we have that number
+	// we then fread() them into our vertice array.
+
+	// Read in the number of vertices (int)
+	pPreviousChunk->bytesRead += fread(&(pObject->iNumOfVerts), 1, 2, m_FilePointer);
+
+	// Allocate the memory for the verts and initialize the structure
+	pObject->pVerts = new CVector3 [pObject->iNumOfVerts];
+	memset(pObject->pVerts, 0, sizeof(CVector3) * pObject->iNumOfVerts);
+
+	// Read in the array of vertices (an array of 3 floats)
+	pPreviousChunk->bytesRead += fread(pObject->pVerts, 1, pPreviousChunk->length - pPreviousChunk->bytesRead, m_FilePointer);
+
+	// Now we should have all of the vertices read in.  Because 3D Studio Max
+	// Models with the Z-Axis pointing up (strange and ugly I know!), we need
+	// to flip the y values with the z values in our vertices.  That way it
+	// will be normal, with Y pointing up.  If you prefer to work with Z pointing
+	// up, then just delete this next loop.  Also, because we swap the Y and Z
+	// we need to negate the Z to make it come out correctly.
+
+	// Go through all of the vertices that we just read and swap the Y and Z values
+	for(int i = 0; i < pObject->iNumOfVerts; i++)
+	{
+		// Store off the Y value
+		float fTempY = pObject->pVerts[i].y;
+
+		// Set the Y value to the Z value
+		pObject->pVerts[i].y = pObject->pVerts[i].z;
+
+		// Set the Z value to the Y value, 
+		// but negative Z because 3D Studio max does the opposite.
+		pObject->pVerts[i].z = -fTempY;
+	}
+}
+
+
+///////////////////////////////// READ OBJECT MATERIAL \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+/////
+/////	This function reads in the material name assigned to the object and sets the materialID
+/////
+///////////////////////////////// READ OBJECT MATERIAL \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+
+void CLoad3ds::ReadObjectMaterial(C3dModel *pModel, t3dObject *pObject, tChunk *pPreviousChunk)
+{
+	char strMaterial[255] = {0};			// This is used to hold the objects material name
+
+	// *What is a material?*  - A material is either the color or the texture map of the object.
+	// It can also hold other information like the brightness, shine, etc... Stuff we don't
+	// really care about.  We just want the color, or the texture map file name really.
+
+	// Here we read the material name that is assigned to the current object.
+	// strMaterial should now have a string of the material name, like "Material #2" etc..
+	pPreviousChunk->bytesRead += GetString(strMaterial);
+
+	// Now that we have a material name, we need to go through all of the materials
+	// and check the name against each material.  When we find a material in our material
+	// list that matches this name we just read in, then we assign the materialID
+	// of the object to that material index.  You will notice that we passed in the
+	// model to this function.  This is because we need the number of textures.
+	// Yes though, we could have just passed in the model and not the object too.
+
+	// Go through all of the textures
+	for(int i = 0; i < pModel->numOfMaterials; i++)
+	{
+		// If the material we just read in matches the current texture name
+		if(strcmp(strMaterial, pModel->pMaterials[i].strName) == 0)
+		{
+			// Set the material ID to the current index 'i' and stop checking
+			pObject->materialID = i;
+
+			// Now that we found the material, check if it's a texture map.
+			// If the strFile has a string length of 1 and over it's a texture
+			if(strlen(pModel->pMaterials[i].strFile) > 0) {
+
+				// Set the object's flag to say it has a texture map to bind.
+				pObject->bHasTexture = true;
+			}	
+			break;
+		}
+		else
+		{
+			// Set the ID to -1 to show there is no material for this object
+			pObject->materialID = -1;
+		}
+	}
+
+	// Read past the rest of the chunk since we don't care about shared vertices
+	// You will notice we subtract the bytes already read in this chunk from the total length.
+	pPreviousChunk->bytesRead += fread(gBuffer, 1, pPreviousChunk->length - pPreviousChunk->bytesRead, m_FilePointer);
+}			
+
+// *Note* 
+//
+// Below are some math functions for calculating vertex normals.  We want vertex normals
+// because it makes the lighting look really smooth and life like.  You probably already
+// have these functions in the rest of your engine, so you can delete these and call
+// your own.  I wanted to add them so I could show how to calculate vertex normals.
+
+//////////////////////////////	Math Functions  ////////////////////////////////*
+
+// This computes the magnitude of a normal.   (magnitude = sqrt(x^2 + y^2 + z^2)
+#define Mag(Normal) (sqrt(Normal.x*Normal.x + Normal.y*Normal.y + Normal.z*Normal.z))
+
+// This calculates a vector between 2 points and returns the result
+CVector3 Vector(CVector3 vPoint1, CVector3 vPoint2)
+{
+	CVector3 vVector;							// The variable to hold the resultant vector
+
+	vVector.x = vPoint1.x - vPoint2.x;			// Subtract point1 and point2 x's
+	vVector.y = vPoint1.y - vPoint2.y;			// Subtract point1 and point2 y's
+	vVector.z = vPoint1.z - vPoint2.z;			// Subtract point1 and point2 z's
+
+	return vVector;								// Return the resultant vector
+}
+
+// This adds 2 vectors together and returns the result
+CVector3 AddVector(CVector3 vVector1, CVector3 vVector2)
+{
+	CVector3 vResult;							// The variable to hold the resultant vector
+	
+	vResult.x = vVector2.x + vVector1.x;		// Add Vector1 and Vector2 x's
+	vResult.y = vVector2.y + vVector1.y;		// Add Vector1 and Vector2 y's
+	vResult.z = vVector2.z + vVector1.z;		// Add Vector1 and Vector2 z's
+
+	return vResult;								// Return the resultant vector
+}
+
+// This divides a vector by a single number (scalar) and returns the result
+CVector3 DivideVectorByScaler(CVector3 vVector1, float Scaler)
+{
+	CVector3 vResult;							// The variable to hold the resultant vector
+	
+	vResult.x = vVector1.x / Scaler;			// Divide Vector1's x value by the scaler
+	vResult.y = vVector1.y / Scaler;			// Divide Vector1's y value by the scaler
+	vResult.z = vVector1.z / Scaler;			// Divide Vector1's z value by the scaler
+
+	return vResult;								// Return the resultant vector
+}
+
+// This returns the cross product between 2 vectors
+CVector3 Cross(CVector3 vVector1, CVector3 vVector2)
+{
+	CVector3 vCross;								// The vector to hold the cross product
+												// Get the X value
+	vCross.x = ((vVector1.y * vVector2.z) - (vVector1.z * vVector2.y));
+												// Get the Y value
+	vCross.y = ((vVector1.z * vVector2.x) - (vVector1.x * vVector2.z));
+												// Get the Z value
+	vCross.z = ((vVector1.x * vVector2.y) - (vVector1.y * vVector2.x));
+
+	return vCross;								// Return the cross product
+}
+
+// This returns the normal of a vector
+CVector3 Normalize(CVector3 vNormal)
+{
+	double Magnitude;							// This holds the magitude			
+
+	Magnitude = Mag(vNormal);					// Get the magnitude
+
+	vNormal.x /= (float)Magnitude;				// Divide the vector's X by the magnitude
+	vNormal.y /= (float)Magnitude;				// Divide the vector's Y by the magnitude
+	vNormal.z /= (float)Magnitude;				// Divide the vector's Z by the magnitude
+
+	return vNormal;								// Return the normal
+}
+
+///////////////////////////////// COMPUTER NORMALS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+/////
+/////	This function computes the normals and vertex normals of the objects
+/////
+///////////////////////////////// COMPUTER NORMALS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
+
+void CLoad3ds::ComputeNormals(C3dModel *pModel)
+{
+	CVector3 vVector1, vVector2, vNormal, vPoly[3];
+
+	// If there are no objects, we can skip this part
+	if(pModel->numOfObjects <= 0)
+		return;
+
+	// What are vertex normals?  And how are they different from other normals?
+	// Well, if you find the normal to a triangle, you are finding a "Face Normal".
+	// If you give OpenGL a face normal for lighting, it will make your object look
+	// really flat and not very round.  If we find the normal for each vertex, it makes
+	// the smooth lighting look.  This also covers up blocky looking objects and they appear
+	// to have more polygons than they do.    Basically, what you do is first
+	// calculate the face normals, then you take the average of all the normals around each
+	// vertex.  It's just averaging.  That way you get a better approximation for that vertex.
+
+	// Go through each of the objects to calculate their normals
+	for(int index = 0; index < pModel->numOfObjects; index++)
+	{
+		// Get the current object
+		t3dObject *pObject = &(pModel->pObject[index]);
+
+		// Here we allocate all the memory we need to calculate the normals
+		CVector3 *pNormals		= new CVector3 [pObject->iNumOfFaces];
+		CVector3 *pTempNormals	= new CVector3 [pObject->iNumOfFaces];
+		pObject->pNormals		= new CVector3 [pObject->iNumOfVerts];
+
+		// Go though all of the faces of this object
+		for(int i=0; i < pObject->iNumOfFaces; i++)
+		{												
+			// To cut down LARGE code, we extract the 3 points of this face
+			vPoly[0] = pObject->pVerts[pObject->pFaces[i].vertIndex[0]];
+			vPoly[1] = pObject->pVerts[pObject->pFaces[i].vertIndex[1]];
+			vPoly[2] = pObject->pVerts[pObject->pFaces[i].vertIndex[2]];
+
+			// Now let's calculate the face normals (Get 2 vectors and find the cross product of those 2)
+
+			vVector1 = Vector(vPoly[0], vPoly[2]);		// Get the vector of the polygon (we just need 2 sides for the normal)
+			vVector2 = Vector(vPoly[2], vPoly[1]);		// Get a second vector of the polygon
+
+			vNormal  = Cross(vVector1, vVector2);		// Return the cross product of the 2 vectors (normalize vector, but not a unit vector)
+			pTempNormals[i] = vNormal;					// Save the un-normalized normal for the vertex normals
+			vNormal  = Normalize(vNormal);				// Normalize the cross product to give us the polygons normal
+
+			pNormals[i] = vNormal;						// Assign the normal to the list of normals
+		}
+
+		//////////////// Now Get The Vertex Normals /////////////////
+
+		CVector3 vSum = {0.0, 0.0, 0.0};
+		CVector3 vZero = vSum;
+		int shared=0;
+
+		for (int i = 0; i < pObject->iNumOfVerts; i++)			// Go through all of the vertices
+		{
+			for (int j = 0; j < pObject->iNumOfFaces; j++)	// Go through all of the triangles
+			{												// Check if the vertex is shared by another face
+				if (pObject->pFaces[j].vertIndex[0] == i || 
+					pObject->pFaces[j].vertIndex[1] == i || 
+					pObject->pFaces[j].vertIndex[2] == i)
+				{
+					vSum = AddVector(vSum, pTempNormals[j]);// Add the un-normalized normal of the shared face
+					shared++;								// Increase the number of shared triangles
+				}
+			}      
+			
+			// Get the normal by dividing the sum by the shared.  We negate the shared so it has the normals pointing out.
+			pObject->pNormals[i] = DivideVectorByScaler(vSum, float(-shared));
+
+			// Normalize the normal for the final vertex normal
+			pObject->pNormals[i] = Normalize(pObject->pNormals[i]);	
+
+			vSum = vZero;									// Reset the sum
+			shared = 0;										// Reset the shared
+		}
+	
+		// Free our memory and start over on the next object
+		delete [] pTempNormals;
+		delete [] pNormals;
+	}
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////
+//
+// * QUICK NOTES * 
+//
+// This was a HUGE amount of knowledge and probably the largest tutorial yet!
+// In the next tutorial we will show you how to load a text file format called .obj.
+// This is the most common 3D file format that almost ANY 3D software will import.
+//
+// Once again I should point out that the coordinate system of OpenGL and 3DS Max are different.
+// Since 3D Studio Max Models with the Z-Axis pointing up (strange and ugly I know! :), 
+// we need to flip the y values with the z values in our vertices.  That way it
+// will be normal, with Y pointing up.  Also, because we swap the Y and Z we need to negate 
+// the Z to make it come out correctly.  This is also explained and done in ReadVertices().
+//
+// CHUNKS: What is a chunk anyway?
+// 
+// "The chunk ID is a unique code which identifies the type of data in this chunk 
+// and also may indicate the existence of subordinate chunks. The chunk length indicates 
+// the length of following data to be associated with this chunk. Note, this may 
+// contain more data than just this chunk. If the length of data is greater than that 
+// needed to fill in the information for the chunk, additional subordinate chunks are 
+// attached to this chunk immediately following any data needed for this chunk, and 
+// should be parsed out. These subordinate chunks may themselves contain subordinate chunks. 
+// Unfortunately, there is no indication of the length of data, which is owned by the current 
+// chunk, only the total length of data attached to the chunk, which means that the only way 
+// to parse out subordinate chunks is to know the exact format of the owning chunk. On the 
+// other hand, if a chunk is unknown, the parsing program can skip the entire chunk and 
+// subordinate chunks in one jump. " - Jeff Lewis (werewolf@worldgate.com)
+//
+// In a short amount of words, a chunk is defined this way:
+// 2 bytes - Stores the chunk ID (OBJECT, MATERIAL, PRIMARY, etc...)
+// 4 bytes - Stores the length of that chunk.  That way you know when that
+//           chunk is done and there is a new chunk.
+//
+// So, to start reading the 3DS file, you read the first 2 bytes of it, then
+// the length (using fread()).  It should be the PRIMARY chunk, otherwise it isn't
+// a .3DS file.  
+//
+// Below is a list of the order that you will find the chunks and all the know chunks.
+// If you go to www.wosit.org you can find a few documents on the 3DS file format.
+// You can also take a look at the 3DS Format.rtf that is included with this tutorial.
+//
+//
+//
+//      MAIN3DS  (0x4D4D)
+//     |
+//     +--EDIT3DS  (0x3D3D)
+//     |  |
+//     |  +--EDIT_MATERIAL (0xAFFF)
+//     |  |  |
+//     |  |  +--MAT_NAME01 (0xA000) (See mli Doc) 
+//     |  |
+//     |  +--EDIT_CONFIG1  (0x0100)
+//     |  +--EDIT_CONFIG2  (0x3E3D) 
+//     |  +--EDIT_VIEW_P1  (0x7012)
+//     |  |  |
+//     |  |  +--TOP            (0x0001)
+//     |  |  +--BOTTOM         (0x0002)
+//     |  |  +--LEFT           (0x0003)
+//     |  |  +--RIGHT          (0x0004)
+//     |  |  +--FRONT          (0x0005) 
+//     |  |  +--BACK           (0x0006)
+//     |  |  +--USER           (0x0007)
+//     |  |  +--CAMERA         (0xFFFF)
+//     |  |  +--LIGHT          (0x0009)
+//     |  |  +--DISABLED       (0x0010)  
+//     |  |  +--BOGUS          (0x0011)
+//     |  |
+//     |  +--EDIT_VIEW_P2  (0x7011)
+//     |  |  |
+//     |  |  +--TOP            (0x0001)
+//     |  |  +--BOTTOM         (0x0002)
+//     |  |  +--LEFT           (0x0003)
+//     |  |  +--RIGHT          (0x0004)
+//     |  |  +--FRONT          (0x0005) 
+//     |  |  +--BACK           (0x0006)
+//     |  |  +--USER           (0x0007)
+//     |  |  +--CAMERA         (0xFFFF)
+//     |  |  +--LIGHT          (0x0009)
+//     |  |  +--DISABLED       (0x0010)  
+//     |  |  +--BOGUS          (0x0011)
+//     |  |
+//     |  +--EDIT_VIEW_P3  (0x7020)
+//     |  +--EDIT_VIEW1    (0x7001) 
+//     |  +--EDIT_BACKGR   (0x1200) 
+//     |  +--EDIT_AMBIENT  (0x2100)
+//     |  +--EDIT_OBJECT   (0x4000)
+//     |  |  |
+//     |  |  +--OBJ_TRIMESH   (0x4100)      
+//     |  |  |  |
+//     |  |  |  +--TRI_VERTEXL          (0x4110) 
+//     |  |  |  +--TRI_VERTEXOPTIONS    (0x4111)
+//     |  |  |  +--TRI_MAPPINGCOORS     (0x4140) 
+//     |  |  |  +--TRI_MAPPINGSTANDARD  (0x4170)
+//     |  |  |  +--TRI_FACEL1           (0x4120)
+//     |  |  |  |  |
+//     |  |  |  |  +--TRI_SMOOTH            (0x4150)   
+//     |  |  |  |  +--TRI_MATERIAL          (0x4130)
+//     |  |  |  |
+//     |  |  |  +--TRI_LOCAL            (0x4160)
+//     |  |  |  +--TRI_VISIBLE          (0x4165)
+//     |  |  |
+//     |  |  +--OBJ_LIGHT    (0x4600)
+//     |  |  |  |
+//     |  |  |  +--LIT_OFF              (0x4620)
+//     |  |  |  +--LIT_SPOT             (0x4610) 
+//     |  |  |  +--LIT_UNKNWN01         (0x465A) 
+//     |  |  | 
+//     |  |  +--OBJ_CAMERA   (0x4700)
+//     |  |  |  |
+//     |  |  |  +--CAM_UNKNWN01         (0x4710)
+//     |  |  |  +--CAM_UNKNWN02         (0x4720)  
+//     |  |  |
+//     |  |  +--OBJ_UNKNWN01 (0x4710)
+//     |  |  +--OBJ_UNKNWN02 (0x4720)
+//     |  |
+//     |  +--EDIT_UNKNW01  (0x1100)
+//     |  +--EDIT_UNKNW02  (0x1201) 
+//     |  +--EDIT_UNKNW03  (0x1300)
+//     |  +--EDIT_UNKNW04  (0x1400)
+//     |  +--EDIT_UNKNW05  (0x1420)
+//     |  +--EDIT_UNKNW06  (0x1450)
+//     |  +--EDIT_UNKNW07  (0x1500)
+//     |  +--EDIT_UNKNW08  (0x2200)
+//     |  +--EDIT_UNKNW09  (0x2201)
+//     |  +--EDIT_UNKNW10  (0x2210)
+//     |  +--EDIT_UNKNW11  (0x2300)
+//     |  +--EDIT_UNKNW12  (0x2302)
+//     |  +--EDIT_UNKNW13  (0x2000)
+//     |  +--EDIT_UNKNW14  (0xAFFF)
+//     |
+//     +--KEYF3DS (0xB000)
+//        |
+//        +--KEYF_UNKNWN01 (0xB00A)
+//        +--............. (0x7001) ( viewport, same as editor )
+//        +--KEYF_FRAMES   (0xB008)
+//        +--KEYF_UNKNWN02 (0xB009)
+//        +--KEYF_OBJDES   (0xB002)
+//           |
+//           +--KEYF_OBJHIERARCH  (0xB010)
+//           +--KEYF_OBJDUMMYNAME (0xB011)
+//           +--KEYF_OBJUNKNWN01  (0xB013)
+//           +--KEYF_OBJUNKNWN02  (0xB014)
+//           +--KEYF_OBJUNKNWN03  (0xB015)  
+//           +--KEYF_OBJPIVOT     (0xB020)  
+//           +--KEYF_OBJUNKNWN04  (0xB021)  
+//           +--KEYF_OBJUNKNWN05  (0xB022)  
+//
+// Once you know how to read chunks, all you have to know is the ID you are looking for
+// and what data is stored after that ID.  You need to get the file format for that.
+// I can give it to you if you want, or you can go to www.wosit.org for several versions.
+// Because this is a proprietary format, it isn't a official document.
+//
+// I know there was a LOT of information blown over, but it is too much knowledge for
+// one tutorial.  In the animation tutorial that I eventually will get to, some of
+// the things explained here will be explained in more detail.  I do not claim that
+// this is the best .3DS tutorial, or even a GOOD one :)  But it is a good start, and there
+// isn't much code out there that is simple when it comes to reading .3DS files.
+// So far, this is the best I have seen.  That is why I made it :)
+// 
+// I would like to thank www.wosit.org and Terry Caton (tcaton@umr.edu) for his help on this.
+//
+// Let me know if this helps you out!
+// 
+// 
+// Ben Humphrey (DigiBen)
+// Game Programmer
+// DigiBen@GameTutorials.com
+// Co-Web Host of www.GameTutorials.com
+//
+//
Index: /orxonox/branches/john/src/3ds.h
===================================================================
--- /orxonox/branches/john/src/3ds.h	(revision 2035)
+++ /orxonox/branches/john/src/3ds.h	(revision 2035)
@@ -0,0 +1,113 @@
+#ifndef _3DS_H
+#define _3DS_H
+
+//>------ Primary Chunk, at the beginning of each file
+#define PRIMARY       0x4D4D
+
+//>------ Main Chunks
+#define OBJECTINFO    0x3D3D				// This gives the version of the mesh and is found right before the material and object information
+#define VERSION       0x0002				// This gives the version of the .3ds file
+#define EDITKEYFRAME  0xB000				// This is the header for all of the key frame info
+
+//>------ sub defines of OBJECTINFO
+#define MATERIAL	  0xAFFF				// This stored the texture info
+#define OBJECT		  0x4000				// This stores the faces, vertices, etc...
+
+//>------ sub defines of MATERIAL
+#define MATNAME       0xA000				// This holds the material name
+#define MATDIFFUSE    0xA020				// This holds the color of the object/material
+#define MATMAP        0xA200				// This is a header for a new material
+#define MATMAPFILE    0xA300				// This holds the file name of the texture
+
+#define OBJECT_MESH   0x4100				// This lets us know that we are reading a new object
+
+//>------ sub defines of OBJECT_MESH
+#define OBJECT_VERTICES     0x4110			// The objects vertices
+#define OBJECT_FACES		0x4120			// The objects faces
+#define OBJECT_MATERIAL		0x4130			// This is found if the object has a material, either texture map or color
+#define OBJECT_UV			0x4140			// The UV texture coordinates
+
+#include "3dStructs.h"
+
+// Here is our structure for our 3DS indicies (since .3DS stores 4 unsigned shorts)
+struct tIndices {							
+
+	unsigned short a, b, c, bVisible;		// This will hold point1, 2, and 3 index's into the vertex array plus a visible flag
+};
+
+// This holds the chunk info
+struct tChunk
+{
+	unsigned short int ID;					// The chunk's ID		
+	unsigned int length;					// The length of the chunk
+	unsigned int bytesRead;					// The amount of bytes read within that chunk
+};
+
+// This class handles all of the loading code
+class CLoad3ds
+{
+public:
+	CLoad3ds();								// This inits the data members
+
+	// This is the function that you call to load the 3DS
+	bool Import3DS(C3dModel *pModel, char *strFileName);
+
+private:
+	// This reads in a string and saves it in the char array passed in
+	int GetString(char *);
+
+	// This reads the next chunk
+	void ReadChunk(tChunk *);
+
+	// This reads the next large chunk
+	void ProcessNextChunk(C3dModel *pModel, tChunk *);
+
+	// This reads the object chunks
+	void ProcessNextObjectChunk(C3dModel *pModel, t3dObject *pObject, tChunk *);
+
+	// This reads the material chunks
+	void ProcessNextMaterialChunk(C3dModel *pModel, tChunk *);
+
+	// This reads the RGB value for the object's color
+	void ReadColorChunk(tMaterialInfo *pMaterial, tChunk *pChunk);
+
+	// This reads the objects vertices
+	void ReadVertices(t3dObject *pObject, tChunk *);
+
+	// This reads the objects face information
+	void ReadVertexIndices(t3dObject *pObject, tChunk *);
+
+	// This reads the texture coodinates of the object
+	void ReadUVCoordinates(t3dObject *pObject, tChunk *);
+
+	// This reads in the material name assigned to the object and sets the materialID
+	void ReadObjectMaterial(C3dModel *pModel, t3dObject *pObject, tChunk *pPreviousChunk);
+	
+	// This computes the vertex normals for the object (used for lighting)
+	void ComputeNormals(C3dModel *pModel);
+
+	// This frees memory and closes the file
+	void CleanUp();
+	
+	// The file pointer
+	FILE *m_FilePointer;
+};
+
+
+#endif
+
+
+/////////////////////////////////////////////////////////////////////////////////
+//
+// * QUICK NOTES * 
+// 
+// This file is created in the hopes that you can just plug it into your code
+// easily.  You will probably want to query more chunks though for animation, etc..
+//
+// 
+// Ben Humphrey (DigiBen)
+// Game Programmer
+// DigiBen@GameTutorials.com
+// Co-Web Host of www.GameTutorials.com
+//
+//
