#include "directgem.h"
#include "gemmath.h"
#include "loader.h"
#include "enum.h"

VOID CalculateVectorKey( gem_VectorTrack::gem_VectorKey* key, DWORD n )
{
	gem_Vector					g1 = (key[n].vec - key[n-1].vec)*(1+key[n].B);
	gem_Vector					g2 = (key[n+1].vec - key[n].vec)*(1-key[n].B);
	gem_Vector					g3 = 0.5*(g2 - g1);	
 	
	FLOAT		delta	= ((FLOAT)key[n+1].frame - (FLOAT)key[n-1].frame)*0.5;
	FLOAT		deltaT1 = (key[n].frame - key[n-1].frame) / delta;
	FLOAT		deltaT2 = (key[n+1].frame - key[n].frame) / delta;		

	key[n].an = (g1 + g3*(1 + key[n].C))*(1 - key[n].T)*deltaT1;
	key[n].bn = (g1 + g3*(1 - key[n].C))*(1 - key[n].T)*deltaT2;
	
}


VOID CalculateFirstVectorKey( gem_VectorTrack::gem_VectorKey* key )
{
	gem_Vector					g1 = key[1].vec - key[0].vec; 

	key[0].an = (g1*1.5-key[1].bn*0.5)*(1-key[0].T);
	key[0].bn = gem_Vector(0,0,0);    	
}


VOID CalculateLastVectorKey( gem_VectorTrack::gem_VectorKey* key, DWORD n )
{
	gem_Vector					g1 = key[n].vec - key[n-1].vec;
	
	key[n].an = gem_Vector(0,0,0);
	key[n].bn = (g1*1.5 - key[n-1].bn*0.5)*(1-key[n].T);	
}
	
VOID Init2KeysVectorTrack( gem_VectorTrack::gem_VectorKey* key )
{	
	gem_Vector					g1 = key[1].vec - key[0].vec;

	key[0].an = g1*(1-key[0].C);
	key[0].bn = gem_Vector(0,0,0);
		
	key[1].an=gem_Vector(0,0,0);
	key[1].bn=g1*(1-key[1].C);
}

gem_VectorTrack::gem_VectorTrack()
{
}

gem_VectorTrack::~gem_VectorTrack()
{
	delete  keys;
}


VOID gem_VectorTrack::Init()
{
	DWORD						i;

	if( dwKeyNumber < 2 )
		return;	

	if( dwKeyNumber == 2 )
		Init2KeysVectorTrack( keys );	
	else
	{
		for( i = 1 ; i<dwKeyNumber-1 ; i++ )
			CalculateVectorKey( keys, i );

		CalculateFirstVectorKey( keys );
		CalculateLastVectorKey( keys, dwKeyNumber-1 );
	}
}


gem_Vector gem_VectorTrack::Interpolation( FLOAT frame )
{	
	FLOAT						h[4];
	FLOAT						t, t2, t3;
	DWORD						i;
		

	if( dwKeyNumber < 2 )	
		return keys[0].vec;
			

	for( i = 0 ; i<dwKeyNumber-1 ; i++ )
	{
		if( (FLOAT)keys[i].frame<=frame && (FLOAT)frame<keys[i+1].frame )
			break;
	}
	
	if( i >= dwKeyNumber-1 )	
		return keys[dwKeyNumber-1].vec;
		
			
	t = ( frame - (FLOAT)keys[i].frame)/((FLOAT)keys[i+1].frame - (FLOAT)keys[i].frame);
	t = RemapEase( t, keys[i].EaseFrom, keys[i].EaseTo );

	t2 = t*t;
	t3 = t2*t;

	h[0]=2.0f*t3 - 3.0f*t2 + 1.0f;
	h[1]=t3 - 2.0f*t2 + t;
	h[2]=-2.0f*t3 + 3.0f*t2;
	h[3]=t3 - t2;

	return h[0]*keys[i].vec + h[1]*keys[i].bn + h[2]*keys[i+1].vec + h[3]*keys[i+1].an;
	
}

