//--FILE-DESC-----------------------------------------------------------------
//	file: keyframer.cpp
//	desc: implementation of keyframers methods (gem_MeshKeyframer, 
//		  gem_LightKeyframer, gem_CameraKeyframer, gem_CameraTrgKeyframer),
//		  more details in documentation
//----------------------------------------------------------------------------
#include "directgem.h"
#include "gemmath.h"
#include "enum.h"
#include "loader.h"


gem_MeshKeyframer::gem_MeshKeyframer( gem_Scene* scene ) : gem_Keyframer( scene )
{
	hide = FALSE;
	isMorphing = FALSE;
	dummy = FALSE;

	hideTrack = NULL;
	morphTrack = NULL;

	morphTrack = NULL;
	hideTrack = NULL;
	rotationTrack = NULL;
	positionTrack = NULL;
	scaleTrack = NULL;
}

gem_MeshKeyframer::~gem_MeshKeyframer()
{
	delete rotationTrack;
	delete scaleTrack;
	delete positionTrack;

	if( hideTrack )
		delete hideTrack;

	if( morphTrack )
		delete morphTrack;
}

//--METHOD-DESC---------------------------------------------------------------
//	name	: UpdateTransform()
//	class	: gem_MeshKeyframer
//	param	: frame number of framer for which transformation shuold  be done
//	return	: void
//	desc:	: calculate a transformation for frame passed as a param, preforms
//			  appropiate interpolation and calculation frame matrix, make
//			  hierarhy transformation
//----------------------------------------------------------------------------	
VOID gem_MeshKeyframer::UpdateTransform( FLOAT frame )
{
	frameMtx =	ScaleMtx( scaleTrack->Interpolation( frame ) ) *
				MtxFromQuat( rotationTrack->Interpolation( frame ) ) *		        
				TranslationMtx( positionTrack->Interpolation( frame ) );

	isMorphing = FALSE;

	if( morphTrack )
	{
		if( !dummy )
		{
			mesh->Morph( morphTrack->Interpolation( frame ) );
			isMorphing = TRUE;
		}
	}

	if( hideTrack )
	{
		if( !dummy )
		{
			hide = hideTrack->Interpolation( frame );
			mesh->bHide = hide;
		}
	}

	if( parent )
	{
		frameMtx = frameMtx*parent->frameMtx;
	}
}

//--METHOD-DESC---------------------------------------------------------------
//	name	: ApplyTransform()
//	class	: gem_MeshKeyframer
//	param	: none
//	return	: void
//	desc:	: apply a frame matrix to object and morph it if necesary
//----------------------------------------------------------------------------	
VOID gem_MeshKeyframer::ApplyTransform()
{
	DWORD					i;
	
	if( !hide && !dummy )
	{	
		mesh->mtxTransform = frameMtx;

		LPD3DVERTEX			src, dest;

		if( pScene->dwFlags&GEMFLAGS_SOFTWAREGEOMETRY )	
		{
			if( isMorphing )
			{
				src		= mesh->pTransformVertexTab;
				dest	= mesh->pTransformVertexTab;
			}
			else
			{
				src		= mesh->pMeshVertexTab;
				dest	= mesh->pTransformVertexTab;
			}

			for( i = 0 ; i < mesh->dwVertexCount ; i++, src++, dest++ )
			{
				MtxMulVertex( frameMtx, src, dest );
			}
			
		}
		else
		{
			if( !isMorphing )
				memcpy( mesh->pTransformVertexTab, mesh->pMeshVertexTab, mesh->dwVertexCount*sizeof(D3DVERTEX) );
		}

		

		/*if( pScene->dwFlags&GEMFLAGS_SOFTWAREGEOMETRY )		
		{
			if( isMorphing )
			{			
				for( i = 0 ; i<mesh->dwVertexCount ; i++ )
					mesh->pTransformVertexTab[i] = mesh->pTransformVertexTab[i]*frameMtx;
			}
			else
			{					
				for( i = 0 ; i <mesh->dwVertexCount ; i++ )
				{									 
					MulVertex( mesh->pMeshVertexTab[i], frameMtx, mesh->pTransformVertexTab[i] );
				}
			}
		}
		else
		{
			if( !isMorphing )
			{			
				memcpy( mesh->pTransformVertexTab, mesh->pMeshVertexTab, mesh->dwVertexCount*sizeof(D3DVERTEX) );
			}
		}*/
	}		
}

