/******************************************************************************
*******************************************************************************

	Bubble Fight EX
	relminator
	http://rel.betterwebber.com


	Singleton Fx3D class


*******************************************************************************
******************************************************************************/

#include "Fx2D.h"

Fx2D* Fx2D::ms_instance = 0;

//--------------------------------------
//	
//--------------------------------------
Fx2D::Fx2D()
{
}

Fx2D::~Fx2D()
{
}

//--------------------------------------
//	
//--------------------------------------
Fx2D* Fx2D::Instance()
{
	if(ms_instance == 0){
		ms_instance = new Fx2D();
	}
	return ms_instance;
}

//--------------------------------------
//	
//--------------------------------------
void Fx2D::Release()
{
	if(ms_instance){
		delete ms_instance;
	}
	ms_instance = 0;
}


void Fx2D::Init()
{
	
	// constant sine divisor
	const u8 K1 = 32;
    const u8 K2 = 12;
    const u8 K3 = 28;
	
	// maximum values our dynamic plasmas can move
	// const u16 KSIN1 = (K1 *(360/57.3f));
    // const u16 KSIN2 = (K2 *(360/57.3f));
    // const u16 KSIN3 = (K3 *(360/57.3f));
	
	
    		
	// precalculate our luts
	for( int i = 0; i < ((2048) - 1); i++ )
	{
        Lsin1[i] = sin(i/(float)K1) * 32+32;
        Lsin2[i] = sin(i/(float)K2) * 16+16;
        Lsin3[i] = sin(i/(float)K3) * 20+20;
    }    

	// generate our 256 color palette
	for( int i = 0; i < 256; i++ )
	{
	    u8 r = (u8)(abs(int(16 - 15 * sin(i * M_PI / 16.0f))));
		u8 g = (u8)(abs(int(16 - 15 * sin(i * M_PI / 12.0f))));
		u8 b = (u8)(abs(int(16 - 15 * sin(i * M_PI / 18.0f))));
		PlasmaPal[i] = RGB15(r,g,b);
	}
	
}
//--------------------------------------
//	
//--------------------------------------
void Fx2D::Fade( unsigned short* Target,    // sub or main bg/oam 
				 const unsigned short* StartPal,  // pal to lerp from 
				 const unsigned short* EndPal,    // pal to lerp to 
				 s32 &Interp,
				 s32 Speed,
			     int MaxColors 
				)
{
   
	Interp += Speed;
	Interp = UTIL::Clamp(Interp,0,4096);
	
	dmaCopy( Palettes::Instance()->LerpPal( StartPal, EndPal,  Interp ),
			 Target,
			 MaxColors
		   );
	
	
}


//--------------------------------------
//	 Bugzoors!!!
//--------------------------------------
void Fx2D::Fade3D( int Color1,    // Color to fade to 
			       int Color2,
				   int Color3,
				   int Color4,
				   s32 &Interp,
			       s32 Speed
			     )
{

	Interp += Speed;
	Interp = UTIL::Clamp( Interp, 0, 4096 );
	int Trans = UTIL::Lerp( 1 << 12 , 30 << 12, Interp ) >> 12;  
	Trans = UTIL::Clamp( Trans, 1, 30 );
	
	glPolyFmt(POLY_ALPHA(Trans) | POLY_CULL_NONE | POLY_ID(63));
	//glPolyFmt(POLY_ALPHA(1 + UTIL::Wrap(Frame/8,30)) | POLY_CULL_NONE | POLY_ID(2));
	//glBoxFilled( 0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1, RGB15(0,0,0) );
			
//	glBoxFilledGradient( 0, 0, 255, 191,
//						 Color1,
//						 Color2,
//						 Color3,
//						 Color4
//					   );
//	
	glBoxFilled( 0, 0, 256, 192,
						 Color1
						 
					   );

}


//--------------------------------------
//	
//--------------------------------------
void Fx2D::AnimateSplashIn( int Palette, glImage* Tile )
{
	
	const int FRAMESTOANIMATE = 128;
	static s32 rotation = 0;
	static s32 scale = 0;
	
	s32 rotinc = ( (BRAD_PI*2) )/ FRAMESTOANIMATE;
	s32 sxinc = ( 1 << 12 )/ FRAMESTOANIMATE;
	
	if( rotation <(BRAD_PI*2))
	{
		rotation += rotinc;
		scale += sxinc;
	}
	rotation = UTIL::Clamp( rotation, 0, BRAD_PI*2 );
	
	glColorTable( GL_RGB16,  Palette );
	
	glSpriteRotateScaleXY( SCREEN_WIDTH/2, SCREEN_HEIGHT/2,
				   rotation,	
				   scale,
				   scale,
				   GL_FLIP_NONE,
				   Tile
				 );
	
}