DWORD gem_VectorTrack::Load( FILE* inFile )
{

	DWORD						number;
	WORD						flag;
	FLOAT						a, b, c;
	DWORD						frame;		

	ReadDword( inFile );
	ReadWord( inFile );
	ReadDword( inFile );
	ReadDword( inFile );

	number = ReadDword( inFile );
	dwKeyNumber = number;
	keys = new gem_VectorKey[number];

	for( DWORD i = 0 ; (! feof( inFile ) ) && i<number ; i++ )
	{		

		frame = ReadDword( inFile );
		keys[i].frame=frame;

		keys[i].T = 0.0f;
		keys[i].B = 0.0f;
		keys[i].C = 0.0f;
		keys[i].EaseFrom = 0.0f;
		keys[i].EaseTo = 0.0f;

		flag = ReadWord( inFile );
		for( DWORD j = 0 ; j<16 ; j++ )
			if( flag&(1<<j) )
				switch( j )
				{
					case 0: 
						keys[i].T = ReadFloat( inFile ); 
					break;

					case 1: 
						keys[i].C = ReadFloat( inFile ); 
					break;

					case 2: 
						keys[i].B = ReadFloat( inFile ); 
					break;

					case 3: 
						keys[i].EaseTo = ReadFloat( inFile ); 
					break;

					case 4: 
						keys[i].EaseFrom = ReadFloat( inFile ); 
					break;
				}

		a = ReadFloat( inFile );
		b = ReadFloat( inFile );
		c = ReadFloat( inFile );
		keys[i].vec.x = a;
		keys[i].vec.y = c;	
		keys[i].vec.z = b;		
	}

	if( feof( inFile ) )
		return GEMERROR_LOAD;

	return GEMERROR_OK;
}



