#include <stdafx.h>

#include <string>
#include <iostream>
#include <strstream>
#include <fstream>
#include <gl/gl.h>

#include "..\objBmp\bmpLoader.hpp"

#include "rtgLoader.hpp"

void print(char *format, ...);

// quick helper functions to reduce clutter
int readXyz ( ifstream *file, char *label, VEC12 *v ) {
	string buffer;
	*file >> buffer;
	if ( buffer != label ) return -1;
	*file >> v->x;	*file >> v->y;	*file >> v->z;
	return 0;
}
int readXyza ( ifstream *file, char *label, VEC16 *v ) {
	string buffer;
	*file >> buffer;
	if ( buffer != label ) return -1;
	*file >> v->x;	*file >> v->y;	*file >> v->z;
	*file >> v->a;
	return 0;
}
int readX ( ifstream *file, char *label, float *v ) {
	string buffer;
	*file >> buffer;
	if ( buffer != label ) return -1;
	*file >> *v;
	return 0;
}
int readSwitch ( ifstream *file, char *label, BOOL *v ) {
	string buffer;
	*file >> buffer;
	if ( buffer != label ) return -1;
	*file >> buffer;
	*v = FALSE;
	if ( buffer == "on" ) *v = TRUE;
	return 0;
}


rtgScene::rtgScene() {

	this->ready = FALSE;

};

