// UtilityFunction.cpp: implementation of the UtilityFunction class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "UtilityFunction.h"

DWORD FLT2DWORD( FLOAT f )
{
	return *( (DWORD*)&f );
}

BOOL CreateRing( PDIRECT3DDEVICE8 pDevice, FLOAT fr, FLOAT fR, DWORD dwSegCount, PDIRECT3DVERTEXBUFFER8* ppvb )
{
	DWORD		dwVertexCount = 2*(dwSegCount + 1);

	if( FAILED( pDevice->CreateVertexBuffer( dwVertexCount*sizeof(LVERTEX), 0, FVF_LVERTEX, D3DPOOL_DEFAULT, ppvb ) ) )
		return FALSE;

	PLVERTEX	pVertices;
	FLOAT		fAngle = 0.0f;
	FLOAT		fDelta = H_2PI/(FLOAT)dwSegCount;
	DWORD		index = 0;

	(*ppvb)->Lock( 0, 0, (LPBYTE*)&pVertices, 0 );

	pVertices[index++] = LVERTEX( fr*cosf(fAngle), fr*sinf(fAngle), 0, 0xffffff, 0.0f, 1.0f );
	pVertices[index++] = LVERTEX( fR*cosf(fAngle), fR*sinf(fAngle), 0, 0xffffff, 0.0f, 0.0f );

	fAngle += fDelta;
	pVertices[index++] = LVERTEX( fr*cosf(fAngle), fr*sinf(fAngle), 0, 0xffffff, fAngle/H_2PI, 1.0f );

	for( DWORD i = 1 ; i < dwSegCount ; i++ )
	{
		pVertices[index++] = LVERTEX( fR*cosf(fAngle), fR*sinf(fAngle), 0, 0xffffff, fAngle/H_2PI, 0.0f );
		fAngle += fDelta;
		pVertices[index++] = LVERTEX( fr*cosf(fAngle), fr*sinf(fAngle), 0, 0xffffff, fAngle/H_2PI, 1.0f );
	}

	pVertices[index++] = LVERTEX( fR*cosf(fAngle), fR*sinf(fAngle), 0, 0xffffff, fAngle/H_2PI, 0.0f );	

	(*ppvb)->Unlock();
		
	return TRUE;
}