/*
VOID CalculateFirstQuatKey(GEM_KEY* key)
{
	gem_Quat		q1 = UnityInverse(key->_qtr)*key->next->_qtr;	
	gem_Quat		log1 = ln(q1);
	gem_Quat		log2 = ln(q1);

	gem_Quat		t0;
	gem_Quat		t1;

	t0 = 0.5*(1-key->tension)*(1-key->continuity)*(1-key->bias)*log1 +
		 0.5*(1-key->tension)*(1+key->continuity)*(1+key->bias)*log2;						

	t1 = 0.5*(1-key->tension)*(1+key->continuity)*(1-key->bias)*log1 +
		 0.5*(1-key->tension)*(1-key->continuity)*(1+key->bias)*log2;						

	t0 = 0.5*(t0 - log1);
	t1 = 0.5*(log2 - t1);

	key->an=key->_qtr*exp(t0);
	key->bn=key->_qtr*exp(t1);
}

VOID CalculateLastQuatKey(GEM_KEY* key)
{
	gem_Quat		q2 = UnityInverse(key->prev->_qtr)*key->_qtr;
	gem_Quat		log1 = ln(q2);
	gem_Quat		log2 = ln(q2);

	gem_Quat		t0;
	gem_Quat		t1;

	t0 = 0.5*(1-key->tension)*(1-key->continuity)*(1-key->bias)*log1 +
		 0.5*(1-key->tension)*(1+key->continuity)*(1+key->bias)*log2;						

	t1 = 0.5*(1-key->tension)*(1+key->continuity)*(1-key->bias)*log1 +
		 0.5*(1-key->tension)*(1-key->continuity)*(1+key->bias)*log2;						

	t0 = 0.5*(t0 - log1);
	t1 = 0.5*(log2 - t1);

	key->an=key->_qtr*exp(t0);
	key->bn=key->_qtr*exp(t1);
}


VOID Init2KeysQuatSpline(GEM_TRACK* track)
{
	GEM_KEY*		key = track->keyList;

	CalculateFirstQuatKey( key );
	CalculateLastQuatKey( key->next );
}


VOID CalculateQuatKey(GEM_KEY* key)
{

	
	gem_Quat		q1 = UnityInverse(key->_qtr)*key->next->_qtr;
	gem_Quat		q2 = UnityInverse(key->prev->_qtr)*key->_qtr;
	gem_Quat		log1 = ln(q1);
	gem_Quat		log2 = ln(q2);

	FLOAT			delta = (key->next->frame - key->prev->frame);
	if( delta==0.0f ) 
		delta = 1.0f;

	FLOAT			deltaT1 = (key->next->frame - key->frame) / delta;
	FLOAT			deltaT2 = (key->frame - key->prev->frame) / delta;

	gem_Quat		t0;
	gem_Quat		t1;

	t0 = 0.5*(1-key->tension)*(1-key->continuity)*(1-key->bias)*log1 +
		 0.5*(1-key->tension)*(1+key->continuity)*(1+key->bias)*log2;						

	t1 = 0.5*(1-key->tension)*(1+key->continuity)*(1-key->bias)*log1 +
		 0.5*(1-key->tension)*(1-key->continuity)*(1+key->bias)*log2;						

	t0 = 0.5*(t0 - log1);
	t1 = 0.5*(log2 - t1);

	key->an=deltaT1*key->_qtr*exp(t0);
	key->bn=deltaT2*key->_qtr*exp(t1);
}

VOID InitQuatSpline(GEM_TRACK* track)
{
	GEM_KEY*		key = track->keyList;

	if( !key || !key->next )
		return;

	key=key->next;
	
	//make all quaternions to have acute angles (q and -q represent the same rot)
	for( GEM_KEY* tmp = track->keyList ; tmp->next; tmp = tmp->next )
		if( Dot( tmp->_qtr, tmp->next->_qtr)<0.0f )
			tmp->next->_qtr = -tmp->next->_qtr;

	if( !key->next)
		Init2KeysQuatSpline( track);
	else
	{
		for( ; key->next ; key = key->next )					
			CalculateQuatKey( key );

		CalculateFirstQuatKey( track->keyList );
		CalculateLastQuatKey( key );
	}
}

gem_Quat QuatSpline(GEM_TRACK* track, DWORD frame)
{
	GEM_KEY*		key = track->keyList;
	FLOAT		t;
	gem_Quat	q;

	if( !key->next )
		return key->_qtr;

	for( ; key->next && key->next->frame<frame; key = key->next );

	if( !key->next )
		return key->_qtr;

	t=((FLOAT)frame - (FLOAT)key->frame)/((FLOAT)key->next->frame - (FLOAT)key->frame);
	RemapEase( t, key->easefrom, key->easeto );

	q = SQUAD( key->_qtr, key->an, key->next->bn, key->next->_qtr, t );
	return q;
}
*/


VOID CalculateQuatKey( gem_RotationTrack::gem_RotationKey* key, DWORD n )
{
	gem_Quat			q0, q1, q2;
	gem_Quat			g1, g2, g3;

	q0=key[n-1].qtr;
	q1=key[n].qtr;
	q2=key[n+1].qtr;

	g1=SLERP(q1,q0,-(1+key[n].B)/3.0);
	g2=SLERP(q1,q2, (1-key[n].B)/3.0);


	g3=SLERP(g1,g2,0.5*(1-key[n].C));
	key[n].an=SLERP(q1,g3,1-key[n].T);


	g3=SLERP(g1,g2,0.5*(1+key[n].C));
	key[n].bn=SLERP(q1,g3,key[n].T-1);

}


VOID CalculateFirstQuatKey( gem_RotationTrack::gem_RotationKey* key )
{
	gem_Quat			q0, q1;

	q0=key[0].qtr;
	q1=key[1].qtr;

	key[0].an=SLERP(q0,q1,(1-key[0].T)*(1+key[0].C*key[0].B)/3.0);
	key[0].bn=gem_Quat(0,0,0,0);		
}