//--METHOD-DESC---------------------------------------------------------------
//	name	: ReadPivot()
//	class	: gem_MeshKeyframer
//	param	: inFile a open stream for .3ds file
//	return	: DWORD error code
//	desc:	: loader function - read pivot point 
//----------------------------------------------------------------------------	
DWORD gem_MeshKeyframer::ReadPivot( FILE *inFile )
{
	FLOAT					a, b, c;

	ReadDword( inFile );

	a = ReadFloat( inFile );
	b = ReadFloat( inFile );
	c = ReadFloat( inFile );

	pivot = gem_Vector( a, c, b );

	if( feof( inFile ) )
		return GEMERROR_LOAD;

	return GEMERROR_OK;
}

DWORD gem_MeshKeyframer::ReadDummyName( FILE* inFile, TCHAR* name )
{		
	ReadDword( inFile );
	ReadASCIIZ( inFile, name );

	dummy = TRUE;

	return GEMERROR_OK;
}


DWORD gem_MeshKeyframer::Load( FILE* inFile )
{	
	LONG					size;
	LONG					pos;
	WORD					sign;
	TCHAR					name[80];
	

	size = ReadDword( inFile ) - IDLENGTH;
	pos = ftell( inFile );

	while( ( !feof( inFile ) ) && ftell( inFile )<size+pos )
	{
		sign = ReadWord( inFile );

		switch (sign)
		{
			case GEMCHUNK_OBJECTINFO:
				if( ReadObjectInfo( inFile, name, parentID )!=GEMERROR_OK )
					return GEMERROR_LOAD;
			break;

			case GEMCHUNK_DUMMYNAME:
				if( ReadDummyName( inFile, name )!=GEMERROR_OK )
					return GEMERROR_LOAD;
			break;

			case GEMCHUNK_ROTATIONTRACK:
				rotationTrack = new gem_RotationTrack;
				if( rotationTrack->Load( inFile )!=GEMERROR_OK )
					return GEMERROR_LOAD;
				rotationTrack->Init();
			break;

			case GEMCHUNK_POSITIONTRACK:
				positionTrack = new gem_VectorTrack;
				if( positionTrack->Load( inFile )!=GEMERROR_OK )
					return GEMERROR_LOAD;
				positionTrack->Init();
			break;

			case GEMCHUNK_SCALETRACK:
				scaleTrack = new gem_VectorTrack;
				if( scaleTrack->Load( inFile )!=GEMERROR_OK )
					return GEMERROR_LOAD;
				scaleTrack->Init();
			break;

			case GEMCHUNK_MORPHTRACK:
				morphTrack = new gem_MorphTrack( pScene );
				if( morphTrack->Load( inFile )!=GEMERROR_OK )
					return GEMERROR_LOAD;
				morphTrack->Init();
			break;

			case GEMCHUNK_HIDETRACK:
				hideTrack = new gem_HideTrack;
				if( hideTrack->Load( inFile )!=GEMERROR_OK )
					return GEMERROR_LOAD;
				hideTrack->Init();
			break;

			case GEMCHUNK_HIERARCHY:
				if( ReadHierarchy( inFile, hierarchyID )!=GEMERROR_OK )
					return GEMERROR_LOAD;
			break;

			case GEMCHUNK_PIVOT:
				if( ReadPivot( inFile )!=GEMERROR_OK )
					return GEMERROR_LOAD;
			break;

			default:
				if( JumpThroughtChunk( inFile )!=GEMERROR_OK )
					return GEMERROR_LOAD;
			break;
		}
	}	

	if( feof( inFile ) )
		return GEMERROR_LOAD;

	if( !dummy )
	{
		mesh = (gem_Mesh*)pScene->FindObject( name );
		mesh->PreTransform( TranslationMtx( -pivot ) );
	}
	else
		mesh = NULL;

	pScene->KeyframerList.AddItem( this, name );

	return GEMERROR_OK;
}

