#include "OBJModel.h"
//#include "ImageLoader.h"


///////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *
//
//// To allow volumetric fog, we need to add some EXT defines and a typedef
//
////These are the defines for the flags that are passed into glFogi()
//#define GL_FOG_COORDINATE_SOURCE_EXT			0x8450
//#define GL_FOG_COORDINATE_EXT					0x8451
//
////// This stores the desired depth that we want to fog
//float g_FogDepth = 50.0f;
////
////// Here we extern our function pointer for volumetric fog positioning
////typedef void (APIENTRY * PFNGLFOGCOORDFEXTPROC) (GLfloat coord);
////
//// This is our fog extension function pointer to set a vertice's depth
//PFNGLFOGCOORDFEXTPROC glFogCoordfEXT = NULL;
//
////
//// Building off of the detail texturing tutorial, we add some awesome volumetric
//// fog using the OpenGL extension: glFogCoordfEXT().
//// 
//// This allows us to do volumetric fog without extra passes, and we are able
//// to effect the fog dynamically, as you will see in the application by the +/- keys.
//// The effect brings an incredible amount of realism to a scene and is a must
//// have in any engine. 
////
//// We add a new function to this file:  SetFogCoord(), which takes a depth
//// for the fog, and the current y value of the vertex having fog applied to it.
//// The volumetric fog is not actually a volume fog, but is a trick that changes
//// the color of the polygons to give the appearance of fog.
////
////
//
///////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *


// OPEN GL EXTENSIONS
//static PFNGLACTIVETEXTUREARBPROC glActiveTexture;
//static PFNGLLOCKARRAYSEXTPROC glLockArrays;
//static PFNGLUNLOCKARRAYSEXTPROC glUnlockArrays;


//////////////////////////////////////////////////////////////////////
// Constructor: Layout                                              //
// 1 - Open the file specified in params                            //
// 2 - Count and read the Vertex Coords("v x y z")                  // 
// 3 - Count and read the Texture Coords("vt u v")                  //
// 4 - Count and read the Normal Coords("vn i j k")                 //
// 5 - Count and read the Face Data("f v/vt/vn v/vt/vn v/vt/vn")    //
// 6 - Count the Materials used and the face they appear at         //
//////////////////////////////////////////////////////////////////////
COBJModel::COBJModel(){
	numVertices=0;
	numFaces=0;
	numNormals=0;
	numTextureCoords=0;
	texsUsed=0;

//	//initialize fog stuff
///////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *
//
//	// If we have loaded the mulitextures correctly, then we can now test to see
//	// if the video card supports hardware accelerated fog.  We do the same things
//	// for every extension.  First we tell wglGetProcAddress() which extension
//	// we want, which then returns a function pointer.  Afterwards, the function
//	// pointer is checked to make sure the current video card drivers or setup
//	// support it.
//
//	// Find the correct function pointer that houses the fog coordinate function
//	glFogCoordfEXT	= (PFNGLFOGCOORDFEXTPROC) wglGetProcAddress("glFogCoordfEXT");
//
//	// Before trying to use this function pointer, we need to make sure it was
//	// given a valid address.  If not, then we need to quit because something is wrong.
//	if(!glFogCoordfEXT)
//	{
//		// Print an error message and quit.
//		MessageBox(NULL, "Your current setup does not support volumetric fog", "Error", MB_OK);
//		PostQuitMessage(0);
//	}
//
//	// It is assumed that by getting here, we should be able to do volumetric fog
//	// with this video card.  Now comes the setup and initialization.  Just like
//	// when we create normal fog, we need to turn on GL_FOG, give a fog color,
//	// as well as give the start and end distance for the thickness of the fog.
//	// The new information that will need to be given will be to glFogi().
//	// The new flags we defined tell OpenGL that we want per vertex fog.
//	// Notice that we don't use GL_FOG_DENSITY.  It doesn't seem to have any effect.
//
//	// Pick a tan color for our fog with a full alpha
//	float fogColor[4] = {0.8f, 0.8f, 0.8f, 1.0f};
//
//	glEnable(GL_FOG);						// Turn on fog
//	glFogi(GL_FOG_MODE, GL_LINEAR);			// Set the fog mode to LINEAR (Important)
//	glFogfv(GL_FOG_COLOR, fogColor);		// Give OpenGL our fog color
//	glFogf(GL_FOG_START, 0.0);				// Set the start position for the depth at 0
//	glFogf(GL_FOG_END, 80.0);				// Set the end position for the detph at 50
//
//	// Now we tell OpenGL that we are using our fog extension for per vertex
//	// fog calculations.  For each vertex that needs fog applied to it we must
//	// use the glFogCoordfEXT() function with a depth value passed in.
//	// These flags are defined in main.h and are not apart of the normal opengl headers.
//	glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
//
//
///////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *
}