VOID CalculateLastQuatKey( gem_RotationTrack::gem_RotationKey* key, DWORD n )
{
	gem_Quat			qn, qn_1;

	qn=key[n].qtr;
	qn_1=key[n-1].qtr;

	key[n].an=gem_Quat(0,0,0,0);	
	key[n].bn=SLERP(qn,qn_1,(1-key[n].T)*(1-key[n].C*key[n].B)/3.0);
}


VOID Init2KeysQuatTrack( gem_RotationTrack::gem_RotationKey* key )
{	
	gem_Quat			q0, q1;

	q0=key[0].qtr;
	q1=key[1].qtr;

	key[0].an=SLERP(q0,q1,(1-key[0].T)*(1+key[0].C*key[0].B)/3.0);
	key[0].bn=gem_Quat(0,0,0,0);

	key[1].an=gem_Quat(0,0,0,0);
	key[1].bn=SLERP(q1,q0,(1-key[1].T)*(1-key[1].C*key[1].B)/3.0);

}

gem_RotationTrack::gem_RotationTrack() 
{
}

gem_RotationTrack::~gem_RotationTrack()
{
	delete keys;
}


VOID gem_RotationTrack::Init()
{
	DWORD			i;

	if( dwKeyNumber < 2 )
		return;

	for( i = 0 ; i<dwKeyNumber-1 ; i++ )
		if( Dot( keys[i].qtr, keys[i+1].qtr)<0.0f )
			keys[i+1].qtr = -keys[i+1].qtr;			

	if( dwKeyNumber == 2 )
		Init2KeysQuatTrack( keys );	
	else
	{
		for( i = 1 ; i<dwKeyNumber-1 ; i++ )
			CalculateQuatKey( keys, i );

		CalculateFirstQuatKey( keys );
		CalculateLastQuatKey( keys, dwKeyNumber-1 );
	}
}

gem_Quat gem_RotationTrack::Interpolation( FLOAT frame )
{	
	DWORD				i;
	FLOAT				t;
	gem_Quat			q0, q1, q2;
			
	if( dwKeyNumber < 2 )	
		return keys[0].qtr;			

	for( i = 0; i<dwKeyNumber-1 ; i++ )
	{
		if( (FLOAT)keys[i].frame<=frame && frame<(FLOAT)keys[i+1].frame )
			break;
	}

	if ( i >= dwKeyNumber-1 )	
		return  keys[dwKeyNumber-1].qtr;			

	t = ( frame-(FLOAT)keys[i].frame )/((FLOAT)keys[i+1].frame-(FLOAT)keys[i].frame);
	t = RemapEase( t, keys[i].EaseFrom, keys[i+1].EaseTo );

	q0 = SLERP( keys[i].qtr, keys[i].an, t );
	q1 = SLERP( keys[i].an, keys[i+1].bn, t);
	q2 = SLERP( keys[i+1].bn, keys[i+1].qtr, t );

	q0 = SLERP( q0, q1, t );
	q1 = SLERP( q1, q2, t );

	return SLERP( q0, q1, t );	
}