gem_LightKeyframer::gem_LightKeyframer( gem_Scene* scene ) : gem_Keyframer( scene )
{
	positionTrack = NULL;
}

gem_LightKeyframer::~gem_LightKeyframer()
{
	delete positionTrack;
}

VOID gem_LightKeyframer::UpdateTransform( FLOAT frame )
{
	gem_Vector					pos;

	pos = positionTrack->Interpolation( frame );

	if( parent )
	{
		pos = pos*parent->frameMtx;
	}

	light->position = pos;
}

VOID gem_LightKeyframer::ApplyTransform()
{
	LPDIRECT3DDEVICE7			lpd3dDevice = pScene->lpd3dDevice;
	D3DLIGHT7					d3dlight;
	
	//lpd3dDevice->GetLight( light->dwIndex, &d3dlight );
	//d3dlight.dvPosition.x = light->position.x;
	//d3dlight.dvPosition.y = light->position.y;
	//d3dlight.dvPosition.z = light->position.z;
	//lpd3dDevice->SetLight( light->dwIndex, &d3dlight );
}

DWORD gem_LightKeyframer::Load( FILE* inFile )
{
	LONG						size;
	LONG						pos;
	WORD						sign;
	TCHAR						name[80];

	
	size = ReadDword( inFile ) - IDLENGTH;
	pos = ftell( inFile );	

	while( ( !feof( inFile ) ) && ftell( inFile )<size+pos )
	{
		sign = ReadWord( inFile );

		switch( sign )
		{
			case GEMCHUNK_OBJECTINFO:
				if( ReadObjectInfo( inFile, name, parentID )!=GEMERROR_OK )
					return GEMERROR_LOAD;
			break;			

			case GEMCHUNK_POSITIONTRACK:
				positionTrack = new gem_VectorTrack;
				if( positionTrack->Load( inFile )!=GEMERROR_OK )
					return GEMERROR_LOAD;
				positionTrack->Init();
			break;

			case GEMCHUNK_HIERARCHY:
				if( ReadHierarchy( inFile, hierarchyID )!=GEMERROR_OK )
					return GEMERROR_LOAD;
			break;

			default:
				if( JumpThroughtChunk( inFile )!=GEMERROR_OK )
					return GEMERROR_LOAD;
			break;
						
		}
	}

	if( feof( inFile ) )
		return GEMERROR_LOAD;

	light = (gem_Light*)pScene->FindObject( name );	
	pScene->KeyframerList.AddItem( this, name );

	return GEMERROR_OK;
}


gem_CameraKeyframer::gem_CameraKeyframer( gem_Scene* scene ) : gem_Keyframer( scene )
{
	fovTrack = NULL;
	rollTrack = NULL;
	positionTrack = NULL;
}

gem_CameraKeyframer::~gem_CameraKeyframer()
{
	delete fovTrack;
	delete rollTrack;
	delete positionTrack;
}

VOID gem_CameraKeyframer::UpdateTransform( FLOAT frame )
{
	gem_Vector					pos;

	camera->fov = fovTrack->Interpolation( frame );
	camera->roll = rollTrack->Interpolation( frame );

	pos = positionTrack->Interpolation( frame );

	if( parent )
	{
		pos = pos*parent->frameMtx;
	}

	camera->position = pos;
}

VOID gem_CameraKeyframer::ApplyTransform()
{
}

