// BigBang.cpp: implementation of the CBigBang class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "BigBang.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CBigBang::CBigBang( PDIRECT3DDEVICE8 pDevice ) : CEfx( pDevice ), m_bsSystem( 25 )
{
	m_piqFade = NULL;
	m_pvbShockWavePod = NULL;
	m_pvbPrticle = NULL;	

	if( !m_psSystem.Initialize( m_pDevice ) )
		throw CSystemException( DEMO_EXCEPTION_D3DERROR, "unalbe to initialize particle system" );

	if( !m_bsSystem.Initialize( m_pDevice ) )
		throw CSystemException( DEMO_EXCEPTION_D3DERROR, "unalbe to initialize blob system" );	

	if( FAILED( m_pDevice->CreateVertexBuffer( 300*sizeof(PARTICLEVERTEX), 0, FVF_PARTICLEVERTEX, D3DPOOL_DEFAULT, &m_pvbPrticle ) ) )
		throw CSystemException( DEMO_EXCEPTION_D3DERROR, "unalbe to create particle buffer" );

	if( !CreateRing( m_pDevice, 1.0f, 5.0f, 50, &m_pvbShockWavePod ) )
		throw CSystemException( DEMO_EXCEPTION_D3DERROR, "unalbe to create shockwave pod buffer" );

	m_piqFade = new CImageQuad( m_pDevice );
	m_piqFade->SetColor( 0x0 );
	m_piqFade->Resize( 0, 0, 512, 512 );
	m_piqFlare = new CImageQuad( m_pDevice );
	m_piqFlare->SetColor( 0xffffff );
	m_piqFlare->SetAlpha( 0x0 );

	try
	{	
		LoadTexture( "explodeflare.jpg" );
		LoadTexture( "flare0.bmp" );
		LoadTexture( "shockwave.jpg" );
		LoadTexture( "envmap4.jpg" );
	}
	catch( CTextureException )
	{
		throw CSystemException( DEMO_EXCEPTION_FILENOTFOUND, "unable to load textures" );
	}

	m_psSystem.SetTexture( GetTexture( "flare0.bmp" ) );
	m_psSystem.SetBlurCoeff( 0.2f );	
	m_psSystem.ConfigureGravity( G_POINT, he3d_CVector( 0, 0.0f, 0.0f ), 0.0f );	

	m_seEmiter.SetCenter( he3d_CVector( 0.0f, 0.0f, 0.0f ) );
	m_seEmiter.SetRadius( 100.0f );
	m_seEmiter.SetEmitCount( 150, 0 );
	m_seEmiter.SetLifeTime( 20.0f, 0.0f );
	m_seEmiter.SetVelocity( 30.0f, 10.0f );
	m_seEmiter.SetSize( 0.8f, 0.0f );
	m_seEmiter.SetParticleType( PT_BLURED );
	m_seEmiter.SetEmitInterval( 0.5f );

	m_fpeEmiter.SetEmitAngle( H_2PI );
	m_fpeEmiter.SetEmiterDir( he3d_CVector( 0.0f, 1.0f, 0.0f ) );
	m_fpeEmiter.SetEmitCount( 1000, 0 );
	m_fpeEmiter.SetDimension( 1000 );
	m_fpeEmiter.EnableAutoDelete( FALSE );
	m_fpeEmiter.SetLifeTime( 20.0f, 0.0f );
	m_fpeEmiter.SetSize( 0.8f, 0.0f );
	m_fpeEmiter.SetVelocity( 20.0f, 5.0f );
	m_fpeEmiter.SetEmiterPos( he3d_CVector( 0.0f, 0.0f, 10.0f ) );
	m_fpeEmiter.SetEmitInterval( 11.8f );

	m_psSystem.AddEmiter( &m_fpeEmiter );		
	m_psSystem.AddEmiter( &m_seEmiter );

	for( DWORD i = 0 ; i < 7 ; i++ )
	{			
		m_b3dBlob[i].m_dwSign = FALSE;
		m_b3dBlob[i].m_fRadius = 1.5f;
		m_b3dBlob[i].m_fDensity = 1.5f;

		m_vBlobsPos[i] = he3d_CVector( 1.0f, 0.0f, 0.0f );

		m_bsSystem.AddBlob( &m_b3dBlob[i] );
	}

	m_b3dBlob[0].m_dwColor = 0x0000ff;
	m_b3dBlob[1].m_dwColor = 0x00ff00;
	m_b3dBlob[2].m_dwColor = 0xff0000;
	m_b3dBlob[3].m_dwColor = 0xff00ff;
	m_b3dBlob[4].m_dwColor = 0xffff00;
	m_b3dBlob[5].m_dwColor = 0x00ffff;
	m_b3dBlob[6].m_dwColor = 0xffffff;

	m_b3dBlob[6].m_dwSign = FALSE;
	m_b3dBlob[6].m_fRadius = 1.0f;
	m_b3dBlob[6].m_fDensity = 3.0f;

	m_vBlobsPos[i] = he3d_CVector( 0.0f, 0.0f, 0.0f );

	for( i = 0 ; i < 7 ; i++ )
	{	
		m_fRotCoeff[i][0] = 2.0f*SIGNEDRAND();
		m_fRotCoeff[i][1] = 2.0f*SIGNEDRAND();
		m_fRotCoeff[i][2] = 2.0f*SIGNEDRAND();		
	}

	for( i = 0 ; i < 30 ; i++ )
	{
		FLOAT				a = H_2PI*RAND();
		FLOAT				b = H_2PI*RAND();

		m_vParticle[i] = he3d_CVector( 1.5f*cosf(a)*sinf(b), 1.5f*cosf(a), 1.5f*sinf(a)*sinf(b) );
	}

	m_sCoreSpline[0] = FLOATKEY(  0.0f, 2.5f );
	m_sCoreSpline[1] = FLOATKEY( 11.0f, 2.5f );
	m_sCoreSpline[2] = FLOATKEY( 11.8f, 0.0f );	

	InitFloatSpline( 3, m_sCoreSpline );
} 