BOOL CreateBox( PDIRECT3DDEVICE8 pDevice, FLOAT fA, PDIRECT3DVERTEXBUFFER8* ppvb )
{
	if( FAILED( pDevice->CreateVertexBuffer( 36*sizeof(LVERTEX), 0, FVF_LVERTEX, D3DPOOL_DEFAULT, ppvb ) ) )
		return FALSE;

	PLVERTEX				pVertices;
	FLOAT					fSize = 0.5f*fA;

	(*ppvb)->Lock( 0, 0, (LPBYTE*)&pVertices, 0 );

	pVertices[ 0] = LVERTEX( -fSize, -fSize, -fSize, 0xffffff, 0.0f, 1.0f );
	pVertices[ 1] = LVERTEX( -fSize,  fSize, -fSize, 0xffffff, 0.0f, 0.0f );
	pVertices[ 2] = LVERTEX(  fSize, -fSize, -fSize, 0xffffff, 1.0f, 1.0f );
	pVertices[ 3] = LVERTEX(  fSize, -fSize, -fSize, 0xffffff, 1.0f, 1.0f );
	pVertices[ 4] = LVERTEX( -fSize,  fSize, -fSize, 0xffffff, 0.0f, 0.0f );
	pVertices[ 5] = LVERTEX(  fSize,  fSize, -fSize, 0xffffff, 1.0f, 0.0f );

	pVertices[ 6] = LVERTEX( -fSize, -fSize,  fSize, 0xffffff, 1.0f, 1.0f );
	pVertices[ 7] = LVERTEX( -fSize,  fSize,  fSize, 0xffffff, 1.0f, 0.0f );
	pVertices[ 8] = LVERTEX(  fSize, -fSize,  fSize, 0xffffff, 0.0f, 1.0f );
	pVertices[ 9] = LVERTEX(  fSize, -fSize,  fSize, 0xffffff, 0.0f, 1.0f );
	pVertices[10] = LVERTEX( -fSize,  fSize,  fSize, 0xffffff, 1.0f, 0.0f );
	pVertices[11] = LVERTEX(  fSize,  fSize,  fSize, 0xffffff, 0.0f, 0.0f );

	pVertices[12] = LVERTEX(  fSize, -fSize, -fSize, 0xffffff, 1.0f, 1.0f );
	pVertices[13] = LVERTEX(  fSize,  fSize, -fSize, 0xffffff, 1.0f, 0.0f );
	pVertices[14] = LVERTEX(  fSize, -fSize,  fSize, 0xffffff, 0.0f, 1.0f );
	pVertices[15] = LVERTEX(  fSize, -fSize,  fSize, 0xffffff, 0.0f, 1.0f );
	pVertices[16] = LVERTEX(  fSize,  fSize, -fSize, 0xffffff, 1.0f, 0.0f );
	pVertices[17] = LVERTEX(  fSize,  fSize,  fSize, 0xffffff, 0.0f, 0.0f );

	pVertices[18] = LVERTEX( -fSize, -fSize, -fSize, 0xffffff, 0.0f, 1.0f );
	pVertices[19] = LVERTEX( -fSize,  fSize, -fSize, 0xffffff, 0.0f, 0.0f );
	pVertices[20] = LVERTEX( -fSize, -fSize,  fSize, 0xffffff, 1.0f, 1.0f );
	pVertices[21] = LVERTEX( -fSize, -fSize,  fSize, 0xffffff, 1.0f, 1.0f );
	pVertices[22] = LVERTEX( -fSize,  fSize, -fSize, 0xffffff, 0.0f, 0.0f );
	pVertices[23] = LVERTEX( -fSize,  fSize,  fSize, 0xffffff, 1.0f, 0.0f );

	pVertices[24] = LVERTEX( -fSize,  fSize, -fSize, 0xffffff, 0.0f, 1.0f );
	pVertices[25] = LVERTEX( -fSize,  fSize,  fSize, 0xffffff, 0.0f, 0.0f );
	pVertices[26] = LVERTEX(  fSize,  fSize, -fSize, 0xffffff, 1.0f, 1.0f );
	pVertices[27] = LVERTEX(  fSize,  fSize, -fSize, 0xffffff, 1.0f, 1.0f );
	pVertices[28] = LVERTEX( -fSize,  fSize,  fSize, 0xffffff, 0.0f, 0.0f );
	pVertices[29] = LVERTEX(  fSize,  fSize,  fSize, 0xffffff, 1.0f, 0.0f );

	pVertices[30] = LVERTEX( -fSize, -fSize, -fSize, 0xffffff, 0.0f, 1.0f );
	pVertices[31] = LVERTEX( -fSize, -fSize,  fSize, 0xffffff, 0.0f, 0.0f );
	pVertices[32] = LVERTEX(  fSize, -fSize, -fSize, 0xffffff, 1.0f, 1.0f );
	pVertices[33] = LVERTEX(  fSize, -fSize, -fSize, 0xffffff, 1.0f, 1.0f );
	pVertices[34] = LVERTEX( -fSize, -fSize,  fSize, 0xffffff, 0.0f, 0.0f );
	pVertices[35] = LVERTEX(  fSize, -fSize,  fSize, 0xffffff, 1.0f, 0.0f );

	(*ppvb)->Unlock();

	return TRUE;
}

_FLOATKEY::_FLOATKEY() : t( 0.0f ), val( 0.0f )
{
}

_FLOATKEY::_FLOATKEY( FLOAT time, FLOAT value ) : t( time ), val( value )
{
}

_VECTORKEY::_VECTORKEY() : t( 0.0f ), val( 0.0f, 0.0f, 0.0f )
{
}

_VECTORKEY::_VECTORKEY( FLOAT time, he3d_CVector& v ) : t( time ), val( v )
{
}

_VECTORKEY::_VECTORKEY( FLOAT time, FLOAT x, FLOAT y, FLOAT z ) : t( time ), val( x, y, z )
{
}

VOID InitFloatSpline( DWORD dwKeysCount, PFLOATKEY pfkKeys )
{
	if( dwKeysCount <= 1 )
		return;

	FLOAT				delta1, delta2;	
	FLOAT				f1, f2;	

	for( DWORD i = 0 ; i < dwKeysCount ; i++ )
	{		
		delta1 = 0.5f;
		delta2 = 0.5f;

		if( i != dwKeysCount - 1 )		
			f1 = pfkKeys[i+1].val - pfkKeys[i].val;		

		if( i != 0 )		
			f2 = pfkKeys[i].val - pfkKeys[i-1].val;
		
		if( i == dwKeysCount - 1 )
			f1 = f2;

		if( i == 0 )
			f2 = f1;

		if( i != 0 && i != dwKeysCount - 1 )
		{
			delta1 = ( pfkKeys[i+1].t - pfkKeys[i].t )/( pfkKeys[i+1].t - pfkKeys[i-1].t );
			delta2 = ( pfkKeys[i].t - pfkKeys[i-1].t )/( pfkKeys[i+1].t - pfkKeys[i-1].t );
		}
		
		pfkKeys[i].t0 = delta1*( f1 + f2 );		
		pfkKeys[i].t1 = delta2*( f1 + f2 );
	}
}