DWORD gem_CameraKeyframer::Load( FILE* inFile )
{
	LONG						size;
	LONG						pos;
	WORD						sign;
	TCHAR						name[80];
	

	size = ReadDword( inFile ) - IDLENGTH;
	pos = ftell( inFile );
	
	while( ( !feof( inFile ) ) && ftell( inFile )<size+pos )
	{
		sign = ReadWord( inFile);
		switch( sign )
		{

			case GEMCHUNK_OBJECTINFO:
				if( ReadObjectInfo( inFile, name, parentID )!=GEMERROR_OK )
					return GEMERROR_LOAD;
			break;			

			case GEMCHUNK_POSITIONTRACK:
				positionTrack = new gem_VectorTrack;
				if( positionTrack->Load( inFile )!=GEMERROR_OK )
					return GEMERROR_LOAD;
				positionTrack->Init();
			break;
			
			case GEMCHUNK_ROLLTRACK:
				rollTrack = new gem_FloatTrack;
				if( rollTrack->Load( inFile )!=GEMERROR_OK )
					return GEMERROR_LOAD;
				rollTrack->Init();
			break;

			case GEMCHUNK_FOVTRACK:
				fovTrack = new gem_FloatTrack;
				if( fovTrack->Load( inFile )!=GEMERROR_OK )
					return GEMERROR_LOAD;
				fovTrack->Init();
			break;

			case GEMCHUNK_HIERARCHY:
				if( ReadHierarchy( inFile, hierarchyID )!=GEMERROR_OK )
					return GEMERROR_LOAD;
			break;

			default:
				if( JumpThroughtChunk( inFile )!=GEMERROR_OK )
					return GEMERROR_LOAD;
			break;			
		}
	}

	if( feof( inFile ) )
		return GEMERROR_LOAD;

	camera = (gem_Camera*)pScene->FindObject( name );	
	pScene->KeyframerList.AddItem( this, name );

	return GEMERROR_OK;
}



gem_CameraTrgKeyframer::gem_CameraTrgKeyframer( gem_Scene* scene ) : gem_Keyframer( scene )
{
}


gem_CameraTrgKeyframer::~gem_CameraTrgKeyframer()
{	
	delete positionTrack;
}

VOID gem_CameraTrgKeyframer::UpdateTransform( FLOAT frame )
{
	gem_Vector					pos;

	pos = positionTrack->Interpolation( frame );

	if( parent )
	{
		pos = pos*parent->frameMtx;
	}

	camera->target = pos;
}

VOID gem_CameraTrgKeyframer::ApplyTransform()
{
}

DWORD gem_CameraTrgKeyframer::Load( FILE* inFile )
{
	LONG						 size;
	LONG						 pos;
	WORD						 sign;	
	TCHAR						name[80];


	size = ReadDword( inFile ) - IDLENGTH;
	pos = ftell( inFile );	

	while( ( !feof( inFile ) ) && ftell( inFile )<size+pos )
	{
		sign = ReadWord( inFile );

		switch( sign )
		{
			case GEMCHUNK_OBJECTINFO:
				if( ReadObjectInfo( inFile, name, parentID )!=GEMERROR_OK )
					return GEMERROR_LOAD;
			break;			

			case GEMCHUNK_POSITIONTRACK:
				positionTrack = new gem_VectorTrack;
				if( positionTrack->Load( inFile )!=GEMERROR_OK )
					return GEMERROR_LOAD;
				positionTrack->Init();
			break;

			case GEMCHUNK_HIERARCHY:
				if( ReadHierarchy( inFile, hierarchyID )!=GEMERROR_OK )
					return GEMERROR_LOAD;
			break;

			default:
				if( JumpThroughtChunk( inFile )!=GEMERROR_OK )
					return GEMERROR_LOAD;
			break;
						
		}
	}	

	if( feof( inFile ) )
		return GEMERROR_LOAD;

	camera = (gem_Camera*)pScene->FindObject( name );	
	pScene->KeyframerList.AddItem( this, name );

	return GEMERROR_OK;
}








	
				