CBigBang::~CBigBang()
{
	if( m_pvbPrticle )
		m_pvbPrticle->Release();

	if( m_pvbShockWavePod )
		m_pvbShockWavePod->Release();

	if( m_piqFade )
		delete m_piqFade;
}

BOOL CBigBang::InitEfx()
{
	return TRUE;
}

BOOL CBigBang::FinishEfx()
{
	return TRUE;
}

BOOL CBigBang::UpdateFrame( FLOAT fTime )
{
	m_psSystem.Update( fTime );

	m_pDevice->SetTransform( D3DTS_PROJECTION, ProjectionMtx( 60.0f, 0.75f, 0.5f, 1000.0f ) );
	m_pDevice->SetTransform( D3DTS_VIEW, CameraMtx( he3d_CVector( 0, 0, -50 ), he3d_CVector( 0, 0, 0 ), 0 ) );	

	if( fTime > 7.0f )
		m_psSystem.RemoveEmiter( &m_seEmiter );

	for( DWORD i = 0 ; i < 7 ; i++ )
		m_b3dBlob[i].m_vPos = m_vBlobsPos[i]*RotationMtx( m_fRotCoeff[i][0]*fTime + (FLOAT)i, m_fRotCoeff[i][1]*fTime + (FLOAT)i, m_fRotCoeff[i][2]*fTime + (FLOAT)i );

	m_bsSystem.CalculateDensity();	

	m_fCoreScale = 2.5f;
	m_fShockScale = 0.0f;

	FLOAT					fAlpha = (2.0f - fTime)*128.0f;

	if( fAlpha > 255.0f )
		fAlpha = 255.0f;

	if( fAlpha <= 0.0f )
		fAlpha = 0.0f;

	m_piqFade->SetAlpha( (DWORD)fAlpha );
	
	if( fTime > 11.8f )
	{
		fAlpha = 255.0f*(fTime - 11.8f);
		m_piqFlare->Resize( 256.0f - fAlpha*0.75f, 256.0f - fAlpha, 256.0f + fAlpha*0.75f, 256.0f + fAlpha );		

		m_piqFlare->SetAlpha( 0xff );
	}

	if( fTime > 13.0f )
	{
		m_piqFade->SetColor( 0xffffff );

		fAlpha = 140.0f*(fTime - 13.0f);

		if( fAlpha > 255.0f )
			fAlpha = 255.0f;

		m_piqFade->SetAlpha( (DWORD)fAlpha );
	}

	//if( fTime > 11.0f )	
	//	m_fCoreScale = 2.5f - 2.5f*(fTime - 11.0f);

	m_fCoreScale = GetFloatSplineValue( fTime, 3, m_sCoreSpline );
		
	if( fTime > 11.8f )
		m_fShockScale = 5.0f*(fTime-11.8f);

	if( m_fCoreScale < 0.0f )
		m_fCoreScale = 0.0f;

	PPARTICLEVERTEX			pVertices;
	he3d_CVector			v;

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

	for( i = 0 ; i < 30 ; i++ )
		for( DWORD j = 0 ; j < 10 ; j++ )
		{
			v = m_vParticle[i]*RotationMtx( fTime - 0.05f*(FLOAT)j, -fTime + 0.05f*(FLOAT)j, 0.5f*fTime - 0.025f*(FLOAT)j );

			pVertices[10*i + j].p = v;
			pVertices[10*i + j].size = 10.0f - 0.8f*(FLOAT)j;
			pVertices[10*i + j].color = 0xffffff;
		}

	m_pvbPrticle->Unlock();

	return TRUE;
}