DWORD gem_RotationTrack::Load( FILE* inFile )
{		
	DWORD						number;
	WORD						flag;
	FLOAT						angle, a, b, c;
	DWORD						frame;
	gem_Quat					prev( 1,0,0,0 );		

	ReadDword( inFile );
	ReadWord( inFile );
	ReadDword( inFile );
	ReadDword( inFile );

	number = ReadDword( inFile );
	dwKeyNumber = number;
	keys = new gem_RotationKey[number];

	for( DWORD i = 0 ; ( !feof( inFile ) ) && i<number ; i++ )
	{
		
		frame = ReadDword( inFile );
		keys[i].frame = frame;

		keys[i].T = 0.0f;
		keys[i].B = 0.0f;
		keys[i].C = 0.0f;
		keys[i].EaseFrom = 0.0f;
		keys[i].EaseTo = 0.0f;

		flag = ReadWord( inFile );
		for( DWORD j = 0 ; j<16 ; j++ )
			if( flag&(1<<j) )
				switch( j )
				{
					case 0: 
						keys[i].T = ReadFloat( inFile ); 
					break;

					case 1: 
						keys[i].C = ReadFloat( inFile ); 
					break;

					case 2: 
						keys[i].B = ReadFloat( inFile ); 
					break;

					case 3: 
						keys[i].EaseTo = ReadFloat( inFile ); 
					break;

					case 4: 
						keys[i].EaseFrom = ReadFloat( inFile ); 
					break;
				}
		
		angle = ReadFloat( inFile );
		a = ReadFloat( inFile );
		b = ReadFloat( inFile );
		c = ReadFloat( inFile );

		keys[i].qtr = prev*FromAxisAngle( a, c, b, angle );
		prev = keys[i].qtr;		
	}

	if( feof( inFile ) )
		return GEMERROR_LOAD;

	return GEMERROR_OK;
}
	
VOID CalculateFloatKey( gem_FloatTrack::gem_FloatKey* key, DWORD n )
{
	FLOAT						g1 = (key[n].val - key[n-1].val)*(1+key[n].B);
	FLOAT						g2 = (key[n+1].val - key[n].val)*(1-key[n].B);
	FLOAT						g3 = 0.5*(g2 - g1);
	
	FLOAT		delta	= ((FLOAT)key[n+1].frame - (FLOAT)key[n-1].frame)*0.5f;
	FLOAT		deltaT1 = (key[n].frame - key[n-1].frame) / delta;
	FLOAT		deltaT2 = (key[n+1].frame - key[n].frame) / delta;		

	key[n].an = (g1 + g3*(1 + key[n].C))*(1 - key[n].T)*deltaT1;
	key[n].bn = (g1 + g3*(1 - key[n].C))*(1 - key[n].T)*deltaT2;
	
}



VOID CalculateFirstFloatKey( gem_FloatTrack::gem_FloatKey* key )
{
	FLOAT			g1 = key[1].val - key[0].val; 

	key[0].an = (g1*1.5-key[1].bn*0.5)*(1-key[0].T);
	key[0].bn = 0;    	
}


VOID CalculateLastFloatKey( gem_FloatTrack::gem_FloatKey* key, DWORD n )
{
	FLOAT			g1 = key[n].val - key[n-1].val;

	key[n].an = 0;
	key[n].bn = (g1*1.5 - key[n-1].an*0.5)*(1-key[n].T);	
}
	
VOID Init2KeysFloatTrack( gem_FloatTrack::gem_FloatKey* key )
{	
	FLOAT			g1 = key[1].val - key[0].val;

	key[0].an = g1*(1-key[0].C);
	key[0].bn = 0;
	
	key[1].an = 0;
	key[1].bn = g1*(1-key[1].C);	
}


//constructor, just set a type and reference to "mother" scene
gem_FloatTrack::gem_FloatTrack()
{
}

//delete table of keys
gem_FloatTrack::~gem_FloatTrack()
{
	delete keys;
}


//initialization, calculating control values
VOID gem_FloatTrack::Init()
{
	DWORD			i;

	if( dwKeyNumber < 2 )
		return;	

	if( dwKeyNumber == 2 )
		Init2KeysFloatTrack( keys );	
	else
	{
		for( i = 1 ; i<dwKeyNumber-1 ; i++ )
			CalculateFloatKey( keys, i );

		CalculateFirstFloatKey( keys );
		CalculateLastFloatKey( keys, dwKeyNumber-1 );
	}
}