void COBJModel::LoadCOBJModel(char *dirname,char *filename){
	// Local Variables
	char *inputBuffer=NULL;
	char tmpBuffer[250];
	float x,y,z,u,v;
	float ni,nj,nk;
	int fa,fb,fc,fd,fe,ff,fg,fh,fi;
	int str;
	FILE *fp;
	// Initialise Some Class Variables
	PALLETEDEXT=0;
	LOCKED=0;
	LOWRES=0;
	UseTextures = 0;
	TexturesLoaded = 0;
	Transparent=0;
	ModelNumber=0;
	inputBuffer = new char[256];	
	inputBuffer[0] = NULL;
	LISTUSED=0;
	OBJDirName = new char[80];
	OBJDirName[0] = '\0';
	ObjectFilename = new char[80];
	//	VTX=0;
	
	// Add the SubDirectory name to the Filename if present
	if(dirname[0] != '\0'){
		strcpy(OBJDirName,dirname);
		sprintf(ObjectFilename,"%s/%s",OBJDirName,filename);
	} else {
		strcpy(ObjectFilename,filename);
	}
	// Load Model from File
	if((fp = fopen(ObjectFilename,"r"))==NULL){
		sprintf(inputBuffer,"Cannot Open 3D Object: \'%s\'",ObjectFilename);
		//MessageBox(NULL,inputBuffer,"Error",MB_OK);
		std::cout << "Error: " << inputBuffer << std::endl;
		numVertices=0;
		numFaces=0;
		numNormals=0;
		numTextureCoords=0;
		return;
	}
	// Create a file buffer of 32kb
	// Cache Buffer (slight speedup)
	char BUFFER[32768];
	setvbuf(fp,BUFFER,_IOFBF,sizeof(BUFFER));
	
	////////////////
	// Read Vertices
	numVertices=0;
	rewind(fp);
	str=1;
	// Count the number of vertex entries in the file
	while(str){
		fgets(inputBuffer, 240, fp);
		if((inputBuffer[0] == 'v')&&
		   (inputBuffer[1] == ' '))
		{
			numVertices++;
		}
		if(feof(fp)!=0){
			str=0;
		}
	}
	//sscanf(inputBuffer,"# %d vertices",&numVertices);
	//MessageBox(NULL,inputBuffer,"Status",MB_OK);
	rewind(fp);
	xVertex = new float[numVertices];
	yVertex = new float[numVertices];
	zVertex = new float[numVertices];
	// Read Vertex Data
	while((inputBuffer[0] != 'v')||(inputBuffer[1] != ' ')){
		fgets(inputBuffer,240,fp);
	}
	for(int i=0;i<numVertices;i++){
		// Parse the line for coord data
		sscanf(inputBuffer," v %f %f %f",&x,&y,&z);
		// Assign Data
		xVertex[i] = x;
		yVertex[i] = y;
		zVertex[i] = z;
		if(i==0){
			Box[0] = x; Box[1] = x; Box[2] = y; Box[3] = y; Box[4] = z; Box[5] = z;   
		}
		// Store BoundingBox Coords (for culling purposes)
		Box[0] = (x<Box[0]) ? x : Box[0];
		Box[1] = (x>Box[1]) ? x : Box[1];
		Box[2] = (y<Box[2]) ? y : Box[2];
		Box[3] = (y>Box[3]) ? y : Box[3];
		Box[4] = (z<Box[4]) ? z : Box[4];
		Box[5] = (z>Box[5]) ? z : Box[5];
		//Read another line of Coords from the file
		fgets(inputBuffer,240,fp);
		while((i+1<numVertices)&&((inputBuffer[0] != 'v')||(inputBuffer[1] != ' '))){
			fgets(inputBuffer,240,fp);
		}
	}
	/////////////////////////
	// Read Texture Coords //
	// if present...       //
	/////////////////////////
	numTextureCoords=0;
	rewind(fp);
	str=1;
	// Count the texture coords in file
	while(str){
		fgets(inputBuffer, 240, fp);
		sscanf(inputBuffer," %s",&tmpBuffer[0]); // Discard Whitespace
		if(strncmp(&tmpBuffer[0],"vt",2)==0){
			numTextureCoords++;
		}
		if(feof(fp)!=0){
			str=0;
		}
	}
	rewind(fp);

	if(numTextureCoords>0){
		uCoord = new float[numTextureCoords];
		vCoord = new float[numTextureCoords];
		// Read Texture Data
		while(strncmp(&tmpBuffer[0],"vt",2)!=0){
			fgets(inputBuffer,240,fp);
			sscanf(inputBuffer," %s",&tmpBuffer[0]); // Discard leading whitespace
		}
		for(int i=0;i<numTextureCoords;i++){
			// Parse the line for coord data
			sscanf(inputBuffer," vt %f %f",&u,&v);
			// Assign Data
			uCoord[i] = u;
			vCoord[i] = v;
			// Find and Read another line of TexCoords from the file
			fgets(inputBuffer,240,fp);
			sscanf(inputBuffer," %s",&tmpBuffer[0]);
			while((i+1<numTextureCoords)&&(strncmp(&tmpBuffer[0],"vt",2)!=0)){
				fgets(inputBuffer,240,fp);
				sscanf(inputBuffer," %s",&tmpBuffer[0]);
			}
		}
	} else {
		uCoord = new float[1];
		vCoord = new float[1];
		uCoord[0] = 0.0f; vCoord[0] = 0.0f; 
	}


	//////////////////
	// Read Normals //
	//////////////////
	numNormals=0;
	rewind(fp);
	str=1;
	// Count the Normals in the file
	while(str){
		fgets(inputBuffer, 240, fp);
		sscanf(inputBuffer," %s",&tmpBuffer[0]); // Discard Whitespace
		if(strncmp(&tmpBuffer[0],"vn",2)==0){
			numNormals++;
		}
		if(feof(fp)!=0){
			str=0;
		}
	}
	rewind(fp);
	if(numNormals>0){
		iNormal = new float[numNormals];
		jNormal = new float[numNormals];
		kNormal = new float[numNormals];
		// Read normal Data
		while(strncmp(&tmpBuffer[0],"vn",2)!=0){
			fgets(inputBuffer,240,fp);
			sscanf(inputBuffer," %s",&tmpBuffer[0]); // Discard Whitespace
		}
		for(int i=0;i<numNormals;i++){
			// Parse the line for normal data
			sscanf(inputBuffer," vn %f %f %f",&ni,&nj,&nk);
			// Assign Data
			iNormal[i] = ni;
			jNormal[i] = nj;
			kNormal[i] = nk;
			// find next line of Normals 
			fgets(inputBuffer,240,fp);
			sscanf(inputBuffer," %s",&tmpBuffer[0]); // Discard Whitespace
			while((i+1<numNormals)&&(strncmp(&tmpBuffer[0],"vn",2)!=0)){
				fgets(inputBuffer,240,fp);
				sscanf(inputBuffer," %s",&tmpBuffer[0]); // Discard Whitespace
			}
		}
	}

	////////////////////
	// Read Face data //
	////////////////////
	numFaces=0;
	rewind(fp);
	str=1;
	texsUsed = 0;
	// Count the faces in the file.
	while(str){
		fgets(inputBuffer, 240, fp);
		if(strncmp(inputBuffer,"f ",2) == 0){
			numFaces++;
		}
		if(strncmp(inputBuffer,"usemtl ",7) == 0){
			texsUsed++;
		}
		if(feof(fp)!=0){
			str=0;
		}
	}
	rewind(fp);
	Faces = new int[numFaces][9];
	FaceTexNum = new int[texsUsed];
	Materials = new OBJMaterial[texsUsed]; // NEW!!!!
	int texIter = 0; // 1
	char texlessfaces;
	
	while(strncmp(inputBuffer,"f ",2) != 0){
		if(strncmp(inputBuffer,"usemtl ",7) == 0){
			FaceTexNum[texIter]=0;
			sscanf(inputBuffer,"usemtl %s",&Materials[texIter].Name[0]);
			texIter++;
		}
		fgets(inputBuffer,240,fp);
	}
	for(int i=0;i<numFaces;i++){
		// Parse the line for face data
		sscanf(inputBuffer,"f %*d%*c%c",&texlessfaces); // Check if a//c or a/b/c 
		if(texlessfaces != '/'){
			sscanf(inputBuffer," f %d/%d/%d %d/%d/%d %d/%d/%d",&fa,&fb,&fc,&fd,&fe,&ff,&fg,&fh,&fi);
		} else {
			sscanf(inputBuffer," f %d//%d %d//%d %d//%d",&fa,&fc,&fd,&ff,&fg,&fi);
			fb = 0;	fe = 0;	fh = 0; // Set Texs to Default
		}
		// Assign Data to our arrays
		// Vertex 1
		Faces[i][0] = fa; // Geometry
		Faces[i][1] = fb; // Texture
		Faces[i][2] = fc; // Normal
		// Vertex 2
		Faces[i][3] = fd; // Geometry
		Faces[i][4] = fe; // Texture
		Faces[i][5] = ff; // Normal
		// Vertex 3
		Faces[i][6] = fg; // Geometry
		Faces[i][7] = fh; // Texture
		Faces[i][8] = fi; // Normal
		
		// Read another line of Faces from the file
		fgets(inputBuffer,240,fp);
		while((i<numFaces-1)&&(strncmp(inputBuffer,"f ",2) != 0)){
			if(strncmp(inputBuffer,"usemtl ",7) == 0){
				FaceTexNum[texIter]=i+1;
				sscanf(inputBuffer,"usemtl %s",&Materials[texIter].Name[0]);
				texIter++;
			}
			fgets(inputBuffer,240,fp);
		}
	}
	fclose(fp); // Clean Up
	delete[] inputBuffer;
}

