
#include "stdafx.h"
#include "CAseModel.h"
#include "../GLDef.h"
#include <fstream>

std::string NactiText(ifstream &is)
{
	std::string ret;
	// texty jsou v "" uvozovkach, vsechno co je mezi uvozovkama nactem do ret
	char temp[255];
	is >> temp;
	int cit=1;
	while(temp[cit] != '"')
	{
		if(temp[cit] == '\0')
		{
			is >> temp;
			cit=-1;
			ret += ' ';
		}else ret += temp[cit];
		cit++;
	}
	return ret;
}

// Pokud najde vrati T, pokud nenajde a je konec souboru(end.) tak F.
void Najdi(ifstream &is, std::string text)
{
	char temp[255];
	while( strcmp(temp, text.c_str()) )
	{
		is >> temp;
	}
}

//////////////////////////////////////////////////////////////////////////
// Construktor - 
//////////////////////////////////////////////////////////////////////////
C_ASEMODEL_0::C_ASEMODEL_0()
{
	_sError = "begin";
	_bVBO = 0;
	_renMode = GL_TRIANGLES;

	//pRender = C_ASEMODEL_0::_RenderObject;
	pRender = C_ASEMODEL_0::_RenderVA;
	_enableAlpha = 1;
}

//////////////////////////////////////////////////////////////////////////
// Des. - 
//////////////////////////////////////////////////////////////////////////
C_ASEMODEL_0::~C_ASEMODEL_0()
{

}

C_ASEMODEL_0::_SetError(std::string name_er)
{
	_sError = name_er;
	//cError.ErrorMsg(0, true, true, "Model errors", name_er.c_str());
}

//////////////////////////////////////////////////////////////////////////
// ReadInt - binarne nacita integer
//////////////////////////////////////////////////////////////////////////
int ReadInt(ifstream &is)
{
	int i;
	is.read((char*)&i, sizeof(i));
	return i;
}

//////////////////////////////////////////////////////////////////////////
// ReadFloat - binarne nacita float
//////////////////////////////////////////////////////////////////////////
float ReadFloat(ifstream &is)
{
	float f;
	is.read((char*)&f, sizeof(f));
	return f;
}

//////////////////////////////////////////////////////////////////////////
// ReadChar - binarne nacita 1 znak
//////////////////////////////////////////////////////////////////////////
char ReadChar(ifstream &is)
{
	char c;
	is.read((char*)&c, sizeof(c));
	return c;
}

//////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////
std::string ReadString(ifstream &is)
{
	std::string ret;

	char c=' ';
	while(c != '\0')
	{
		is.read((char*)&c, sizeof(c));
		if(c != '\0') ret += c;
	}
	return ret;
}


//////////////////////////////////////////////////////////////////////////
// LoadModel - nacita binarni format "wfo"
//////////////////////////////////////////////////////////////////////////
bool C_ASEMODEL_0::LoadModelBinar(std::string name)
{
	ifstream is(name.c_str(), ios::binary);
	int iHeader = 0xF1A6B51A;

	if(ReadInt(is) != 0xF1A6B51A) return FALSE;
	char version = ReadChar(is);
	if(version == 1)		_LoadVersion1(is);
	else if(version == 2)	_LoadVersion2(is);
	else if(version == 3)	_LoadVersion3(is);
	else return FALSE;

	is.close();
	return TRUE;
}