BOOL CBigBang::RenderEfx()
{	
	m_pDevice->SetRenderState( D3DRS_ZENABLE, FALSE );

	m_pDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
	m_pDevice->Clear( 0, NULL, D3DCLEAR_TARGET, 0x0, 0, 0 );
	m_psSystem.Render( m_pDevice );		
	
	m_pDevice->SetTransform( D3DTS_WORLD, ScaleMtx( m_fCoreScale ) );

	m_pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
	m_pDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
	m_pDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
	m_pDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );

	m_pDevice->SetRenderState( D3DRS_POINTSPRITEENABLE, TRUE );
	m_pDevice->SetRenderState( D3DRS_POINTSPRITEENABLE, TRUE );

	m_pDevice->SetTexture( 0, GetTexture( "flare0.bmp" ) );
	m_pDevice->SetVertexShader( FVF_PARTICLEVERTEX );
	m_pDevice->SetStreamSource( 0, m_pvbPrticle, sizeof(PARTICLEVERTEX) );
	m_pDevice->DrawPrimitive( D3DPT_POINTLIST, 0, 300 );

	m_pDevice->SetTexture( 0, GetTexture( "envmap4.jpg" ) );
	m_pDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACENORMAL );
	m_pDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 );	
	m_pDevice->SetTransform( D3DTS_TEXTURE0, TranslationMtx( 1.0f, 1.0f, 1.0f )*ScaleMtx( 0.5f ) );	

	m_pDevice->SetRenderState( D3DRS_POINTSPRITEENABLE, FALSE );
	m_pDevice->SetRenderState( D3DRS_POINTSPRITEENABLE, FALSE );

	m_pDevice->SetRenderState( D3DRS_LIGHTING, TRUE );	

	D3DLIGHT8			d3dlit;
	ZeroMemory( &d3dlit, sizeof(D3DLIGHT8) );

	d3dlit.Type = D3DLIGHT_DIRECTIONAL;
	d3dlit.Attenuation0 = 1.0f;
	d3dlit.Range = 3000.0f;
	d3dlit.Position.x = 0.0f;
	d3dlit.Position.y = 0.0f;
	d3dlit.Position.z = 0.0f;
	d3dlit.Direction.x = 0.0f;
	d3dlit.Direction.y = 0.0f;
	d3dlit.Direction.z = 1.0f;
	d3dlit.Diffuse.r = 1.0f;
	d3dlit.Diffuse.g = 1.0f;
	d3dlit.Diffuse.b = 1.0f;

	m_pDevice->SetLight( 0, &d3dlit );
	m_pDevice->LightEnable( 0, TRUE );
	
	m_pDevice->SetRenderState( D3DRS_AMBIENT, 0x909090 );		
	m_bsSystem.Render( m_pDevice, FALSE );	
	
	m_pDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
	m_pDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_PASSTHRU );
	m_pDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );	

	m_pDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
	m_pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );	
	m_pDevice->SetTransform( D3DTS_WORLD, ZRotationMtx( H_PI )*YRotationMtx( H_PI2 + 0.1f )*ZRotationMtx( 0.1f )*ScaleMtx( m_fShockScale ) );

	m_pDevice->SetTexture( 0, GetTexture( "shockwave.jpg" ) );

	m_pDevice->SetVertexShader( FVF_LVERTEX );
	m_pDevice->SetStreamSource( 0, m_pvbShockWavePod, sizeof(LVERTEX) );
	m_pDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 100 );

	m_pDevice->SetTransform( D3DTS_WORLD, IdentMtx() );

	m_pDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
	m_pDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );

	m_pDevice->SetTexture( 0, GetTexture( "explodeflare.jpg" ) );
	m_pDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 );
	m_piqFlare->Render( m_pDevice );
	m_pDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );

	m_pDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
	m_pDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );

	m_pDevice->SetTexture( 0, NULL );	
	m_piqFade->Render( m_pDevice );	
	
	m_pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );	
	

	return TRUE;
}