////////////////
// Destructor //
////////////////
COBJModel::~COBJModel()
{
	if(TexturesLoaded==1)
	{
#ifdef USING_VRJUGGLER //using Juggler's special context-specific data types
		if(*texture != NULL)
		{
			delete[] texture;
		}
#else //using normal data types
		if(texture != NULL)
		{
			delete[] texture;
		}
#endif

		TexturesLoaded=NULL;
	}	
	if(xVertex!=NULL)delete[] xVertex;xVertex=NULL;
	if(yVertex!=NULL)delete[] yVertex;yVertex=NULL;
	if(zVertex!=NULL)delete[] zVertex;zVertex=NULL;
	if(Faces!=NULL)delete[] Faces;Faces=NULL;
	if(ObjectFilename!=NULL) delete[] ObjectFilename; ObjectFilename=NULL;
	if(OBJDirName!=NULL) delete[] OBJDirName; OBJDirName=NULL;
	if(MaterialFilename!=NULL)delete[] MaterialFilename; MaterialFilename=NULL;
	if(LISTUSED==0){
		if(iNormal!=NULL)delete[] iNormal; iNormal = NULL;
		if(jNormal!=NULL)delete[] jNormal; jNormal = NULL;;
		if(kNormal!=NULL)delete[] kNormal; kNormal = NULL;;
		if(uCoord!=NULL)delete[] uCoord; uCoord = NULL;;
		if(vCoord!=NULL)delete[] vCoord; vCoord = NULL;;
	}	
		
	if(FaceTexNum!=NULL)delete[] FaceTexNum; FaceTexNum=NULL;
	if(Materials!=NULL)delete[] Materials; Materials=NULL;
}

////////////////////////////////////////
// Build a display list for the model //
// Makes things run much faster	      //
////////////////////////////////////////
void COBJModel::BuildList()
{
	ReadMTL(); //New; this is here to get all context-specific stuff in one place

#ifdef USING_VRJUGGLER //using Juggler's special context-specific data types
	(*OBJList) = glGenLists(1);
#else //using normal data types
	OBJList = glGenLists(1);
#endif

	int texToUse=0;
	int texIter=0;

#ifdef USING_VRJUGGLER //using Juggler's special context-specific data types
	glNewList(*OBJList,GL_COMPILE);
#else //using normal data types
	glNewList(OBJList,GL_COMPILE);
#endif

	//glPushAttrib(GL_LIGHTING_BIT);
	if(TRANSPARENT==1){
		glEnable(GL_ALPHA_TEST);
	}
	if(UseTextures){
		glEnable(GL_TEXTURE_2D);
		glBindTexture(GL_TEXTURE_2D, Materials[texToUse].map_Kd); 
		
		texToUse++;
		texIter++;
	} else {
		//glMaterialf(GL_FRONT,GL_SHININESS,128.0);//Materials[texToUse].NSpecPower
		glMaterialfv(GL_FRONT,GL_AMBIENT,Materials[texToUse].Ambient);
		glMaterialfv(GL_FRONT,GL_DIFFUSE,Materials[texToUse].Diffuse);
		//glMaterialfv(GL_FRONT,GL_SPECULAR,Materials[texToUse].Specular);
		glColor4fv(Materials[texToUse].Diffuse);
		texToUse++;
		texIter++;
	}

	for(int p=0;p<numFaces;p++){
		if((texIter<texsUsed)&&(p==FaceTexNum[texIter])){ 
			if(UseTextures){
				glEnable(GL_TEXTURE_2D);
				glBindTexture(GL_TEXTURE_2D, Materials[texToUse].map_Kd);
				texIter++;
				texToUse++;
			} else {
				glMaterialfv(GL_FRONT,GL_AMBIENT,Materials[texToUse].Ambient);
				glMaterialfv(GL_FRONT,GL_DIFFUSE,Materials[texToUse].Diffuse);
				texToUse++;
				texIter++;
				glColor4fv(Materials[texToUse].Diffuse);
			}
		}
		int vx,vt,vn;
		glBegin(GL_TRIANGLES);
		for(int i=0;i<3;i++){
			vx = Faces[p][(i*3)]-1;
			vt = Faces[p][(i*3)+1]-1;
			vn = Faces[p][(i*3)+2]-1;
			if(vt < 0 ){ vt=0;}
			if(vn < 0 ){ vn=0;}
			if(vx < 0 ){ vx=0;}
			// Tex Coords
			if(UseTextures==1)
				glTexCoord2f(uCoord[vt],vCoord[vt]);
			// Normal Coords
			glNormal3f(iNormal[vn],jNormal[vn],kNormal[vn]);

			////volumetric fog stuff
			//// Set the fog coordinate for this vertex
			//SetFogCoord(g_FogDepth, yVertex[vx]);

			// Vertex Coords
			glVertex3f(xVertex[vx],yVertex[vx],zVertex[vx]);
		}
		glEnd();
	}
	if(TRANSPARENT==1){
		glDisable(GL_ALPHA_TEST);
	}
	if(UseTextures){
		glDisable(GL_TEXTURE_2D);
	}
	//glColor4f(1.0f,1.0f,1.0f,1.0f);
	//glPopAttrib();
	glEndList();
	NukeData();
	// Set flag to indicate we are using a Display List
	LISTUSED=1;
}

////////////////////////////////////
// Display lists make their own   //
// copy of everything, so we Nuke // 
// the old stuff in RAM			  //
////////////////////////////////////
void COBJModel::NukeData()
{
	delete[] xVertex;
	delete[] yVertex;
	delete[] zVertex;

	delete[] iNormal;
	delete[] jNormal;
	delete[] kNormal;
	delete[] uCoord;
	delete[] vCoord;
	delete[] ObjectFilename;
	delete[] OBJDirName;
	delete[] FaceTexNum; 
	delete[] Materials;

	xVertex = NULL;
	yVertex = NULL;
	zVertex = NULL;

	iNormal = NULL;
	jNormal = NULL;
	kNormal = NULL;
	uCoord = NULL;
	vCoord = NULL;
	ObjectFilename = NULL;
	OBJDirName = NULL;
	FaceTexNum = NULL;
	Materials = NULL;
}

/////////////////////////////////
// Call this to draw the model //
// It will choose the correct  //
// method to use.			   //
/////////////////////////////////
void COBJModel::DrawModel(){
	if(LISTUSED==1)
	{
#ifdef USING_VRJUGGLER //using Juggler's special context-specific data types
		glCallList(*OBJList);
#else //using normal data types
		glCallList(OBJList);
#endif
	} 
	else 
	{
		DrawModel2();
	}
}