bool C_ASEMODEL_0::_LoadVersion1(ifstream &is)
{
	_num_object = ReadInt(is);
	for(register i=0; i<_num_object; i++)
	{
		T_OBJECT_0 objTemp;
		objTemp.material = -1;
		objTemp.name = "binar";
		// Nacist vertexy
		objTemp.iNumVertex = ReadInt(is)*3; // pocet face
		for(register j=0; j<objTemp.iNumVertex; j++)
		{
			float x = ReadFloat(is);
			float y = ReadFloat(is);
			float z = ReadFloat(is);
			objTemp.vertex.push_back( CVector3(x, y, z) );
		}

		// Nacist texturove coordinaty
		int num_texCoord = ReadInt(is)*3;  // nacte pocet texturovych kordinatu

		for(register k=0; k<num_texCoord; k++)
		{
			float x = ReadFloat(is);
			float y = ReadFloat(is);
			objTemp.texture.push_back( CVector2(x, y) );
		}
		int num_normals = ReadInt(is);
		for(register l=0; l<num_normals*3; l++)
		{
			float x = ReadFloat(is);
			float y = ReadFloat(is);
			float z = ReadFloat(is);
			objTemp.normal.push_back( CVector3(x, y, z) );
		}
		_vObject.push_back(objTemp);
		// Nacist normaly pro facy
	}
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////
bool C_ASEMODEL_0::_LoadVersion2(ifstream &is)
{
	// Nacist maetrialy
	int numMaterial = ReadInt(is);
	for(register m=0; m<numMaterial; m++)
	{
		TMaterial tempMat;
		tempMat.name = ReadString(is);
		tempMat.patch = ReadString(is);
		_vMaterial.push_back(tempMat);
	}
	
	_num_object = ReadInt(is);
	for(register i=0; i<_num_object; i++)
	{
		T_OBJECT_0 objTemp;
		//objTemp.material = -1;
		objTemp.ren_coord=0;
		objTemp.ren_normals=0;
		objTemp.name = "binar";
		// nacist material
		objTemp.material = ReadInt(is);		
		// Nacist vertexy
		objTemp.iNumVertex = ReadInt(is)*3; // pocet face
		for(register j=0; j<objTemp.iNumVertex; j++)
		{
			float x = ReadFloat(is);
			float y = ReadFloat(is);
			float z = ReadFloat(is);
			objTemp.vertex.push_back( CVector3(x, y, z) );
		}

		// Nacist texturove coordinaty
		int num_texCoord = ReadInt(is)*3;  // nacte pocet texturovych kordinatu
		if(num_texCoord > 0) objTemp.ren_coord=1;
		for(register k=0; k<num_texCoord; k++)
		{
			float x = ReadFloat(is);
			float y = ReadFloat(is);
			objTemp.texture.push_back( CVector2(x, y) );
		}
		// Nacist normaly pro facy
		int num_normals = ReadInt(is);
		if(num_normals > 0) objTemp.ren_normals=1;
		for(register l=0; l<num_normals*3; l++)
		{
			float x = ReadFloat(is);
			float y = ReadFloat(is);
			float z = ReadFloat(is);
			objTemp.normal.push_back( CVector3(x, y, z) );
		}
		_vObject.push_back(objTemp);
	}
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////
bool C_ASEMODEL_0::_LoadVersion3(ifstream &is)
{
	// Nacist maetrialy
	int numMaterial = ReadInt(is);
	for(register m=0; m<numMaterial; m++)
	{
		TMaterial tempMat;
		tempMat.name = ReadString(is);
		tempMat.patch = ReadString(is);
		_vMaterial.push_back(tempMat);
	}

	// Load Point - nacist body
	int numPoint = ReadInt(is);
	for(register p=0; p<numPoint; p++)
	{
		T3DSpecPoint t;
		t.pos.x = ReadFloat(is);
		t.pos.y = ReadFloat(is);
		t.pos.z = ReadFloat(is);
		t.name = ReadString(is);
		_dataPoint.push_back( t );
	}
	
	_num_object = ReadInt(is);
	for(register i=0; i<_num_object; i++)
	{
		T_OBJECT_0 objTemp;
		//objTemp.material = -1;
		objTemp.ren_coord=0;
		objTemp.ren_normals=0;
		objTemp.name = "binar";
		// nacist material
		objTemp.material = ReadInt(is);		
		// Nacist vertexy
		objTemp.iNumVertex = ReadInt(is)*3; // pocet face
		for(register j=0; j<objTemp.iNumVertex; j++)
		{
			float x = ReadFloat(is);
			float y = ReadFloat(is);
			float z = ReadFloat(is);
			objTemp.vertex.push_back( CVector3(x, y, z) );
		}

		// Nacist texturove coordinaty
		int num_texCoord = ReadInt(is)*3;  // nacte pocet texturovych kordinatu
		if(num_texCoord > 0) objTemp.ren_coord=1;
		for(register k=0; k<num_texCoord; k++)
		{
			float x = ReadFloat(is);
			float y = ReadFloat(is);
			objTemp.texture.push_back( CVector2(x, y) );
		}
		// Nacist normaly pro facy
		int num_normals = ReadInt(is);
		if(num_normals > 0) objTemp.ren_normals=1;
		for(register l=0; l<num_normals*3; l++)
		{
			float x = ReadFloat(is);
			float y = ReadFloat(is);
			float z = ReadFloat(is);
			objTemp.normal.push_back( CVector3(x, y, z) );
		}
		_vObject.push_back(objTemp);
	}
	
	return TRUE;
}

void C_ASEMODEL_0::LoadModel(std::string name)
{
	std::string prip = W_GetPripona(name);
	if(prip == "txt")
	{
		if(!LoadModelText(name)) cError.ErrorMsg(0, true, true, "Model error(TXT)", _sError);
	}else
	if(prip == "wfo")
	{
		if(!LoadModelBinar(name)) cError.ErrorMsg(0, true, true, W_GetString("Model error(BIN) %s ", name.c_str() ), _sError);
	}
}

//////////////////////////////////////////////////////////////////////////
// LoadModel - 
//////////////////////////////////////////////////////////////////////////
bool C_ASEMODEL_0::LoadModelText(std::string name)
{
	ifstream is;
	float version;
	char temp[255];
	is.open( name.c_str() );
	if(!is)
	{
		_SetError("No file laod");
		return FALSE;
	}
	
	is >> temp;
	if( !strcmp(temp, "W_Format_object") )
	{
		is >> version;
	}else
	{
		_SetError("No file format");
		return FALSE;
	}

	if(version == 1.0)			_LoadTextVersion1(is);
	else if(version == 1.1f)	_LoadTextVersion11(is);
	else
	{
		_SetError("Valid version");
		return FALSE;
	}
	
	is.close();
	return TRUE;
}

bool C_ASEMODEL_0::_LoadTextVersion1(ifstream &is)
{
	char temp[255];
	int iTemp=0;
	Najdi(is, "NUM_OBJECT");
	is >> _num_object;	
	for(register i=0; i<_num_object; i++)
	{
		Najdi(is, "OBJECT");
		T_OBJECT_0 objTemp;
		is >> objTemp.name;
		// Nacist vertexy
		Najdi(is, "NUM_FACE");
		is >> iTemp;
		objTemp.iNumVertex = iTemp*3;
		for(register j=0; j<objTemp.iNumVertex; j++)
		{
			float x, y, z;
			is >> x;
			is >> y;
			is >> z;
			//CVector3 vecTemp(x, y, z);
			objTemp.vertex.push_back( CVector3(x, y, z) );
		}
		// Nacist texturove coordinaty
		Najdi(is, "NUM_FACETEXCOORD");
		is >> iTemp;
		for(register k=0; k<objTemp.iNumVertex; k++)
		{
			float x, y;
			is >> x;
			is >> y;
			objTemp.texture.push_back( CVector2(x, y) );
		}
		Najdi(is, "NUM_NORMALS");
		is >> iTemp;
		for(register l=0; l<objTemp.iNumVertex; l++)
		{
			float x, y, z;
			is >> x >> y >> z;
			objTemp.normal.push_back( CVector3(x, y, z) );
		}
		_vObject.push_back(objTemp);
		// Nacist normaly pro facy
	}
	return TRUE;
}

bool C_ASEMODEL_0::_LoadTextVersion11(ifstream &is)
{
	char temp[255];
	int iTemp=0;
	// nacist materialy //
	Najdi(is, "MATERIAL_COUNT");
	int matCount;
	is >> matCount;
	for(register j=0; j<matCount; j++)
	{
		TMaterial matTemp;
		Najdi(is, "NAME");
		matTemp.name = NactiText(is);
		Najdi(is, "PATCH");
		matTemp.patch = NactiText(is);
		_vMaterial.push_back(matTemp);
	}
	
	Najdi(is, "NUM_OBJECT");
	is >> _num_object;	
	for(register i=0; i<_num_object; i++)
	{
		Najdi(is, "OBJECT");
		T_OBJECT_0 objTemp;
		is >> objTemp.name;
		Najdi(is, "MATERIAL");
		is >> objTemp.material;
		// Nacist vertexy
		Najdi(is, "NUM_FACE");
		is >> iTemp;
		objTemp.iNumVertex = iTemp*3;
		for(register j=0; j<objTemp.iNumVertex; j++)
		{
			float x, y, z;
			is >> x;
			is >> y;
			is >> z;
			//CVector3 vecTemp(x, y, z);
			objTemp.vertex.push_back( CVector3(x, y, z) );
		}
		// Nacist texturove coordinaty
		Najdi(is, "NUM_FACETEXCOORD");
		is >> iTemp;
		for(register k=0; k<objTemp.iNumVertex; k++)
		{
			float x, y;
			is >> x;
			is >> y;
			objTemp.texture.push_back( CVector2(x, y) );
		}
		Najdi(is, "NUM_NORMALS");
		is >> iTemp;
		for(register l=0; l<objTemp.iNumVertex; l++)
		{
			float x, y, z;
			is >> x >> y >> z;
			objTemp.normal.push_back( CVector3(x, y, z) );
		}
		_vObject.push_back(objTemp);
		// Nacist normaly pro facy
	}
	return TRUE;
}

void C_ASEMODEL_0::Render()
{
	(this->*pRender)();
}

void C_ASEMODEL_0::_RenderObject()
{
	glColor3ub(255, 255, 255);
	std::vector<T_OBJECT_0>::iterator iter = _vObject.begin();
	for(; iter != _vObject.end(); iter++)
	{
		if(_vMaterial.size() > 0 && (int)iter->material != (int)-1)
		{ 
			static uint lastTexture=0;
			if( lastTexture != _vMaterial[iter->material].texture_id )
			{
				glBindTexture(GL_TEXTURE_2D, _vMaterial[iter->material].texture_id );
				lastTexture =  _vMaterial[iter->material].texture_id;
			}
			//glBindTexture(GL_TEXTURE_2D, _vMaterial[iter->material].texture_id);
			glEnable(GL_TEXTURE_2D);
		}
		for(register k=0; k<iter->iNumVertex; k+=3)
		{
			CVector3 a = iter->vertex[k];
			CVector3 b = iter->vertex[k+1];
			CVector3 c = iter->vertex[k+2];

			CVector2 e, f, g;
			if(iter->ren_coord)
			{
				e = iter->texture[k];
				f = iter->texture[k+1];
				g = iter->texture[k+2];
			}

			CVector3 n1, n2, n3;
			if(iter->ren_normals)
			{
				n1 = iter->normal[k];
				n2 = iter->normal[k+1];
				n3 = iter->normal[k+2];
			}
			glBegin(_renMode);
				if(iter->ren_normals) glNormal3f(n1.x, n1.y, n1.z);
				if(iter->ren_coord) glTexCoord2f(e.x, e.y); 
				glVertex3f(a.x, a.y, a.z);
				if(iter->ren_normals) glNormal3f(n2.x, n2.y, n2.z);
				if(iter->ren_coord) glTexCoord2f(f.x, f.y); 
				glVertex3f(b.x, b.y, b.z);
				if(iter->ren_normals) glNormal3f(n3.x, n3.y, n3.z);
				if(iter->ren_coord) glTexCoord2f(g.x, g.y); 
				glVertex3f(c.x, c.y, c.z);
			glEnd();
		}
	}

	glDisable(GL_TEXTURE_2D);	
}

void C_ASEMODEL_0::_RenderVA()
{
	// osetrit vykreslovani
//	glEnable(GL_CULL_FACE);
	glEnableClientState( GL_VERTEX_ARRAY );

	std::vector<T_OBJECT_0>::iterator iter = _vObject.begin();
	for(; iter != _vObject.end(); iter++)
	{
		// !!!! //
		/*glColor3f(1,1,1);
		if( iter == _vObject.end()-9-56 )
		{
			glBlendFunc(GL_SRC_ALPHA,GL_ONE);
			//glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); 
			glEnable( GL_BLEND );
			glColor4f(1,0,0, 1.0f);
		}*/
		// !!!! //
		if( iter->ren_coord ) glEnableClientState( GL_TEXTURE_COORD_ARRAY );
		else glDisableClientState( GL_TEXTURE_COORD_ARRAY );
		if( iter->ren_normals ) glEnableClientState( GL_NORMAL_ARRAY );
		else glDisableClientState( GL_NORMAL_ARRAY );
		
		if(_vMaterial.size() > 0 && (int)iter->material != (int)-1)
		{ 
			glBindTexture(GL_TEXTURE_2D, _vMaterial[iter->material].texture_id);
			glEnable(GL_TEXTURE_2D);
		}
		if( _enableAlpha ) glEnable(GL_ALPHA_TEST);
		glNormalPointer(GL_FLOAT, 0, &iter->normal[0] );
		glTexCoordPointer(2, GL_FLOAT, 0, &iter->texture[0] );
		glVertexPointer(3, GL_FLOAT, 0, &iter->vertex[0] );
		glDrawArrays(_renMode, 0, iter->iNumVertex);
	}
	

	glDisableClientState( GL_NORMAL_ARRAY );
	glDisableClientState( GL_TEXTURE_COORD_ARRAY );
	glDisableClientState( GL_VERTEX_ARRAY );
	glDisable(GL_CULL_FACE);
}

//////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////
void C_ASEMODEL_0::Translate(float x, float y, float z)
{
	std::vector<T_OBJECT_0>::iterator iter = _vObject.begin();
	for(; iter != _vObject.end(); iter++)
	{
		for(register k=0; k<iter->iNumVertex; k+=3)
		{
			CVector3 *a = &iter->vertex[k];
			CVector3 *b = &iter->vertex[k+1];
			CVector3 *c = &iter->vertex[k+2];

			a->x /= x;
			a->y /= y;
			a->z /= z;
			b->x /= x;
			b->y /= y;
			b->z /= z;
			c->x /= x;
			c->y /= y;
			c->z /= z;
		}
	}
	std::vector<T3DSpecPoint>::iterator it = _dataPoint.begin();
	for(; it != _dataPoint.end(); it++)
	{
		CVector3 *v = &it->pos;
		v->x /= x;
		v->y /= y;
		v->z /= z;
	}
}

//////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////
void C_ASEMODEL_0::ReloadTexture(C_TEXTURE_MANAGER_0 &tm)
{
	std::vector<TMaterial>::iterator iter = _vMaterial.begin();	
	for(; iter != _vMaterial.end(); iter++)
	{
		iter->flag = TM_LINEAR;
		tm.SetAlphaRozmezi(0);
		tm.SetColorAlpha(255,0,255);
		iter->tm_id = tm.AddTexture(iter->patch, iter->flag,1);
		tm.ReloadTextures();
		iter->texture_id = tm.GetIdTexture( iter->tm_id );
	}
}

//////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////
TBBox C_ASEMODEL_0::GetBBox()
{
	TBBox ret;
	static bool init;
	init=0;
	
	std::vector<T_OBJECT_0>::iterator iter = _vObject.begin();
	for(; iter != _vObject.end(); iter++)
	{
		for(register k=0; k<iter->iNumVertex; k++)
		{
			CVector3 *a = &iter->vertex[k];
			if(!init)
			{
				ret.xMin = ret.xMax = a->x;
				ret.yMin = ret.yMax = a->y;
				ret.zMin = ret.zMax = a->z;
				init=1;
				continue;
			}
			if(a->x < ret.xMin) ret.xMin = a->x;
			if(a->y < ret.yMin) ret.yMin = a->y;
			if(a->z < ret.zMin) ret.zMin = a->z;

			if(a->x > ret.xMax) ret.xMax = a->x;
			if(a->y > ret.yMax) ret.yMax = a->y;
			if(a->z > ret.zMax) ret.zMax = a->z;	
		}
	}
	return ret;
}

void C_ASEMODEL_0::DeleteTexture( C_TEXTURE_MANAGER_0 &tm )
{
	std::vector<TMaterial>::iterator i = _vMaterial.begin();
	for(; i != _vMaterial.end(); i++)
	{
		tm.DeleteTexture( i->tm_id );
	}
}

void C_ASEMODEL_0::Delete()
{
	_vMaterial.clear();
	_vObject.clear();
	_dataPoint.clear();
}

//////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////
CVector3 C_ASEMODEL_0::GetPosPoint( std::string name )
{
	std::vector<T3DSpecPoint>::iterator it = _dataPoint.begin();
	for(; it != _dataPoint.end(); it++)
	{
		if( it->name == name ) return it->pos;
	}
	return CV3_NULL;
}