//interpolation
FLOAT gem_FloatTrack::Interpolation( FLOAT frame )
{	
	FLOAT				h[4];
	FLOAT				t, t2, t3;	
	DWORD				i;
	
	if( dwKeyNumber < 2 )	
		return keys[0].val;;	

	for( i = 0 ; i<dwKeyNumber-1 ; i++ )
	{
		if( (FLOAT)keys[i].frame<=frame && frame<(FLOAT)keys[i+1].frame )
			break;
	}

	if( i >= dwKeyNumber-1 )	
		return keys[dwKeyNumber-1].val;		
				
	t = ( frame - (FLOAT)keys[i].frame)/((FLOAT)keys[i+1].frame - (FLOAT)keys[i].frame);
	t = RemapEase( t, keys[i].EaseFrom, keys[i].EaseTo );

	t2 = t*t;
	t3 = t2*t;

	h[0] = 2.0f*t3 - 3.0f*t2 + 1.0f;
	h[1] = t3 - 2.0f*t2 + t;
	h[2] = -2.0f*t3 + 3.0f*t2;
	h[3] = t3 - t2;

	return h[0]*keys[i].val + h[1]*keys[i].bn + h[2]*keys[i+1].val + h[3]*keys[i+1].an;

}

DWORD gem_FloatTrack::Load( FILE* inFile )
{
	DWORD						number;
	WORD						flag;
	FLOAT						a;
	DWORD						frame;
	
	ReadDword( inFile );
	ReadWord( inFile );
	ReadDword( inFile );
	ReadDword( inFile );

	number = ReadDword( inFile );
	dwKeyNumber = number;
	keys = new gem_FloatKey[number];

	for( DWORD i = 0 ; ( !feof( inFile ) ) && i<number ; i++ )
	{
		
		frame = ReadDword( inFile );
		keys[i].frame = frame;

		keys[i].T = 0.0f;
		keys[i].B = 0.0f;
		keys[i].C = 0.0f;
		keys[i].EaseFrom = 0.0f;
		keys[i].EaseTo = 0.0f;

		flag = ReadWord( inFile );
		for( DWORD j = 0 ; j<16 ; j++ )
			if( flag&(1<<j) )
				switch( j )
				{
					case 0: 
						keys[i].T = ReadFloat( inFile ); 
					break;

					case 1: 
						keys[i].C = ReadFloat( inFile ); 
					break;

					case 2: 
						keys[i].B = ReadFloat( inFile ); 
					break;

					case 3: 
						keys[i].EaseTo = ReadFloat( inFile ); 
					break;

					case 4: 
						keys[i].EaseFrom = ReadFloat( inFile ); 
					break;
				}


		a = ReadFloat( inFile );
		keys[i].val=a;
	}

	if( feof( inFile ) )
		return GEMERROR_LOAD;

	return GEMERROR_OK;
}

gem_HideTrack::gem_HideTrack()
{
}

gem_HideTrack::~gem_HideTrack()
{
	delete keys;
}

VOID gem_HideTrack::Init()
{
}

BOOL gem_HideTrack::Interpolation( FLOAT frame )
{
	DWORD				i;
	
	if( (FLOAT)frame<keys[0].frame )
	{		
		return FALSE;
	}

	for( i=0; i<dwKeyNumber-1; i++ )
	{
		if( (FLOAT)keys[i].frame<=frame && (FLOAT)frame<keys[i+1].frame )
			break;
	}

	if( i==dwKeyNumber-1 )
	{
		return keys[dwKeyNumber-1].hide;		
	}

	return keys[i].hide;	
}