//////////////////////////////////
// Draw method used when we		//
// DONT use Display Lists		//
//////////////////////////////////
void COBJModel::DrawModel2()
{
	int texToUse=0;
	int texIter=0;
	if(TRANSPARENT==1){
		glEnable(GL_ALPHA_TEST);
	}
	if(UseTextures){
		glEnable(GL_TEXTURE_2D);
		glBindTexture(GL_TEXTURE_2D, Materials[texToUse].map_Kd); //texture[texToUse]
		texToUse++;
		texIter++;
	}
	
	for(int p=0;p<numFaces;p++){
		if((texIter<texsUsed)&&(p==FaceTexNum[texIter])){ //FaceTexNum[texIter]
			if(UseTextures){
				glEnable(GL_TEXTURE_2D);
				glBindTexture(GL_TEXTURE_2D, Materials[texToUse].map_Kd);
				texIter++;
				texToUse++;
			}
		}
		glBegin(GL_TRIANGLES);  
		// Loop through our vertices and draw the model
		for(int i=0;i<3;i++){
			int vx = Faces[p][(i*3)]-1;
			int vt = Faces[p][(i*3)+1]-1;
			int vn = Faces[p][(i*3)+2]-1;
			if(vt < 0 ){ vt=0;}
			if(vn < 0 ){ vn=0;}
			if(vx < 0 ){ vx=0;}
			// Tex Coords
			if(UseTextures==1)
				glTexCoord2f(uCoord[vt],vCoord[vt]);
			// Normal Coords
			glNormal3f(iNormal[vn],jNormal[vn],kNormal[vn]);
			// Vertex Coords
			glVertex3f(xVertex[vx],yVertex[vx],zVertex[vx]);
		}
		glEnd();
	}

	if(TRANSPARENT==1){
		glDisable(GL_ALPHA_TEST);
	}
	glDisable(GL_TEXTURE_2D);
}