FLOAT GetFloatSplineValue( FLOAT fT, DWORD dwKeysCount, PFLOATKEY pfkKeys )
{	
	if( dwKeysCount <= 1 )
		return pfkKeys[0].val;

	if( pfkKeys[0].t >= fT )
		return pfkKeys[0].val;

	if( pfkKeys[dwKeysCount-1].t <= fT )
		return pfkKeys[dwKeysCount-1].val;

	for( DWORD i = 0 ; i < dwKeysCount - 1  && pfkKeys[i+1].t < fT ; i++ );

	FLOAT					t, t2, t3;
	FLOAT					h[4];

	t = (fT - pfkKeys[i].t)/(pfkKeys[i+1].t - pfkKeys[i].t);	

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

	h[0] = 2*t3 - 3*t2 + 1;
	h[1] = -2*t3 + 3*t2;
	h[2] = t3 - 2*t2 + t;
	h[3] = t3 - t2;

	return h[0]*pfkKeys[i].val + h[1]*pfkKeys[i+1].val + h[2]*pfkKeys[i].t0 + h[3]*pfkKeys[i+1].t1;
}

VOID InitVectorSpline( DWORD dwKeysCount, PVECTORKEY pvkKeys )
{
	if( dwKeysCount <= 1 )
		return;

	FLOAT				delta1, delta2;	
	he3d_CVector		v1, v2;	

	for( DWORD i = 0 ; i < dwKeysCount ; i++ )
	{		
		delta1 = 0.5f;
		delta2 = 0.5f;

		if( i != dwKeysCount - 1 )		
			v1 = pvkKeys[i+1].val - pvkKeys[i].val;		

		if( i != 0 )		
			v2 = pvkKeys[i].val - pvkKeys[i-1].val;
		
		if( i == dwKeysCount - 1 )
			v1 = v2;

		if( i == 0 )
			v2 = v1;

		if( i != 0 && i != dwKeysCount - 1 )
		{
			delta1 = ( pvkKeys[i+1].t - pvkKeys[i].t )/( pvkKeys[i+1].t - pvkKeys[i-1].t );
			delta2 = ( pvkKeys[i].t - pvkKeys[i-1].t )/( pvkKeys[i+1].t - pvkKeys[i-1].t );
		}
		
		pvkKeys[i].t0 = delta1*( v1 + v2 );		
		pvkKeys[i].t1 = delta2*( v1 + v2 );
	}
}

he3d_CVector GetVectorSplineValue( FLOAT fT, DWORD dwKeysCount, PVECTORKEY pvkKeys )
{
	if( dwKeysCount <= 1 )
		return pvkKeys[0].val;

	if( pvkKeys[0].t >= fT )
		return pvkKeys[0].val;

	if( pvkKeys[dwKeysCount-1].t <= fT )
		return pvkKeys[dwKeysCount-1].val;

	for( DWORD i = 0 ; i < dwKeysCount - 1  && pvkKeys[i+1].t < fT ; i++ );

	FLOAT					t, t2, t3;
	FLOAT					h[4];

	t = (fT - pvkKeys[i].t)/(pvkKeys[i+1].t - pvkKeys[i].t);	

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

	h[0] = 2*t3 - 3*t2 + 1;
	h[1] = -2*t3 + 3*t2;
	h[2] = t3 - 2*t2 + t;
	h[3] = t3 - t2;

	return h[0]*pvkKeys[i].val + h[1]*pvkKeys[i+1].val + h[2]*pvkKeys[i].t0 + h[3]*pvkKeys[i+1].t1;
}

he3d_CVector Polar2Cartesian3d( FLOAT fRadius, FLOAT fAlpha, FLOAT fBeta )
{
	return he3d_CVector( fRadius*cosf(fAlpha)*sinf(fBeta), fRadius*cosf(fBeta), fRadius*sinf(fAlpha)*sinf(fBeta) );
}