//----------------------------------------------------------------------
// load the rtg File, returns 0 if all is ok
//----------------------------------------------------------------------
int rtgScene::load ( string pth ) {
	char letter=0;
	int discard=0;
	int place,i=0,j=0,o=0,a=0;
	char b[200];
	string buffer="";

	this->txCount=0;  // number of textures bound to Gl

	this->path=pth;
//	this->fileName=fnme; TO DO FIX UP 
	this->fileAbs = path; //+fileName; serious mod !!!!!!!******** check here for problems

	if ( this->ready ) return 0;
	this->ready=FALSE;

	// open file as ascii

	ifstream fp( fileAbs.c_str() );
	if (!fp) return 1;

	//HEADER_TITLE
	fp >> buffer; if ( buffer != "HEADER_TITLE" ) goto failure;
	fp.getline ( b,98,'\n'); this->headerTitle=b;
	//HEADER_VERSION
	fp >> buffer; if ( buffer != "HEADER_VERSION" ) goto failure;
	fp >> this->headerVersion;
	//NUMBER_OF_OBJECTS
	fp >> buffer; if ( buffer != "NUMBER_OF_OBJECTS" ) goto failure;
	fp >> this->numberOfObjects;

	if ( -1 == readSwitch ( &fp, "OUTPUT_VERT_NORMS", &this->vertNorms ) ) goto failure;
	if ( -1 == readSwitch ( &fp, "OUTPUT_VERT_COLORS", &this->vertColors ) ) goto failure;
	if ( -1 == readSwitch ( &fp, "OUTPUT_TEX_COORDS", &this->texCoords ) ) goto failure;
	if ( -1 == readSwitch ( &fp, "OUTPUT_POLY_NORMS", &this->polyNorms ) ) goto failure;
	if ( -1 == readSwitch ( &fp, "OUTPUT_HIERARCHY", &this->outputHierarchy ) ) goto failure;
	if ( -1 == readSwitch ( &fp, "OUTPUT_LOCAL", &this->outputLocal ) ) goto failure;
	if ( -1 == readSwitch ( &fp, "SHOW_INDEX_COUNTERS", &this->showIndexCounters ) ) goto failure;
	if ( -1 == readSwitch ( &fp, "OUTPUT_MATERIALS", &this->outputMaterials ) ) goto failure;
	if ( -1 == readSwitch ( &fp, "OUTPUT_ANIMATION", &this->outputAnimation ) ) goto failure;
	if ( -1 == readSwitch ( &fp, "OUTPUT_ALL_NODES", &this->outputAllNodes ) ) goto failure;
	if ( -1 == readSwitch ( &fp, "OUTPUT_DECOMP", &this->outputDecomp ) ) goto failure;
	if ( -1 == readSwitch ( &fp, "OUTPUT_DEGREES", &this->outputDegrees ) ) goto failure;

				
	//MATERIAL_LIST 1
	fp >> buffer; if ( buffer != "MATERIAL_LIST" ) goto failure;
	fp >> this->materials.count;

	// alloc mem for all materials
	this->materials.mat = new class rtgMaterial[this->materials.count];

	// read in all the materials
		fp >> buffer; 
	for ( i=0; i<this->materials.count; i++ ) {
		//    MATERIAL 0
		
		if ( buffer != "MATERIAL" ) goto failure;
		fp >> place; if ( place != i ) goto failure;

		//    NAME lambert1
		fp >> buffer; if ( buffer != "NAME" ) goto failure;
		fp >> this->materials.mat[i].name;

		if ( -1 == readXyz ( &fp, "AMBIENT",		&this->materials.mat[i].ambient) )	goto failure;
		if ( -1 == readXyz ( &fp, "DIFFUSE",		&this->materials.mat[i].diffuse) ) goto failure;
		if ( -1 == readXyz ( &fp, "SPECULAR",		&this->materials.mat[i].specular) ) goto failure;
		if ( -1 == readXyz ( &fp, "EMMISION",		&this->materials.mat[i].emmision) ) goto failure;
		if ( -1 == readX   ( &fp, "SHININESS",		&this->materials.mat[i].shininess) ) goto failure;
		if ( -1 == readX   ( &fp, "TRANSPARENCY",	&this->materials.mat[i].transparency) ) goto failure;

		fp >> buffer;
		if ( buffer == "TEXTURE_NAME" ) { // we got texture fileNames coming up
			fp >> this->materials.mat[i].sgiTextureFile;
			fp >> buffer; 
			if ( buffer == "TEXTURE_FILENAME" ) {
				fp >> this->materials.mat[i].textureFile;
				 this->materials.mat[i].texture.LoadBMP( (char*)this->materials.mat[i].textureFile.c_str() );
				fp >> buffer;
			}

		}
		if ( buffer == "BUMP_NAME" ) { // we got bump map file name coming up
			fp >> this->materials.mat[i].bumpName;
			fp >> buffer;
		}

		if ( buffer == "REFLECTED_NAME" ) { // we got bump map file name coming up
			fp >> this->materials.mat[i].reflectedName;
			fp >> buffer;
		}
		
	}

	//END_MATERIAL_LIST
	//fp >> buffer; 
	if ( buffer != "END_MATERIAL_LIST" ) goto failure;

	// now create objects
	//HIERARCHY_LIST H 3 top_level
	fp >> buffer; if ( buffer != "HIERARCHY_LIST" ) goto failure;
	fp >> buffer; if ( buffer != "HXP" ) goto failure;

	fp >> this->objects.count;

	fp >> this->objects.name;

//	this->objects.obj = new class rtgObject[this->objects.count];
	this->objects.obj = new class rtgObject[this->numberOfObjects];


//	for ( i=0; i<this->objects.count; i++ ) {
	for ( i=0; i<this->numberOfObjects; i++ ) {
	//0 P Square // 0 G Obj	!!!! if its n G discard it its superficial

		fp >> buffer;
		fp >> buffer; // <---- P or G
		if ( buffer == "G" ) discard++; // extremely important, G is not realy an object!
			
		fp >> this->objects.obj[i].name;

		if ( -1 == readXyz ( &fp, "tran:",		&this->objects.obj[i].translate) )	goto failure;
		if ( -1 == readXyz ( &fp, "rot:",		&this->objects.obj[i].rotate) )	goto failure;
		if ( -1 == readXyz ( &fp, "scal:",		&this->objects.obj[i].scale) )	goto failure;
		if ( -1 == readXyz ( &fp, "sPiv:",		&this->objects.obj[i].sPivot) )	goto failure;
		if ( -1 == readXyz ( &fp, "rPiv:",		&this->objects.obj[i].rPivot) )	goto failure;
		if ( -1 == readXyza ( &fp, "ltm0:",		&this->objects.obj[i].ltm0) )	goto failure;
		if ( -1 == readXyza ( &fp, "ltm1:",		&this->objects.obj[i].ltm1) )	goto failure;
		if ( -1 == readXyza ( &fp, "ltm2:",		&this->objects.obj[i].ltm2) )	goto failure;
		if ( -1 == readXyza ( &fp, "ltm3:",		&this->objects.obj[i].ltm3) )	goto failure;
	}

	//END_HIERARCHY_LIST
	fp >> buffer; if ( buffer != "END_HIERARCHY_LIST" ) goto failure;


	this->discard = discard;
//	for ( i=0; i<this->objects.count; i++ ){
	for ( i=0; i<(this->numberOfObjects-discard); i++ ){

	// now load in vertexes colors normals texcoords polyindexes
	//OBJECT_START Square v8 n24 t14 p6
	fp >> buffer; if ( buffer != "OBJECT_START" ) goto failure;
	fp >> buffer;
	fp >> letter; fp >> this->objects.obj[i].vertCount;
	fp >> letter; fp >> this->objects.obj[i].normCount;
	fp >> letter; fp >> this->objects.obj[i].texCount;
	fp >> letter; fp >> this->objects.obj[i].polyCount;
	//USES_MATERIAL 0 lambert1
		// USES_MATERIAL 2 Material__79 (there can be more than one!!!)
		// USES_MATERIAL 0 Oxidized_Metall

	fp >> buffer; if ( buffer != "USES_MATERIAL" ) goto failure;
	fp >> this->objects.obj[i].usesMaterial;
	fp >> buffer;

	fp >> buffer;

	if ( buffer == "USES_MATERIAL" ) {
		fp >> this->objects.obj[i].usesMaterial2;
		fp >> buffer;fp >> buffer;
	}
	//VERTEX world
	if ( buffer != "VERTEX" ) goto failure;
	fp >> buffer;

	// read in vertecies
	//	VERTEX world
	//	0   2.263598 -1.878061 -1.230052
	this->objects.obj[i].vertex = new VEC12[this->objects.obj[i].vertCount];
	for ( j=0; j<this->objects.obj[i].vertCount; j++ ) {
		fp >> place; if ( place != j ) goto failure;
		fp >> this->objects.obj[i].vertex[j].x;
		fp >> this->objects.obj[i].vertex[j].y;
		fp >> this->objects.obj[i].vertex[j].z;
	}


	// read in colours
	fp >> buffer; if (( buffer != "COLORS") && (buffer != "COLOR")) goto failure;
	//	COLORS
	//
	//  This is a real problem! we dont realy know how many colours there are!!!
	//  dont know how much memory is needed!!!!!!


	// 

	streampos p = fp.tellg();
	string temp="";
	// lets count all the colours first
	for ( j=0; temp != "NORMAL"; j++ ) {
		fp >> temp;// if ( place != j ) goto failure;
		fp >> buffer; fp >> buffer;	fp >> buffer; fp >> buffer; // r g b a
	}

	this->objects.obj[i].colCount = j-1;
	this->objects.obj[i].colour = new VEC16[j];

	// ok go back and now read in the colours for real
	fp.seekg( p, ios::beg);
	
	for ( j=0; j<this->objects.obj[i].colCount; j++ ) {
		fp >> place; if ( place != j ) goto failure;
		fp >> this->objects.obj[i].colour[j].x;
		fp >> this->objects.obj[i].colour[j].y;
		fp >> this->objects.obj[i].colour[j].z;
		fp >> this->objects.obj[i].colour[j].a;
	}

	// read in normals
	fp >> buffer; 
	if ( buffer != "NORMAL" ) goto failure;
	//	NORMAL
	//0   0.000000 0.000000 1.000000
	this->objects.obj[i].normal = new VEC12[this->objects.obj[i].normCount];
	for ( j=0; j<this->objects.obj[i].normCount; j++ ) {
		fp >> place; if ( place != j ) goto failure;
		fp >> this->objects.obj[i].normal[j].x;
		fp >> this->objects.obj[i].normal[j].y;
		fp >> this->objects.obj[i].normal[j].z;
	}

	// read in texture coords
	fp >> buffer; 
	if ( buffer != "TEXCOORD" ) goto failure;
	//	TEXCOORD
	//0   0.000000 0.000000 1.000000
	this->objects.obj[i].texture = new VEC8[this->objects.obj[i].texCount];
	for ( j=0; j<this->objects.obj[i].texCount; j++ ) {
		fp >> place; if ( place != j ) goto failure;
		fp >> this->objects.obj[i].texture[j].x;
		fp >> this->objects.obj[i].texture[j].y;
	}


	// ****** FARK how do I know its a quad or tri, this sux or what, had to do it the hard way, oh well
	// read in polygon indexes . .. theres gota be a better way
	fp >> buffer; if ( buffer != "POLYGON" ) goto failure;
	//	POLYGON
	//0 v 0 1 3 2 n 0 1 2 3 t 0 1 3 2  RGB 128 128 128
	this->objects.obj[i].polygon = new class rtgObjectPolygon[this->objects.obj[i].polyCount];
	for ( j=0; j<this->objects.obj[i].polyCount; j++ ) {

		fp >> place; if ( place != j ) goto failure;

		// tricky way to find variable sized polygons, here goes
		// A - read stuff from   v  to  t markers
		// this can get freakin amazing in mazive files where each line is so long!

		for ( o=0; o<199; o++) 	b[o] = 0;	// must clear it or suffer!
		
		// get stuff from current pos to the next ->   t   marker, in here we should count the number of indexes
		fp.getline (b,198,'t');

		 // B - then find number of white spaces between  the  v   and   n   markers store it in  a
		for ( o=0,a=0; b[o] != 'n'; o++ ) {
			if (b[o] == ' ') a++;
		}
		// C - figure out how many bytes we read in the get line so we can undo the getline read
		for ( o=0; b[o] !=0; o++ ) {
		}
		// D - we are back to where we started from but we know how many verts in this poly = a - 2
		fp.seekg ( -o, ios::cur );
			
		fp >> buffer; if ( buffer != "v" ) goto failure;

		// setup the polygon
		this->objects.obj[i].polygon[j].verts = a-2;
		this->objects.obj[i].polygon[j].v = new SHORT[ a-2 ];
		this->objects.obj[i].polygon[j].n = new SHORT[ a-2 ];
		this->objects.obj[i].polygon[j].t = new SHORT[ a-2 ];

		for ( o=0 ; o <	this->objects.obj[i].polygon[j].verts; o++ )
			fp >> this->objects.obj[i].polygon[j].v[o];

		fp >> buffer; if ( buffer != "n" ) goto failure;

		for ( o=0 ; o <	this->objects.obj[i].polygon[j].verts; o++ )
			fp >> this->objects.obj[i].polygon[j].n[o];

		fp >> buffer; if ( buffer != "t" ) goto failure;

		for ( o=0 ; o <	this->objects.obj[i].polygon[j].verts; o++ )
			fp >> this->objects.obj[i].polygon[j].t[o];
		
		fp >> buffer; 
		

		// polygon has either a colour, or it has a texture index
		if ( buffer != "RGB" ) {
			if ( buffer == "T" ) {
				fp >> buffer;
			}
		} else {

			fp >> this->objects.obj[i].polygon[j].colour.r;
			fp >> this->objects.obj[i].polygon[j].colour.g;
			fp >> this->objects.obj[i].polygon[j].colour.b;
		}
	}
		fp >> buffer; if ( buffer != "OBJECT_END" ) goto failure;

	}

	// close file off
	this->ready = TRUE;
	fp.close();

	return 0;
// I know , I know, you hate goto's
failure:
	this->ready = FALSE;
	return -1;
}