/////////////////////////////////////////////////////////////
// Reads the materials and the textures for the model.	   //
// (NB) This MUST be only called AFTER openGl has started  //
// i.e. after glutInit() has been called.				   //
/////////////////////////////////////////////////////////////
int COBJModel::ReadMTL(int Flags){
	// Variables
	FILE *fp;
	char *tempMatName;	tempMatName = new char[MAX_PATH];
	char *tempTexName;	tempTexName = new char[MAX_PATH];
	FILE *mtlfp;
	char *inputBuffer = new char[256];
	
	if((fp=fopen(ObjectFilename,"r"))==NULL){
		sprintf(inputBuffer,"Error Opening Object %s for Material File",ObjectFilename);
		//MessageBox(NULL,inputBuffer,"ERROR",MB_OK);
		std::cout << "Error: " << inputBuffer << std::endl;
		delete[] tempMatName;
		delete[] tempTexName;
		delete[] inputBuffer;
		return 2;
	}
	inputBuffer[0] = NULL;
	char matFileName[256];
	
	// Read Material Filename
	int str=1;
	// Count the number of vertex entries in the file
	while(str){
		fgets(inputBuffer, 240, fp);
		if(strncmp(inputBuffer,"mtllib ",7) == 0){
			sscanf(inputBuffer," mtllib %s\n",tempMatName);
			str=0;
		}
		if(feof(fp)!=0){
			//MessageBox(NULL,"Error Material Entry not Found","ERROR",MB_OK);
			std::cout << "Error: Material Entry not Found" << std::endl;
			rewind(fp);
			return 1;
		}
	}
	rewind(fp); // Back to start of file
	fclose(fp);
	if(OBJDirName[0] != '\0'){
		sprintf(matFileName,"%s/%s",OBJDirName,tempMatName);
	} else {
		strcpy(matFileName,tempMatName);
	}
	if((mtlfp=fopen(matFileName,"r"))==NULL){
		//MessageBox(NULL,"Material File Missing","ERROR",MB_OK);
		std::cout << "Error: Material File Missing" << std::endl;
		BuildList();
		delete[] inputBuffer;
		delete[] tempMatName;
		delete[] tempTexName;
		return 2;
	}
	// Create a file buffer of 32kb
	// Cache Buffer
	char BUFFER[32768];
	setvbuf(mtlfp,BUFFER,_IOFBF,sizeof(BUFFER));
	
	str = 1;
	int NumberOfTextures=0;
	char (*TexName)[80];
	char (*TexFileName)[256];
	// Count the Number of Materials in the file	
	while(str){
		fgets(inputBuffer, 240, mtlfp);
		if(strncmp(inputBuffer,"newmtl ",7)==0){
			NumberOfTextures++;
		}
		if(feof(mtlfp)!=0){
			rewind(mtlfp);
			str=0;
		}
	}

	// Temp Material Settings Variables
	float (*Ambient)[3];
	float (*Diffuse)[3];
	float (*Specular)[3];
	float *Dissolve;
	int *illum;
	int *Nfactor;

	// activate them
	TexName = new char[NumberOfTextures][80];
	TexFileName = new char[NumberOfTextures][256];
	Ambient = new float[NumberOfTextures][3];
	Diffuse = new float[NumberOfTextures][3];
	Specular = new float[NumberOfTextures][3];
	illum = new int[NumberOfTextures];
	Nfactor = new int[NumberOfTextures];
	Dissolve = new float[NumberOfTextures];
	
#ifdef USING_VRJUGGLER //using Juggler's special context-specific data types
	*texture = new GLuint[NumberOfTextures];
	for(int o=0;o<NumberOfTextures;o++)
	{
		*texture[o]=0;
	}
#else //using normal data types
	texture = new GLuint[NumberOfTextures];
	for(int o=0;o<NumberOfTextures;o++)
	{
		texture[o]=0;
	}
#endif
	
	// Scan to start of a block
	while(strncmp(inputBuffer,"newmtl ",7)!=0){ //(inputBuffer[0] != 'n')||(inputBuffer[1] != 'e')){
		fgets(inputBuffer,240,mtlfp);
	}
	for(int i=0;i<NumberOfTextures;i++){

		// Parse the line for coord data
		sscanf(inputBuffer,"newmtl %s\n",TexName[i]);
				
		fgets(inputBuffer,240,mtlfp);
		sscanf(inputBuffer," Ka %f %f %f\n",&Ambient[i][0],&Ambient[i][1],&Ambient[i][2]);
		
		fgets(inputBuffer,240,mtlfp);
		sscanf(inputBuffer," Kd %f %f %f\n",&Diffuse[i][0],&Diffuse[i][1],&Diffuse[i][2]);
		
		fgets(inputBuffer,240,mtlfp);
		sscanf(inputBuffer," Ks %f %f %f\n",&Specular[i][0],&Specular[i][1],&Specular[i][2]);
		
		//// Check needed to differentiate MS3D and 3DEX created files
		//fgets(inputBuffer,240,mtlfp);
		//illum[i]=0;
		//if(sscanf(inputBuffer," Ns %d\n",&Nfactor[i])==0){
		//	sscanf(inputBuffer," illum %d",&illum[i]);
		//	fgets(inputBuffer,240,mtlfp);
		//	sscanf(inputBuffer," Ns %d\n",&Nfactor[i]);
		//}
		//Dissolve[i] = 1.0f;

		// This works for the Max2Mtl exporter - Tyler Streeter
		fgets(inputBuffer,240,mtlfp); //getting the d line
		//sscanf(inputBuffer," d %d\n",&Dissolve[i]);
		Dissolve[i] = 1.0f; //just use 1 for the d value
		fgets(inputBuffer,240,mtlfp); //getting the Ns line
		sscanf(inputBuffer," Ns %d\n",&Nfactor[i]);
		fgets(inputBuffer,240,mtlfp); //getting the illum line
		sscanf(inputBuffer," illum %d",&illum[i]);

		fgets(inputBuffer,240,mtlfp);
		if(0==sscanf(inputBuffer," map_Kd %s\n",tempTexName)){
			strcpy(tempTexName,"ERROR.bmp");	
		} else {
			if(tempTexName[1]==':'){
				// Jiggery Pokery to handle short and long filenames (3dex vs MS3D)
				char *ptr=strstr(inputBuffer,"map_Kd");
				strcpy(tempTexName,&ptr[7]);
				char *ptr2 = strstr(tempTexName,".bmp");
				if(ptr2 != NULL)
					ptr2[4]='\0';
			}
			fgets(inputBuffer,240,mtlfp);
		}

		if(OBJDirName[0] != '\0'){
			if(tempTexName[1]!=':'){
				sprintf(TexFileName[i],"%s/%s",OBJDirName,tempTexName);
			} else {
				strcpy(TexFileName[i],tempTexName);
			}
		} else {
			strcpy(TexFileName[i],tempTexName);
		}
		
		if((Flags & TEX_NONE) != TEX_NONE){
			if(strncmp(tempTexName,"ERROR.bmp",9)!=0){
				if(Transparent==0){
					//texture[i] = CImageLoader::LoadImage(TexFileName[i],Flags);

#ifdef USING_VRJUGGLER //using Juggler's special context-specific data types
					*texture[i] = CreateTexture(TexFileName[i]);
#else //using normal data types
					texture[i] = CreateTexture(TexFileName[i]);
#endif
				} else {
					//texture[i] = CImageLoader::LoadImage(TexFileName[i],Flags,TranzColor[0],TranzColor[1],TranzColor[2]);

#ifdef USING_VRJUGGLER //using Juggler's special context-specific data types
					*texture[i] = CreateTexture(TexFileName[i]);
#else //using normal data types
					texture[i] = CreateTexture(TexFileName[i]);
#endif
				}
			} else {
#ifdef USING_VRJUGGLER //using Juggler's special context-specific data types
					*texture[i] = 0;
#else //using normal data types
					texture[i] = 0;
#endif
			}
		}
		//Read another line of Coords from the file
		
		while((i+1<NumberOfTextures)&&(strncmp(inputBuffer,"newmtl ",7) != 0)){
			fgets(inputBuffer,240,mtlfp);
		}
	}

	// Transfer the Material details from our temp holders to our Material structs
	for(int matcpy=0;matcpy<NumberOfTextures;matcpy++){
		for(int tmp=0;tmp<texsUsed;tmp++){
			if(strcmp(&Materials[tmp].Name[0],TexName[matcpy])==0){
				Materials[tmp].map_Kd	= texture[matcpy];		// Diffuse Texture Map
				Materials[tmp].map_Ka	= 0;					// Ambient Map
				Materials[tmp].map_Ks	= 0;					// Specular Map
				Materials[tmp].map_Bump = 0;					// Bump Map
				Materials[tmp].map_d	= 0;					// Opacity Map
				Materials[tmp].Ambient[0] = Ambient[matcpy][0]; // Ambient Material details
				Materials[tmp].Ambient[1] = Ambient[matcpy][1];
				Materials[tmp].Ambient[2] = Ambient[matcpy][2];
				Materials[tmp].Ambient[3] = Dissolve[matcpy];
				Materials[tmp].Diffuse[0] = Diffuse[matcpy][0]; // Diffuse Material details
				Materials[tmp].Diffuse[1] = Diffuse[matcpy][1];
				Materials[tmp].Diffuse[2] = Diffuse[matcpy][2];
				Materials[tmp].Diffuse[3] = Dissolve[matcpy];
				Materials[tmp].Specular[0] = Specular[matcpy][0];// Spec Material details
				Materials[tmp].Specular[1] = Specular[matcpy][1]; 
				Materials[tmp].Specular[2] = Specular[matcpy][2]; 
				Materials[tmp].Specular[3] = Dissolve[matcpy];
				Materials[tmp].illum = illum[matcpy];			// Illumination Model
				Materials[tmp].Ns = Nfactor[matcpy];			// Phong Specular setting
				Materials[tmp].Ni = 1;							// Refractive Index
			}
		}
	}
	// Clean Up after ourselves
	fclose(mtlfp);
	delete[] inputBuffer;
	delete[] TexName;
	delete[] TexFileName;
	delete[] tempMatName;
	delete[] tempTexName;
	// Material Settings
	delete[] Ambient;
	delete[] Diffuse;
	delete[] Specular;
	delete[] Nfactor;
	delete[] illum;
	delete[] Dissolve;
	
	if((Flags & TEX_NONE)!=TEX_NONE){
		UseTextures = 1;
	}
	TexturesLoaded = 1;
	return 0;
}

// Set the Objects Position;
void COBJModel::SetOBJPos(float xPos, float yPos, float zPos)
{
	Pos[0] = xPos;
	Pos[1] = yPos;
	Pos[2] = zPos;
	Box[0] += xPos; Box[1] += xPos;
	Box[2] += yPos; Box[3] += yPos;
	Box[4] += zPos; Box[5] += zPos;
}
// Set its Heading
void COBJModel::SetOBJHeading(float Pitch,float Yaw,float Roll){
	Heading[0] = Pitch;
	Heading[1] = Yaw;
	Heading[2] = Roll;
}


void COBJModel::LockPosition()
{
	for(int i=0;i<numVertices;i++){
		xVertex[i] += Pos[0];
		yVertex[i] += Pos[1];
		zVertex[i] += Pos[2];
	}
	LOCKED=1;
}