DWORD gem_HideTrack::Load( FILE* inFile )
{
	DWORD				number;
	WORD				flag;	
	DWORD				frame;	
	WORD	     		hide=0;	

	ReadDword( inFile );
	ReadWord( inFile );
	ReadDword( inFile );
	ReadDword( inFile );

	number = ReadDword( inFile );
	dwKeyNumber = number;
	keys = new gem_HideKey[number];

	for( DWORD i = 0 ; ( !feof( inFile ) ) && i<number ; i++ )
	{
		
		flag = ReadWord( inFile );
		for( DWORD j = 0 ; j<16 ; j++ )
			if( flag&(1<<j) )
				switch( j )
				{
					case 0: 
						ReadFloat( inFile ); 
					break;

					case 1: 
						ReadFloat( inFile ); 
					break;

					case 2: 
						ReadFloat( inFile ); 
					break;

					case 3: 
						ReadFloat( inFile ); 
					break;

					case 4: 
						ReadFloat( inFile ); 
					break;
				}
		
     
		keys[i].hide=(hide^=1);		
	}

	if( feof( inFile ) )
		return GEMERROR_LOAD;

	return GEMERROR_OK;
}


gem_MorphTrack::gem_MorphTrack( gem_Scene* scene )
{
	pScene = scene;
}

gem_MorphTrack::~gem_MorphTrack()
{
	delete keys;
}

VOID gem_MorphTrack::Init()
{
}

gem_MorphInfo gem_MorphTrack::Interpolation( FLOAT frame )
{
	DWORD				i;
	gem_MorphInfo		info;
	FLOAT				t;
	

	if( dwKeyNumber<2 )
	{
		info.MorphSource = keys[0].mesh;
		info.MorphTarget = keys[0].mesh;
		info.MorphFactor = 0;
		return info;
	}


	for( i = 0 ; i<dwKeyNumber ; i++ )
	{
		if( (FLOAT)keys[i].frame<=frame && (FLOAT)frame<keys[i+1].frame )
			break;
	}

	if( i==dwKeyNumber-1 )
	{
		info.MorphSource = keys[dwKeyNumber-1].mesh;
		info.MorphTarget = keys[dwKeyNumber-1].mesh;
		info.MorphFactor = 0;
		return info;
	}

	t = ( frame - (FLOAT)keys[i].frame)/((FLOAT)keys[i+1].frame - (FLOAT)keys[i].frame);
	t = RemapEase( t, keys[i].EaseFrom, keys[i].EaseTo );

	info.MorphSource = keys[i].mesh;
	info.MorphTarget = keys[i+1].mesh;
	info.MorphFactor = t;

	return info;
}

DWORD gem_MorphTrack::Load( FILE* inFile )
{	
	DWORD						number;
	WORD						flag;	
	DWORD						frame;	
	TCHAR						objname[80];
	gem_Object*					object;

	ReadDword( inFile );
	ReadWord( inFile );
	ReadDword( inFile );
	ReadDword( inFile );

	number = ReadDword( inFile );
	dwKeyNumber = number;
	keys = new gem_MorphKey[number];

	for( DWORD i = 0 ; ( !feof( inFile ) ) && i<number ; i++ )
	{
		
		frame = ReadDword( inFile );
		keys[i].frame = frame;
		
		keys[i].EaseFrom = 0.0f;
		keys[i].EaseTo = 0.0f;

		flag = ReadWord( inFile );
		for( DWORD j = 0 ; j<16 ; j++ )
			if( flag&(1<<j) )
				switch( j )
				{
					case 0: 
						ReadFloat( inFile ); 
					break;

					case 1: 
						ReadFloat( inFile ); 
					break;

					case 2: 
						ReadFloat( inFile ); 
					break;

					case 3: 
						keys[i].EaseTo = ReadFloat( inFile ); 
					break;

					case 4: 
						keys[i].EaseFrom = ReadFloat( inFile ); 
					break;
				}

	
		ReadASCIIZ( inFile, objname );
		if( !( object = pScene->FindObject( objname ) ) )
			return GEMERROR_LOAD;
		
		keys[i].mesh=(gem_Mesh*)object;		
	}

	if( feof( inFile ) )
		return GEMERROR_LOAD;

	return GEMERROR_OK;
}