void rtgScene::render ( void ) {

	// dont forget the discarded @@@!!! :P
	for ( int i=0; i<this->numberOfObjects-this->discard; i++ ) {
		this->objects.obj[i].render(this);
	}
}


void rtgObject::render(class rtgScene *scn) {

	glPushMatrix();
	glTranslatef ( this->translate.x,this->translate.y,this->translate.z );
	glScalef ( this->scale.x,this->scale.y,this->scale.z );
	glRotatef ( this->rotate.x,1.0,0.0,0.0);
	glRotatef ( this->rotate.y,0.0,1.0,0.0);
	glRotatef ( this->rotate.z,0.0,0.0,1.0);

	glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
	glEnable (GL_TEXTURE_2D);

	glBindTexture(GL_TEXTURE_2D, 1);

//	print ("Using Material %d\n",this->usesMaterial);
	for ( int i=0; i<this->polyCount; i++) {

		glBegin(GL_POLYGON);
		for ( int j=0; j<this->polygon[i].verts; j++ ) {

			glNormal3f (	this->normal[ this->polygon[i].n[j] ].x,
							this->normal[ this->polygon[i].n[j] ].y,
							this->normal[ this->polygon[i].n[j] ].z
							);

			glTexCoord2f (	this->texture[ this->polygon[i].t[j] ].x,
							this->texture[ this->polygon[i].t[j] ].y
							);

			glVertex3f (	this->vertex[ this->polygon[i].v[j] ].x,
							this->vertex[ this->polygon[i].v[j] ].y,
							this->vertex[ this->polygon[i].v[j] ].z
							);
		}
		glEnd();
	}

	glPopMatrix();

}