void COBJModel::SetVertexArrays(){
/*	if(VTX==0){
		glLockArrays = (PFNGLLOCKARRAYSEXTPROC) wglGetProcAddress( "glLockArraysEXT" );
		glUnlockArrays = (PFNGLUNLOCKARRAYSEXTPROC) wglGetProcAddress( "glUnlockArraysEXT" );
		glActiveTexture = (PFNGLACTIVETEXTUREARBPROC) wglGetProcAddress( "glActiveTextureARB");
		VertexArray = new GLfloat[numFaces*9];
		NormalArray = new GLfloat[numFaces*9];
		TexCoordArray = new GLfloat[numFaces*6];
	
		for(int p=0;p<numFaces;p++){
			// Loop through our vertices and draw the model
			for(int i=0;i<3;i++){
				int vx = Faces[p][(i*3)]-1;
				if(vx < 0 ){ vx=0;}
				int vn = Faces[p][(i*3)+2]-1;
				if(vn < 0 ){ vn=0;}
				int vt = Faces[p][(i*3)+1]-1;
				// Vertex Coords
				VertexArray[(p*9)+((i*3)+0)] = xVertex[vx];
				VertexArray[(p*9)+((i*3)+1)] = yVertex[vx];
				VertexArray[(p*9)+((i*3)+2)] = zVertex[vx];

				NormalArray[(p*9)+((i*3)+0)] = iNormal[vn];	
				NormalArray[(p*9)+((i*3)+1)] = jNormal[vn];	
				NormalArray[(p*9)+((i*3)+2)] = kNormal[vn];

				TexCoordArray[(p*6)+((i*2)+0)] = uCoord[vt];
				TexCoordArray[(p*6)+((i*2)+1)] = vCoord[vt];
			}
		}
		
		VTX=1;
	} else {
	//glLockArrays(0,numFaces);
	
		glEnableClientState(GL_VERTEX_ARRAY);
		glEnableClientState(GL_NORMAL_ARRAY);
		glEnableClientState(GL_TEXTURE_COORD_ARRAY);

		glVertexPointer(3,GL_FLOAT,0,VertexArray);
		glNormalPointer(GL_FLOAT,0,NormalArray);
		glTexCoordPointer(2,GL_FLOAT,0,TexCoordArray);
		glEnable(GL_TEXTURE_2D);
		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D,Materials[3].map_Kd);
		//glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
		//glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_REPLACE);

		glActiveTexture(GL_TEXTURE1);
		glBindTexture(GL_TEXTURE_2D,Materials[5].map_Kd);
		//glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
		//glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD);

		
		glLockArrays(0,(GLsizei)numFaces);
		glDrawArrays(GL_TRIANGLES,0,numFaces*3);
		glActiveTexture(GL_TEXTURE0);
		glDisable(GL_TEXTURE_2D);

		glDisableClientState(GL_NORMAL_ARRAY);
		glDisableClientState(GL_VERTEX_ARRAY);
		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	
	//glUnlockArrays();
	}*/
}

//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////

void COBJModel::LoadCOBJModel2(std::string dirname,std::string filename){
	std::string inputBufferString;
	std::string objectFilenameString = (dirname.empty()==true)? filename : dirname + "/" + filename;
	std::ifstream objectFile(objectFilenameString.c_str(), std::ios_base::in); 
	if(!objectFile)
	{ 
		//MessageBox(NULL,"Error opening 3D Object File", "Error", MB_OK); 
		std::cout << "Error opening 3D Object File: " << filename << std::endl;
		return; 
	}
	
	while(!objectFile.eof()){
		std::getline(objectFile,inputBufferString);
		if(inputBufferString.compare(0,2,"v ")==0) { numVertices++; }
		if(inputBufferString.compare(0,3,"vt ")==0){ numTextureCoords++; }
		if(inputBufferString.compare(0,3,"vn ")==0){ numNormals++; }
		if(inputBufferString.compare(0,2,"f ")==0){ numFaces++; }
		if(inputBufferString.compare(0,7,"usemtl ")==0){ texsUsed++; }
	}
	objectFile.clear();
	objectFile.seekg(0); // Rewind
	// Allocate Memory for our 3D Object
	xVertex = new float[numVertices];
	yVertex = new float[numVertices];
	zVertex = new float[numVertices];
	uCoord  = new float[numTextureCoords];
	vCoord  = new float[numTextureCoords];
	iNormal = new float[numNormals];
	jNormal = new float[numNormals];
	kNormal = new float[numNormals];
	Faces   = new int  [numFaces][9];
	FaceTexNum = new int[texsUsed];
	Materials = new OBJMaterial[texsUsed]; 
	MaterialFilename = new char[40];
	MaterialFilename[0] = '\0';

	// Read The File Data
	int vertexCounter=0,texCoordCounter=0,normalCounter=0,faceCounter=0,materialCounter=0;
	char faceComponents;
	while(!objectFile.eof()){
		std::getline(objectFile,inputBufferString);
		if(inputBufferString.compare(0,2,"v ")==0){
			sscanf(inputBufferString.c_str(),"v %f %f %f",&xVertex[vertexCounter],&yVertex[vertexCounter],&zVertex[vertexCounter]);
			if(vertexCounter==0){
				Box[0] = xVertex[vertexCounter]; Box[1] = xVertex[vertexCounter]; Box[2] = yVertex[vertexCounter]; Box[3] = yVertex[vertexCounter]; Box[4] = zVertex[vertexCounter]; Box[5] = zVertex[vertexCounter];   
			} else {
				// Store BoundingBox Coords (for culling purposes)
				Box[0] = (xVertex[vertexCounter]<Box[0]) ? xVertex[vertexCounter] : Box[0];
				Box[1] = (xVertex[vertexCounter]>Box[1]) ? xVertex[vertexCounter] : Box[1];
				Box[2] = (yVertex[vertexCounter]<Box[2]) ? yVertex[vertexCounter] : Box[2];
				Box[3] = (yVertex[vertexCounter]>Box[3]) ? yVertex[vertexCounter] : Box[3];
				Box[4] = (zVertex[vertexCounter]<Box[4]) ? zVertex[vertexCounter] : Box[4];
				Box[5] = (zVertex[vertexCounter]>Box[5]) ? zVertex[vertexCounter] : Box[5];								
			}
			vertexCounter++;
		}
		if(inputBufferString.compare(0,3,"vt ")==0){
			sscanf(inputBufferString.c_str(),"vt %f %f",&uCoord[texCoordCounter],&vCoord[texCoordCounter]);
			texCoordCounter++;
		}
		if(inputBufferString.compare(0,3,"vn ")==0){
			sscanf(inputBufferString.c_str(),"vn %f %f %f",&iNormal[normalCounter],&jNormal[normalCounter],&kNormal[normalCounter]);
			normalCounter++;
		}
		if(inputBufferString.compare(0,2,"f ")==0){
			sscanf(inputBufferString.c_str(),"f %*d%*c%c",&faceComponents);
			switch(faceComponents){
			case ' ':
				sscanf(inputBufferString.c_str(),"f %d %d %d",	&Faces[faceCounter][0],&Faces[faceCounter][3],&Faces[faceCounter][6]);
				Faces[faceCounter][1] = 0; Faces[faceCounter][2] = 0; Faces[faceCounter][4] = 0;
				Faces[faceCounter][5] = 0; Faces[faceCounter][7] = 0; Faces[faceCounter][8] = 0;
				break;
			case '/':
				sscanf(inputBufferString.c_str(),"f %d//%d %d//%d %d//%d",	&Faces[faceCounter][0],&Faces[faceCounter][2],
																			&Faces[faceCounter][3],&Faces[faceCounter][5],
																			&Faces[faceCounter][6],&Faces[faceCounter][8]);
				Faces[faceCounter][1] = 0; Faces[faceCounter][4] = 0; Faces[faceCounter][7] = 0;
				break;
			default:
				sscanf(inputBufferString.c_str(),"f %d/%d/%d %d/%d/%d %d/%d/%d",&Faces[faceCounter][0],&Faces[faceCounter][1],
																				&Faces[faceCounter][2],&Faces[faceCounter][3],
																				&Faces[faceCounter][4],&Faces[faceCounter][5],
																				&Faces[faceCounter][6],&Faces[faceCounter][7],
																				&Faces[faceCounter][8]);
				break;
			}
			faceCounter++;
		}
		if(inputBufferString.compare(0,7,"usemtl ")==0){
			sscanf(inputBufferString.c_str(),"usemtl %s",&Materials[materialCounter].Name[0]);
			FaceTexNum[materialCounter] = faceCounter;
			materialCounter++;
		}
		if(inputBufferString.compare(0,7,"mtllib ")==0){
			sscanf(inputBufferString.c_str(),"mtllib %s",MaterialFilename);
		}

	}
	
	objectFile.close();
	
	// Initialise Some Class Variables to defaults
	PALLETEDEXT=0;		LOCKED=0;	LOWRES=0;
	UseTextures = 0;	TexturesLoaded = 0;
	Transparent=0;		ModelNumber=0;
	LISTUSED=0;			VTX=0;
	OBJDirName = new char[80];
	OBJDirName[0] = '\0';
	ObjectFilename = new char[80];
	
	if(dirname.empty() == false){
		strcpy(OBJDirName,dirname.c_str());
		sprintf(ObjectFilename,objectFilenameString.c_str());
	} else {
		strcpy(ObjectFilename,filename.c_str());
	}
}

