// Model.cpp

#include <windows.h>
#include <stdlib.h>
	#include <stdio.h>

#include "Types.h"
#include "File.h"
#include "PGF.h"
#include "P3D.h"
#include "Math.h"
#include "Misc.h"
#include "Object.h"
#include "Model.h"


#define SCALE 25.4F


CGeomTex::CGeomTex()
{
	Name[0] = 0;
}


void CGeomTex::Load( const char *filename )
{
	strcpy( Name, filename );

	if (stricmp( filename, "FRONT" ) == 0)
	{
		Width = 32;
		Height = 64;
	}

	if (stricmp( filename, "TOP" ) == 0)
	{
		Width = 32;
		Height = 53;
	}

	if (stricmp( filename, "BACK" ) == 0)
	{
		Width = 16;
		Height = 64;
	}

	if (stricmp( filename, "SIDE" ) == 0)
	{
		Width = 16;
		Height = 64;
	}
}


void CModel::LoadTextures( CPhilGenFile &pgf )
{
	CGeomTex
		*tex;
	s32
		i,
		count;
	char
		filename[32],
		pathname[MAX_PATH];

	count = pgf.ReadLong();

	for (i=0; i<count; i++)
	{
		pgf.ReadString( pathname );
		_splitpath( pathname, NULL, NULL, filename, NULL );

		tex = new CGeomTex;
		tex->Load( filename );
		Textures.Add( tex );
	}
}


void CModel::LoadObject( CPhilGenFile &pgf )
{
	CObject
		*obj;
	Matrix3
		matrix;
	Vector3
		v;
	SFace
		*face;
	s32
		i,
		id = 0,
		count;
	char
		name[64];

	if (Frame < 0 || Frame > 1)
		return;


	pgf.ReadString( name );
//	printf( "Object: %s\n", name );

	obj = Find( name );
	if (!obj)
		obj = Add( name );

	while (id != PGF_ID_END)
	{
		id = pgf.OpenChunk();

		switch (id)
		{
			case P3D_ID_MATRIX:
			case P3D_ID_MATRIX2:
				pgf.Read( matrix.m, 3*4*4 );
				matrix.ScaleBy( SCALE );
				matrix.t[0] *= SCALE;
				matrix.t[1] *= SCALE;
				matrix.t[2] *= SCALE;
				matrix.GetTrans( &v );
				obj->SetBase( Frame, &v );
				break;

			case P3D_ID_VERTICES:
				count = pgf.ReadLong();

				obj->AllocVerts( count );

				for (i=0; i<count; i++)
				{
					pgf.Read( &v.x, 3*4 );
					matrix.Transform( &v );
					obj->SetVert( Frame, i, &v );
				}
				break;

			case P3D_ID_FACES:
				count = pgf.ReadLong();

				obj->AllocFaces( count );

				for (i=0; i<count; i++)
				{
					face = obj->GetFace( i );

					pgf.Read( &face->vtx, 3*4 );
					pgf.Skip( 4 );

					face->tex = -1;
					face->TexName[0] = 0;
				}
				break;

			case P3D_ID_MATERIALS:
				count = pgf.ReadLong();

				for (i=0; i<count; i++)
				{
					face = obj->GetFace( i );

					id = pgf.ReadLong();

					if (id & 1)
					{
						face->tex = pgf.ReadLong();
						pgf.Read( &face->uv, 3*sizeof( SUV ) );
					}
					else
					{
						memset( &face->uv, 0, 3 * sizeof( SUV ) );
						pgf.Skip( 4 );
					}
				}
				break;
		}

		pgf.CloseChunk();
	}
}


CModel::CModel()
{
	Frame = 0;
}


CModel::~CModel()
{
}


void CModel::LoadP3D( const char *filename )
{
	CPhilGenFile
		pgf;
	CObject
		*obj;
	CGeomTex
		*tex;
	SFace
		*face;
	s32
		i,
		f,
		id = 0,
		type,
		version,
		size;

	Objects.Clear();
	Textures.Clear();


	if (!pgf.OpenFile( filename, &type, &version, &size ))
	{
		Error( "'%s' is not a P3D file.", filename );
		return;
	}

	if (type != P3D_ID_P3D)
	{
		Error( "'%s' is not a P3D file.", filename );
		return;
	}

	if (HIWORD( version ) != P3D_VER_MAJOR)
	{
		Error( "Cannot handle version %d.%02d", HIWORD( version ), LOWORD( version ) );
		return;
	}


	while (id != PGF_ID_END)
	{
		id = pgf.OpenChunk();

		if (id == P3D_ID_FRAME)
		{
			Frame = pgf.ReadLong();
//			printf( "Frame = %d\n", Frame );

			while (id != PGF_ID_END)
			{
				id = pgf.OpenChunk();

				if (id == P3D_ID_OBJECT)
					LoadObject( pgf );

				pgf.CloseChunk();
			}

			id = 0;
		}
		else if (id == P3D_ID_TEXTURES)
		{
			LoadTextures( pgf );
		}

		pgf.CloseChunk();
	}

	pgf.CloseFile();


	for (i=0; i<Objects.Count; i++)
	{
		obj = Objects[i];

		for (f=0; f<obj->NumFaces; f++)
		{
			face = obj->GetFace( f );

			if (face->tex >= 0)
			{
				tex = Textures[face->tex];
				strcpy( face->TexName, tex->Name );
			}
		}
	}
}


CObject *CModel::Add( const char *name )
{
	CObject
		*obj;

	obj = new CObject;
	strcpy( obj->Name, name );
	Objects.Add( obj );

	return( obj );
}


CObject *CModel::Find( const char *name )
{
	CObject
		*obj;
	s32
		i;

	for (i=0; i<Objects.Count; i++)
	{
		obj = Objects[i];
		if (!stricmp( obj->Name, name ))
			return( obj );
	}

	return( NULL );
}