//--------------------------------------
//	
//--------------------------------------
void Fx2D::AnimateSplashOut( int Palette, glImage* Tiles, int Color )
{
	
	static int frame = 0;
	static int scalex = BRAD_PI/2;
	static int scaley = BRAD_PI/2;
	static int lastx = 0; 
	static int lasty = 0; 
	static bool flip = false; 
	
	
	const int TILE_SIZE = 16;
 
	// calculate number of tiles per row and column
	const int SCREEN_TILE_X = SCREEN_WIDTH / TILE_SIZE;
	const int SCREEN_TILE_Y = SCREEN_HEIGHT / TILE_SIZE;
	
	glColorTable( GL_RGB16,  Palette );
	glColor(Color);
	
	
	for( int y = lasty; y < SCREEN_TILE_Y - lasty; y++ )
	{
		for( int x = lastx; x < SCREEN_TILE_X - lastx; x++ ) 
		{
			glSpriteRotateScaleXY( x * 16+8, y * 16+8,
						   frame * 230,	
						   sinLerp(scaley),
						   sinLerp(scalex),
						   GL_FLIP_NONE,
						   &Tiles[(y * 16 + x)]
						 );
		}
	}
	
	//int scale = abs(sinLerp(frame));
	frame++;
	scalex += 128;
	scaley += 64;
	
	if( (frame & 15) == 0 )
	{
		flip = !flip;
		if( flip )
		{
			if( lastx < (SCREEN_TILE_X/2) ) lastx++;
		}
		else
		{
			if( lasty < (SCREEN_TILE_Y/2-1) ) lasty++;
		}
	}
	
	
}	


//--------------------------------------
//	
//--------------------------------------
u8* Fx2D::PlasmaTrans()
{
	
	// offset 2nd plasma by a factor of 64 * 2 or (-64 to 64)
	u8 rot = 64;
	
	
	//write to vpage directly
	u8 *vpage_offset = Vpage;
	
	for(int ya = 0; ya < SCREEN_HEIGHT; ya++ )
	{
		for(int xa = 0; xa < SCREEN_WIDTH-1; xa++ )
		{
			rot = -rot;		// draw plasmas every other pixel
			// calculate colors
			u16 c = (Lsin1[xa + 1 + rot] + Lsin2[ya + 2 + rot] + Lsin3[1024+xa + ya - 4]);
			c = (Lsin1[xa + 1 + rot+c] + Lsin2[ya + 5 + rot+c] + Lsin3[1024+xa + ya - 1 + c]);
			// write to vram
			*vpage_offset++ = c;
		}
		vpage_offset++;		// magic
	}	

	return Vpage;
	
}


//--------------------------------------
//	
//--------------------------------------
u8* Fx2D::PlasmaTrans2()
{
	
	// offset 2nd plasma by a factor of 64 * 2 or (-64 to 64)
	u8 rot = 64;
	
	
	//write to vpage directly
	u8 *vpage_offset = Vpage;
	
	for(int ya = 0; ya < SCREEN_HEIGHT; ya++ )
	{
		for(int xa = 0; xa < SCREEN_WIDTH-1; xa++ )
		{
			rot = -rot;		// draw plasmas every other pixel
			// calculate colors
			u16 c = (Lsin2[xa + 1 + rot] + Lsin2[ya + 2 + rot] + Lsin3[1024+xa + ya - 4]);
			c = (Lsin3[xa + 1 + rot+c] + Lsin1[ya + 5 + rot+c] + Lsin2[1024+xa + ya - 1 + c]);
			// write to vram
			*vpage_offset++ = c;
		}
		vpage_offset++;		// magic
	}	

	return Vpage;
	
}


//--------------------------------------
//	
//--------------------------------------
void Fx2D::CyclePlasmaPal()
{
	
	for( int i = 0; i < 256; i++ )
	{
		int j = UTIL::Wrap(i+1, 255);
		PlasmaPal[i] = PlasmaPal[j];
	}
	
}

//--------------------------------------
//	
//--------------------------------------
void Fx2D::LoadPal( const unsigned short *pal )
{
	
	for( int i = 0; i < 256; i++ )
	{
		PlasmaPal[i] = pal[i];
	}
	
}
	