/////////////////////////////////////////////////////////////
// Reads the materials and the textures for the model.	   //
// (NB) This MUST be only called AFTER openGl has started  //
/////////////////////////////////////////////////////////////
int COBJModel::ReadMTL2(int Flags){
	// Variables
	char *tempMatName;	tempMatName = new char[MAX_PATH];
	char *tempTexName;	tempTexName = new char[MAX_PATH];
	
	char *inputBuffer = new char[256];
	std::string inputBufferString;
	FILE *mtlfp = NULL;
	inputBuffer[0] = NULL;
	//char matFileName[256];
	std::string matFileName;
	
	// Read Material Filename
	int str=1;
	// Count the number of vertex entries in the file
	if(MaterialFilename[0] == '\0'){
		// No Material File Entry in OBJ File
		return 1;
	}
	
	if(OBJDirName[0] != '\0'){
		char tmp1[80];
		sprintf(&tmp1[0],"%s/%s",OBJDirName,MaterialFilename);
		matFileName = tmp1;
	} else {
		matFileName = MaterialFilename;
	}
	std::ifstream materialFile(matFileName.c_str(), std::ios_base::in); 
	if(!materialFile){ 
		//MessageBox(NULL,"Material File Missing", "Error", MB_ICONEXCLAMATION|MB_OK);
		std::cout << "Material File Missing" << std::endl;
		BuildList();
		delete[] inputBuffer;
		delete[] tempMatName;
		delete[] tempTexName;
		return 2; 
	}
	
	int NumberOfTextures=0;
	// Count the Number of Materials in the file	
	while(!materialFile.eof()){
		std::getline(materialFile,inputBufferString);
		if(inputBufferString.compare(0,7,"newmtl ")==0){ NumberOfTextures++; }
	}
	materialFile.clear();
	materialFile.seekg(0); // Rewind

	
	str = 1;

	char (*TexName)[80];
	char (*TexFileName)[256];



	// Temp Material Settings Variables
	float (*Ambient)[3];
	float (*Diffuse)[3];
	float (*Specular)[3];
	float *Dissolve;
	int *illum;
	int *Nfactor;

	// activate them
	TexName = new char[NumberOfTextures][80];
	TexFileName = new char[NumberOfTextures][256];
	Ambient = new float[NumberOfTextures][3];
	Diffuse = new float[NumberOfTextures][3];
	Specular = new float[NumberOfTextures][3];
	illum = new int[NumberOfTextures];
	Nfactor = new int[NumberOfTextures];
	Dissolve = new float[NumberOfTextures];
	
#ifdef USING_VRJUGGLER //using Juggler's special context-specific data types
	*texture = new GLuint[NumberOfTextures];
	for(int o=0;o<NumberOfTextures;o++)
	{
		*texture[o]=0;
	}
#else //using normal data types
	texture = new GLuint[NumberOfTextures];
	for(int o=0;o<NumberOfTextures;o++)
	{
		texture[o]=0;
	}
#endif


	
	// Scan to start of a block
	while(strncmp(inputBuffer,"newmtl ",7)!=0){ //(inputBuffer[0] != 'n')||(inputBuffer[1] != 'e')){
//		fgets(inputBuffer,240,mtlfp);
	}
	for(int i=0;i<NumberOfTextures;i++){

		// Parse the line for coord data
		sscanf(inputBuffer,"newmtl %s\n",TexName[i]);
				
		fgets(inputBuffer,240,mtlfp);
		sscanf(inputBuffer," Ka %f %f %f\n",&Ambient[i][0],&Ambient[i][1],&Ambient[i][2]);
		
		fgets(inputBuffer,240,mtlfp);
		sscanf(inputBuffer," Kd %f %f %f\n",&Diffuse[i][0],&Diffuse[i][1],&Diffuse[i][2]);
		
		fgets(inputBuffer,240,mtlfp);
		sscanf(inputBuffer," Ks %f %f %f\n",&Specular[i][0],&Specular[i][1],&Specular[i][2]);
		
		// Check needed to differentiate MS3D and 3DEX created files
		fgets(inputBuffer,240,mtlfp);
		illum[i]=0;
		if(sscanf(inputBuffer," Ns %d\n",&Nfactor[i])==0){
			sscanf(inputBuffer," illum %d",&illum[i]);
			fgets(inputBuffer,240,mtlfp);
			sscanf(inputBuffer," Ns %d\n",&Nfactor[i]);
		}
		Dissolve[i] = 1.0f;

		fgets(inputBuffer,240,mtlfp);
		if(0==sscanf(inputBuffer," map_Kd %s\n",tempTexName)){
			strcpy(tempTexName,"ERROR.bmp");	
		} else {
			if(tempTexName[1]==':'){
				// Jiggery Pokery to handle short and long filenames (3dex vs MS3D)
				char *ptr=strstr(inputBuffer,"map_Kd");
				strcpy(tempTexName,&ptr[7]);
				char *ptr2 = strstr(tempTexName,".bmp");
				if(ptr2 != NULL)
					ptr2[4]='\0';
			}
			fgets(inputBuffer,240,mtlfp);
		}

		if(OBJDirName[0] != '\0'){
			if(tempTexName[1]!=':'){
				sprintf(TexFileName[i],"%s/%s",OBJDirName,tempTexName);
			} else {
				strcpy(TexFileName[i],tempTexName);
			}
		} else {
			strcpy(TexFileName[i],tempTexName);
		}
		
		if((Flags & TEX_NONE) != TEX_NONE){
			if(strncmp(tempTexName,"ERROR.bmp",9)!=0){
				if(Transparent==0){
					//texture[i] = CImageLoader::LoadImage(TexFileName[i],Flags);
#ifdef USING_VRJUGGLER //using Juggler's special context-specific data types
					*texture[i] = CreateTexture(TexFileName[i]);
#else //using normal data types
					texture[i] = CreateTexture(TexFileName[i]);
#endif
				} else {
					//texture[i] = CImageLoader::LoadImage(TexFileName[i],Flags,TranzColor[0],TranzColor[1],TranzColor[2]);
#ifdef USING_VRJUGGLER //using Juggler's special context-specific data types
					*texture[i] = CreateTexture(TexFileName[i]);
#else //using normal data types
					texture[i] = CreateTexture(TexFileName[i]);
#endif
				}
			} else {
#ifdef USING_VRJUGGLER //using Juggler's special context-specific data types
				*texture[i] = 0;
#else //using normal data types
				texture[i] = 0;
#endif
			}
		}
		//Read another line of Coords from the file
		
		while((i+1<NumberOfTextures)&&(strncmp(inputBuffer,"newmtl ",7) != 0)){
			fgets(inputBuffer,240,mtlfp);
		}
	}

	// Transfer the Material details from our temp holders to our Material structs
	for(int matcpy=0;matcpy<NumberOfTextures;matcpy++){
		for(int tmp=0;tmp<texsUsed;tmp++){
			if(strcmp(&Materials[tmp].Name[0],TexName[matcpy])==0)
			{
#ifdef USING_VRJUGGLER //using Juggler's special context-specific data types
				Materials[tmp].map_Kd	= *texture[matcpy];		// Diffuse Texture Map
#else //using normal data types
				Materials[tmp].map_Kd	= texture[matcpy];		// Diffuse Texture Map
#endif

				Materials[tmp].map_Ka	= 0;					// Ambient Map
				Materials[tmp].map_Ks	= 0;					// Specular Map
				Materials[tmp].map_Bump = 0;					// Bump Map
				Materials[tmp].map_d	= 0;					// Opacity Map
				Materials[tmp].Ambient[0] = Ambient[matcpy][0]; // Ambient Material details
				Materials[tmp].Ambient[1] = Ambient[matcpy][1];
				Materials[tmp].Ambient[2] = Ambient[matcpy][2];
				Materials[tmp].Ambient[3] = Dissolve[matcpy];
				Materials[tmp].Diffuse[0] = Diffuse[matcpy][0]; // Diffuse Material details
				Materials[tmp].Diffuse[1] = Diffuse[matcpy][1];
				Materials[tmp].Diffuse[2] = Diffuse[matcpy][2];
				Materials[tmp].Diffuse[3] = Dissolve[matcpy];
				Materials[tmp].Specular[0] = Specular[matcpy][0];// Spec Material details
				Materials[tmp].Specular[1] = Specular[matcpy][1]; 
				Materials[tmp].Specular[2] = Specular[matcpy][2]; 
				Materials[tmp].Specular[3] = Dissolve[matcpy];
				Materials[tmp].illum = illum[matcpy];			// Illumination Model
				Materials[tmp].Ns = Nfactor[matcpy];			// Phong Specular setting
				Materials[tmp].Ni = 1;							// Refractive Index
			}
		}
	}
	// Clean Up after ourselves
	fclose(mtlfp);
	delete[] inputBuffer;
	delete[] TexName;
	delete[] TexFileName;
	delete[] tempMatName;
	delete[] tempTexName;
	// Material Settings
	delete[] Ambient;
	delete[] Diffuse;
	delete[] Specular;
	delete[] Nfactor;
	delete[] illum;
	delete[] Dissolve;
	
	if((Flags & TEX_NONE)!=TEX_NONE){
		UseTextures = 1;
	}
	TexturesLoaded = 1;
	return 0;
}

//New Functions- Tyler Streeter
int COBJModel::GetNumVertices()
{
	return numVertices;
}

//shallow copy only
void COBJModel::GetVertexArrays(float*& xCoords, float*& yCoords, float*& zCoords)
{
	xCoords = xVertex;
	yCoords = yVertex;
	zCoords = zVertex;
}

int COBJModel::GetNumFaces()
{
	return numFaces;
}

void COBJModel::GetFaceArray(int (*&faceArray)[9])
{
	faceArray = Faces;
}

GLuint COBJModel::CreateTexture(std::string filename)
{
	GLuint newTextureID;
	
	if(filename == "")
	{
		std::cout << "No image filename given." << std::endl;
		std::cout << "Quitting..." << std::endl;
		exit(0);
	}
	
	corona::Image* image = corona::OpenImage(filename.c_str(), corona::PF_R8G8B8);

	if (!image)
	{
		std::cout << "Error loading image file: " << filename << std::endl;
		std::cout << "Quitting..." << std::endl;
		exit(0);
	}

	// Generate a texture
	glGenTextures(1, &newTextureID);

	// This sets the alignment requirements for the start of each pixel row in memory.
	//glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

	// Bind the texture to newTextureID
	glBindTexture(GL_TEXTURE_2D, newTextureID);

	// Build Mipmaps (builds different versions of the picture for distances - looks better)
	gluBuild2DMipmaps(GL_TEXTURE_2D, 3, image->getWidth(), image->getHeight(), GL_RGB, GL_UNSIGNED_BYTE, image->getPixels());

	// Lastly, we need to tell OpenGL the quality of our texture map.  GL_LINEAR_MIPMAP_LINEAR
	// is the smoothest.  GL_LINEAR_MIPMAP_NEAREST is faster than GL_LINEAR_MIPMAP_LINEAR, 
	// but looks blochy and pixilated.  Good for slower computers though. 
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_LINEAR);	

	// Now we need to free the image data that we loaded since OpenGL stored it as a texture
	delete image;

	return newTextureID;
}

///////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *

//void COBJModel::SetFogCoord(float depth, float height)
//{
//	// This function takes the depth of the fog, as well as the height
//	// of the current vertex.  If the height is greater than the depth, there
//	// is no fog applied to it (0), but if it's below the depth, then we
//	// calculate the fog value that should be applied to it.  Since the higher
//	// the number passed into glFogCoordfEXT() produces more fog, we need to
//	// subtract the depth from the height, then negate that value to switch
//	// the ratio from 0 to the depth around.  Otherwise it would have more
//	// fog on the top of the fog volume than the bottom of it.
//
//	float fogY = 0;
//
//	// Check if the height of this vertex is greater than the depth (needs no fog)
//	if(height > depth)
//		fogY = 0;
//	// Otherwise, calculate the fog depth for the current vertex
//	else
//		fogY = -(height - depth);
//
//	// Assign the fog coordinate for this vertex using our extension function pointer
//	glFogCoordfEXT(fogY);
//}

///////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *
