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

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


	Engine class


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

#include "Engine.h"

// Texture Packer generated files
#include "uvcoord_metroid_sprite.h"
#include "uvcoord_star_sprite.h"
#include "uvcoord_explosions_sprite.h"




void SpawnRandomBlobs( int Frame );
void SpawnRandomCancers( int Frame );
void SpawnRandomCentipedes( int Frame );
void SpawnRandomMetroids( int Frame );
void SpawnRandomPopcorns( int Frame );
void SpawnRandomSparks( int Frame );
void SpawnRandomTentakills( int Frame );


// Easy GL2D Sprite/Tile Sheets
static glImage StarImages[STAR_SPRITE_NUM_IMAGES];
static glImage CancerImages[8];
static glImage MetroidImages[METROID_SPRITE_NUM_IMAGES];
static glImage BlobImages[4];
static glImage TentakillImages[4];
static glImage CentipedeImages[4];
static glImage SparkyImages[4];
static glImage SmallEnemiesImages[1024/16];

static glImage ExplosionsImages[EXPLOSIONS_SPRITE_NUM_IMAGES];
static glImage Stage01BG[(128/16)*(256/16)];
static glImage Stage02BG[(256/16)*(64/16)];


// Splash screens (top)
static glImage Walar1a[1];
static glImage WalarTiles[ (256/16) * (192/16) ];

// Fonts
static glImage KromGLFontImages[1024/16];
static glImage BubblaGLFontImages[512/8];


// Bosses
static glImage MoaiImages[4];
static glImage CircleSawImages[1];
static glImage BouncerImages[4];


static Oamfont KromFont;
static Oamfont BubblaFont;

static GlFont KromGLFont;
static GlFont BubblaGLFont;

static Level Lvl;


// Sub BG ID
static int SubBG3;

// Font Palettes
static int BubblaGLFontTexPal;
static int KromGLFontTexPal;


// Images Palettes

// Player
static int StarTexPal;

// Enemies
static int CancerTexPal;
static int MetroidTexPal;
static int BlobTexPal;
static int TentakillTexPal;
static int CentipedeTexPal;
static int SparkyTexPal;

static int SmallEnemiesTexPal;

// Bosses
static int MoaiTexPal;
static int CircleSawTexPal;
static int BouncerTexPal;

// Explosions
static int ExplosionsTexPal;


// 3D BGs
static int Stage01BGTexPal;
static int Stage02BGTexPal;

// Texture Pal
static int OrganTexPal;
static int XmasballsTexPal;
static int MuscleTexPal;	

// Textures
static int MuscleTextureID;
static int OrganTextureID;
static int XmasballsTextureID;


static CancerContainer Cancers;
static MetroidContainer Metroids;
static BlobContainer Blobs;
static TentakillContainer Tentakills;
static CentipedeContainer Centipedes;
static SparkyContainer Sparkies;
static RotoSparkContainer RotoSparks;
static PopcornContainer Popcorns;
	


//--------------------------------------
//	
//--------------------------------------
Engine::Engine()
{
}

Engine::~Engine()
{
}


//--------------------------------------
//	
//--------------------------------------
void Engine::InitHardware()
{
	
	videoSetMode( MODE_5_3D );
	videoSetModeSub( MODE_5_2D );
	
	vramSetBankA( VRAM_A_TEXTURE );     
	vramSetBankB( VRAM_B_TEXTURE );     
	vramSetBankC( VRAM_C_TEXTURE );     
	vramSetBankD( VRAM_D_SUB_SPRITE );	// oam fonts et al
	vramSetBankH( VRAM_H_SUB_BG );		// Our sub BG  
	vramSetBankI( VRAM_I_SUB_BG_0x06208000 ); // H + I makes 256*192
	
	
}


//--------------------------------------
//	
//--------------------------------------
void Engine::InitEverything()
{
	
	// Initialize GL2D
    glScreen2D();
   
	// 2D FX
	Fx2D::Instance()->Init();
	
	// 3D FX
	Fx3D::Instance()->InitShapes();
	Fx3D::Instance()->InitStars();
	
	// Palettes
	Palettes::Instance()->Init();
	
	// Sound
	Sound::Instance()->Init( (mm_addr)soundbank_bin );
	Sound::Instance()->SetMode( MM_MODE_A );
	
	// Bg
	SubBG3 = bgInitSub( 3, BgType_Bmp8, BgSize_B8_256x256, 0, 0 );
	
	// Oam
	oamInit(&oamSub, SpriteMapping_1D_128, false);
	
}


//--------------------------------------
//	
//--------------------------------------
void Engine::LoadSounds()
{
	
	// BGMs
	Sound::Instance()->LoadBGM( MOD_INTRO );
	Sound::Instance()->LoadBGM( MOD_LEVEL01 );
	Sound::Instance()->LoadBGM( MOD_BOSS );
	Sound::Instance()->LoadBGM( MOD_ENDING );
	
	// SFXs
	Sound::Instance()->LoadSFX( SFX_BURST );
	Sound::Instance()->LoadSFX( SFX_ENTER );
	Sound::Instance()->LoadSFX( SFX_PLAYERMISS );
	Sound::Instance()->LoadSFX( SFX_HIT );
	Sound::Instance()->LoadSFX( SFX_SMALLEXP );
	Sound::Instance()->LoadSFX( SFX_MEDEXP1 );
	Sound::Instance()->LoadSFX( SFX_MEDEXP2 );
	Sound::Instance()->LoadSFX( SFX_BIGEXP );
	
	
}
	

//--------------------------------------
//	
//--------------------------------------
void Engine::LoadFonts()
{
	
	// Oam Fonts
	KromFont.Init(&oamSub, (u8*)font_kromTiles, 16, 16, SpriteSize_16x16, 64, 64);
	BubblaFont.Init(&oamSub, (u8*)font_bubblaTiles, 8, 8, SpriteSize_8x8, 64, 0);
	BubblaFont.LoadPalette( font_bubblaPal, SPRITE_PALETTE_SUB, 512 );
	
	BubblaGLFont.Load( BubblaGLFontImages,
			   8, 
			   8,
			   8,
			   512,
			   GL_RGB16,
			   TEXTURE_SIZE_8,
			   TEXTURE_SIZE_512,
			   TEXGEN_OFF|GL_TEXTURE_COLOR0_TRANSPARENT,
			   (u8*)glfont_bubblaBitmap	 
			 );
	BubblaGLFontTexPal = gluTexLoadPal( glfont_bubblaPal, glfont_bubblaPalLen, GL_RGB16 );
	
	
	KromGLFont.Load( KromGLFontImages,
			   16, 
			   16,
			   16,
			   1024,
			   GL_RGB16,
			   TEXTURE_SIZE_16,
			   TEXTURE_SIZE_1024,
			   TEXGEN_OFF|GL_TEXTURE_COLOR0_TRANSPARENT,
			   (u8*)glfont_kromBitmap	 
			 );
	KromGLFontTexPal = gluTexLoadPal( glfont_kromPal, glfont_kromPalLen, GL_RGB16 );
	
	
	
}


//--------------------------------------
//	
//--------------------------------------
void Engine::LoadImages()
{
	
	// Easy GL2D Images
	
	// Player
	glLoadSpriteSet( StarImages,				// pointer to glImage array
					 STAR_SPRITE_NUM_IMAGES, 	// Texture packer auto-generated #define
					 star_sprite_texcoords,		// Texture packer auto-generated array
					 GL_RGB256,				// texture type for glTexImage2D() in videoGL.h 
					 TEXTURE_SIZE_128,		// sizeX for glTexImage2D() in videoGL.h
					 TEXTURE_SIZE_128,		// sizeY for glTexImage2D() in videoGL.h
					 TEXGEN_OFF|GL_TEXTURE_COLOR0_TRANSPARENT, // param for glTexImage2D() in videoGL.h
					 (u8*)star_spriteBitmap	 	// image data generated by GRIT
				   );
	
	StarTexPal = gluTexLoadPal( star_spritePal, star_spritePalLen, GL_RGB256 );


	// Enemies
	glLoadTileSet( CancerImages,		// pointer to glImage array
				   32,				// sprite width
				   32,				// sprite height
				   32,				// bitmap image width
				   256,				// bitmap image height
				   GL_RGB16,		// texture type for glTexImage2D() in videoGL.h
				   TEXTURE_SIZE_32,	// sizeX for glTexImage2D() in videoGL.h
				   TEXTURE_SIZE_256,	// sizeY for glTexImage2D() in videoGL.h
				   TEXGEN_OFF|GL_TEXTURE_COLOR0_TRANSPARENT,
				   (u8*)cancer_spriteBitmap // image data generated by GRIT
				 );
	CancerTexPal = gluTexLoadPal( cancer_spritePal, cancer_spritePalLen, GL_RGB16 );
	
	
	glLoadSpriteSet( MetroidImages,				// pointer to glImage array
					 METROID_SPRITE_NUM_IMAGES, 	// Texture packer auto-generated #define
					 metroid_sprite_texcoords,		// Texture packer auto-generated array
					 GL_RGB16,				// texture type for glTexImage2D() in videoGL.h 
					 TEXTURE_SIZE_128,		// sizeX for glTexImage2D() in videoGL.h
					 TEXTURE_SIZE_256,		// sizeY for glTexImage2D() in videoGL.h
					 TEXGEN_OFF|GL_TEXTURE_COLOR0_TRANSPARENT, // param for glTexImage2D() in videoGL.h
					 (u8*)metroid_spriteBitmap	 	// image data generated by GRIT
				   );
	MetroidTexPal = gluTexLoadPal( metroid_spritePal, metroid_spritePalLen, GL_RGB16 );


	glLoadTileSet( BlobImages,		// pointer to glImage array
				   32,				// sprite width
				   32,				// sprite height
				   32,				// bitmap image width
				   128,				// bitmap image height
				   GL_RGB16,		// texture type for glTexImage2D() in videoGL.h
				   TEXTURE_SIZE_32,	// sizeX for glTexImage2D() in videoGL.h
				   TEXTURE_SIZE_128,	// sizeY for glTexImage2D() in videoGL.h
				   TEXGEN_OFF|GL_TEXTURE_COLOR0_TRANSPARENT,
				   (u8*)blob_spriteBitmap // image data generated by GRIT
				 );
	BlobTexPal = gluTexLoadPal( blob_spritePal, blob_spritePalLen, GL_RGB16 );


	glLoadTileSet( TentakillImages,		// pointer to glImage array
				   8,				// sprite width
				   8,				// sprite height
				   32,				// bitmap image width
				   8,				// bitmap image height
				   GL_RGB16,		// texture type for glTexImage2D() in videoGL.h
				   TEXTURE_SIZE_32,	// sizeX for glTexImage2D() in videoGL.h
				   TEXTURE_SIZE_8,	// sizeY for glTexImage2D() in videoGL.h
				   TEXGEN_OFF|GL_TEXTURE_COLOR0_TRANSPARENT,
				   (u8*)tentakill_spriteBitmap // image data generated by GRIT
				 );
	TentakillTexPal = gluTexLoadPal( tentakill_spritePal, tentakill_spritePalLen, GL_RGB16 );
	
	
	glLoadTileSet( CentipedeImages,		// pointer to glImage array
				   32,				// sprite width
				   32,				// sprite height
				   32,				// bitmap image width
				   64,				// bitmap image height
				   GL_RGB16,		// texture type for glTexImage2D() in videoGL.h
				   TEXTURE_SIZE_32,	// sizeX for glTexImage2D() in videoGL.h
				   TEXTURE_SIZE_64,	// sizeY for glTexImage2D() in videoGL.h
				   TEXGEN_OFF|GL_TEXTURE_COLOR0_TRANSPARENT,
				   (u8*)centipede_spriteBitmap // image data generated by GRIT
				 );
	CentipedeTexPal = gluTexLoadPal( centipede_spritePal, centipede_spritePalLen, GL_RGB16 );
	
	glLoadTileSet( SparkyImages,		// pointer to glImage array
				   20,				// sprite width
				   96,				// sprite height
				   64,				// bitmap image width
				   128,				// bitmap image height
				   GL_RGB16,		// texture type for glTexImage2D() in videoGL.h
				   TEXTURE_SIZE_64,	// sizeX for glTexImage2D() in videoGL.h
				   TEXTURE_SIZE_128,	// sizeY for glTexImage2D() in videoGL.h
				   TEXGEN_OFF|GL_TEXTURE_COLOR0_TRANSPARENT,
				   (u8*)sparky_spriteBitmap // image data generated by GRIT
				 );
	SparkyTexPal = gluTexLoadPal( sparky_spritePal, sparky_spritePalLen, GL_RGB16 );
	
	
	glLoadSpriteSet( ExplosionsImages,				// pointer to glImage array
					 EXPLOSIONS_SPRITE_NUM_IMAGES, 	// Texture packer auto-generated #define
					 explosions_sprite_texcoords,		// Texture packer auto-generated array
					 GL_RGB256,				// texture type for glTexImage2D() in videoGL.h 
					 TEXTURE_SIZE_256,		// sizeX for glTexImage2D() in videoGL.h
					 TEXTURE_SIZE_128,		// sizeY for glTexImage2D() in videoGL.h
					 TEXGEN_OFF|GL_TEXTURE_COLOR0_TRANSPARENT, // param for glTexImage2D() in videoGL.h
					 (u8*)explosions_spriteBitmap	 	// image data generated by GRIT
				   );
	ExplosionsTexPal = gluTexLoadPal( explosions_spritePal, explosions_spritePalLen, GL_RGB256 );
	
	glLoadTileSet( Stage01BG,		// pointer to glImage array
				   16,				// sprite width
				   16,				// sprite height
				   128,				// bitmap image width
				   256,				// bitmap image height
				   GL_RGB256,		// texture type for glTexImage2D() in videoGL.h
				   TEXTURE_SIZE_128,	// sizeX for glTexImage2D() in videoGL.h
				   TEXTURE_SIZE_256,	// sizeY for glTexImage2D() in videoGL.h
				   TEXGEN_OFF|GL_TEXTURE_COLOR0_TRANSPARENT,
				   (u8*)stage01bgBitmap // image data generated by GRIT
				 );
	Stage01BGTexPal = gluTexLoadPal( stage01bgPal, stage01bgPalLen, GL_RGB256 );
	
	glLoadTileSet( Stage02BG,		// pointer to glImage array
				   16,				// sprite width
				   16,				// sprite height
				   256,				// bitmap image width
				   64,				// bitmap image height
				   GL_RGB256,		// texture type for glTexImage2D() in videoGL.h
				   TEXTURE_SIZE_256,	// sizeX for glTexImage2D() in videoGL.h
				   TEXTURE_SIZE_64,	// sizeY for glTexImage2D() in videoGL.h
				   TEXGEN_OFF|GL_TEXTURE_COLOR0_TRANSPARENT,
				   (u8*)stage02bgBitmap // image data generated by GRIT
				 );
	Stage02BGTexPal = gluTexLoadPal( stage02bgPal, stage02bgPalLen, GL_RGB256 );
	
	
	
	
	OrganTexPal = gluTexLoadPal( organPal, organPalLen, GL_RGB256 );
	XmasballsTexPal = gluTexLoadPal( xmasballsPal, xmasballsPalLen, GL_RGB256 );
	
	
	
	glLoadTileSet( SmallEnemiesImages,		// pointer to glImage array
				   16,				// sprite width
				   16,				// sprite height
				   16,				// bitmap image width
				   1024,				// bitmap image height
				   GL_RGB256,		// texture type for glTexImage2D() in videoGL.h
				   TEXTURE_SIZE_16,	// sizeX for glTexImage2D() in videoGL.h
				   TEXTURE_SIZE_1024,	// sizeY for glTexImage2D() in videoGL.h
				   TEXGEN_OFF|GL_TEXTURE_COLOR0_TRANSPARENT,
				   (u8*)small_enemies_spriteBitmap // image data generated by GRIT
				 );
	SmallEnemiesTexPal = gluTexLoadPal( small_enemies_spritePal, small_enemies_spritePalLen, GL_RGB256 );
	
	// Muscle
	glGenTextures(1, &MuscleTextureID);
	glBindTexture(0, MuscleTextureID);
	glTexImage2D( 0, 0, GL_RGB256, TEXTURE_SIZE_128, TEXTURE_SIZE_128, 
	              0, GL_TEXTURE_WRAP_S|GL_TEXTURE_WRAP_T, (u8*)muscleBitmap );
	
	MuscleTexPal = gluTexLoadPal( musclePal, musclePalLen, GL_RGB256 );
	
	// Boss
	glLoadTileSet( MoaiImages,		// pointer to glImage array
				   64,				// sprite width
				   64,				// sprite height
				   256,				// bitmap image width
				   64,				// bitmap image height
				   GL_RGB16,		// texture type for glTexImage2D() in videoGL.h
				   TEXTURE_SIZE_256,	// sizeX for glTexImage2D() in videoGL.h
				   TEXTURE_SIZE_64,	// sizeY for glTexImage2D() in videoGL.h
				   TEXGEN_OFF|GL_TEXTURE_COLOR0_TRANSPARENT,
				   (u8*)moai_spriteBitmap // image data generated by GRIT
				 );
	MoaiTexPal = gluTexLoadPal( moai_spritePal, moai_spritePalLen, GL_RGB16 );
	
	glLoadTileSet( CircleSawImages,		// pointer to glImage array
				   32,				// sprite width
				   32,				// sprite height
				   32,				// bitmap image width
				   32,				// bitmap image height
				   GL_RGB16,		// texture type for glTexImage2D() in videoGL.h
				   TEXTURE_SIZE_32,	// sizeX for glTexImage2D() in videoGL.h
				   TEXTURE_SIZE_32,	// sizeY for glTexImage2D() in videoGL.h
				   TEXGEN_OFF|GL_TEXTURE_COLOR0_TRANSPARENT,
				   (u8*)circlesaw_spriteBitmap // image data generated by GRIT
				 );
	CircleSawTexPal = gluTexLoadPal( circlesaw_spritePal, circlesaw_spritePalLen, GL_RGB16 );
	
	glLoadTileSet( BouncerImages,		// pointer to glImage array
				   64,				// sprite width
				   64,				// sprite height
				   64,				// bitmap image width
				   256,				// bitmap image height
				   GL_RGB16,		// texture type for glTexImage2D() in videoGL.h
				   TEXTURE_SIZE_64,	// sizeX for glTexImage2D() in videoGL.h
				   TEXTURE_SIZE_256,	// sizeY for glTexImage2D() in videoGL.h
				   TEXGEN_OFF|GL_TEXTURE_COLOR0_TRANSPARENT,
				   (u8*)bouncer_spriteBitmap // image data generated by GRIT
				 );
	BouncerTexPal = gluTexLoadPal( bouncer_spritePal, bouncer_spritePalLen, GL_RGB16 );
	
	Explosion::Instance()->Init(ExplosionsTexPal, ExplosionsImages );
	
	
}

//--------------------------------------
//	
//--------------------------------------
void Engine::Load3D()
{
	
	OrganTextureID = Fx3D::Instance()->LoadAscaris( GL_RGB256,
						 TEXTURE_SIZE_128, 
						 TEXTURE_SIZE_128, 
						 GL_TEXTURE_WRAP_S|GL_TEXTURE_WRAP_T,
						 (u8*)organBitmap, 
						 OrganTexPal
					   );
					   
	Fx3D::Instance()->LoadShapes( GL_RGB256,
						 MuscleTextureID, 
						 MuscleTexPal
					   );
	
	XmasballsTextureID = Fx3D::Instance()->LoadGrid( GL_RGB256,
						 TEXTURE_SIZE_128, 
						 TEXTURE_SIZE_128, 
						 GL_TEXTURE_WRAP_S|GL_TEXTURE_WRAP_T,
						 (u8*)xmasballsBitmap, 
						 XmasballsTexPal
					   );
	
	
}

//--------------------------------------
//	
//--------------------------------------
void Engine::GameDoSubScreen( int Frame, s32 &BGInterp )
{
	
	BubblaFont.Clear(); // deactivate every oam per frame
	KromFont.Clear(); // deactivate every oam per frame
	
	// Print stuff via OAM
	KromFont.Print(0, 0, "CONTROLS");
	
	BubblaFont.Print(0, 30, "FLY       = ");
	KromFont.Print(98, 30-8, "UP/A");
	
	BubblaFont.Print(0, 60, "MOVE      = ");
	KromFont.Print(98, 60-8, "LEFT/RIGHT");
	
	
	BubblaFont.Print(0, 90, "BURST     = ");
	KromFont.Print(98, 90-8, "B");
	
	BubblaFont.Print(0, 120, "DEBUG     = ");
	KromFont.Print(98, 120-8, "SELECT");
	
	BubblaFont.Print(0, 150, "PAUSE     = ");
	KromFont.Print(98, 150-8, "START");
	
	BubblaFont.Print(0, 180, "FRAMES:");
	KromFont.PrintScore(60, 180-8, Frame, "0",7);
	
	// Draw
	oamUpdate(&oamSub);
	
	// Fade the fonts from black to pal
	Fx2D::Instance()->Fade( SPRITE_PALETTE_SUB,
							Palettes::Instance()->GetBlack(),
							font_bubblaPal,
							BGInterp,
							32,
							512
						  );

	
	
	
	
	// fade from black sub bg
	Fx2D::Instance()->Fade( BG_PALETTE_SUB,
							Palettes::Instance()->GetBlack(),
							Fx2D::Instance()->GetPlasmaPal(),
							BGInterp,
							16,
							512
						  );
	
	// Animate the plazma!
	Fx2D::Instance()->CyclePlasmaPal();
	
	
}
	

void Engine::GameUpdateAll( int Frame,
							int KeyH,
							int KeyD,
							int Stage,
							bool &StageFinished,
							StarFighter &Star,
							std::vector<EntityContainer*> Enemies,
							Level &Lvl
						  )
{
  
	// Player
	if( Star.IsAlive )
	{
		StageFinished = Star.Update( KeyH, KeyD );
	}
	else
	{
		if( Star.Lives > -1 )
		{
			Star.NewLifeCounter--;
			if( Star.NewLifeCounter == 0 )
			{
				Star.NewLife();
				Sound::Instance()->PlaySFX(E_SFX_ENTER);
			}
	
		}
		
	}
	
	// Level
	Lvl.Update( Stage, Frame );
	
	// update all enemy types
	std::vector<EntityContainer*>::iterator iter;
	for( iter = Enemies.begin(); iter != Enemies.end(); ++iter )
	{
		(*iter)->UpdateEntities();
	}

	Explosion::Instance()->Update();
	
	
}

//--------------------------------------
//	
//--------------------------------------
void Engine::GamePause( int Frame,
						int Stage,
						s32 &BGInterp,
				        const StarFighter &Star,
				        std::vector<EntityContainer*> Enemies,
				        const Level &Lvl
			          )
{
  
	bool IsPaused = true;
	bool PressStart = true;
	int frames = 0;
	while( IsPaused )
	{
		frames++;
		scanKeys();
		int KD = keysDown();

		if (KD & KEY_START)
		{
			IsPaused = false;
			
		}
		
		
		Lvl.Draw3D(Stage, Frame );		
		
		// set up GL2D for 2d mode
		glBegin2D();

			Lvl.Draw2D(Stage, Frame );		
		
			// draw all enemies
			std::vector<EntityContainer*>::iterator iter;
			for( iter = Enemies.begin(); iter != Enemies.end(); ++iter )
			{
				(*iter)->DrawEntities();
			}
		
			// draw star
			Star.Draw( StarTexPal, StarImages );
			
			
			// Tell the player that he paused
			glColorTable( GL_RGB16, KromGLFontTexPal );
			glColor( RGB15( 16 + ((frames/4) & 15),
						    16 + ((frames/2) & 15),
						    16 + ((16-(frames/8)) & 15)
						  )
				   );
			KromGLFont.PrintCentered(0,60, "PAUSED");	
			// Draw the Press Start string
			if( (frames & 31)==0 )PressStart = !PressStart;
			if( PressStart )
			{
				glColor( RGB15(31,31,31) );
				KromGLFont.PrintCentered(0,100, "PRESS START");
			}
			
			// Draw score and lives left
			glColorTable(GL_RGB16, BubblaGLFontTexPal);
			glColor( RGB15(31,31,31) );
			BubblaGLFont.Print( 00, 0, "SCORE: " );				  
			BubblaGLFont.PrintScore( 56, 0, Star.Score, "0", 7 );				  
			BubblaGLFont.Print( 00, 10, "LEFT: ", Star.Lives );				  
			
		// end 2D rendering mode		
		glEnd2D();
		
		glFlush(0); 
		
		swiWaitForVBlank();
		
		GameDoSubScreen( Frame, BGInterp );

	}
		
	
}

void Engine::GameSpawnEnemies( int Frame )
{
	static int EnemyType = 0;
	
	//  temp spawning system
	
	//SpawnRandomTentakills( Frame );

	if((Frame & 2047) == 0) Centipedes.Spawn( 300, 96 );
		
		// spawn enemy
	if( (Frame & 255) == 0 )
	{
		bool srot;
		EnemyType = (EnemyType + 1) % 7;
		switch( EnemyType )
		{
			case 0:
				Cancers.Spawn( 300, qran_range(16, 192-16) );
				break;
			case 1:
				Metroids.Spawn( 300, qran_range(16, 192-16),
								-qran_range( 1024, 2048 ),
								qran_range(10, 50)
							  );
				break;
			case 2:
				Blobs.Spawn( 300, qran_range(16, 192-16),
								-qran_range( 512, 1024 ),
								qran_range(25, 50)
							  );
				break;
			case 3:
				Tentakills.Spawn( 320, qran_range(16, 192-16),
								 -qran_range( 1024, 4096 ),
								  qran_range(10, 50), 
								  qran() );
				break;
			case 4:
				Sparkies.Spawn( 300, qran_range(16, 192-16) );
				break;
			case 5:
				srot =  qran_range(0, 256) > 128;
				RotoSparks.Spawn( 300, qran_range(16, 192-16), srot );
				break;
			case 6:
				Popcorns.Spawn( 300, qran_range(16, 192-16),
							   -qran_range( 512, 1024 ),
								qran_range(25, 50)
							  );
				break;
			default:
				Cancers.Spawn( 300, qran_range(16, 192-16) );
		}
		
	}
	
		
}
	
//--------------------------------------
//	
//--------------------------------------
void Engine::Main()
{
  
	const int FADE_BGM = 4096*2+128;
	const int START_BOSS = FADE_BGM + (64*3);
	const int STOP_SPAWING = FADE_BGM - (64*5);
	
	const int DO_INTRO = true;
	const int DO_SPLASH = true;
	const int DRAW_3D = true;
	const int SPAWN_BADDIES = true;
	
	InitHardware();
	InitEverything();
	
	LoadSounds();
	LoadFonts();
	LoadImages();
	Load3D();
	
	Cancers.Init( CancerTexPal, CancerImages );
	Metroids.Init( MetroidTexPal, MetroidImages );
	Blobs.Init( BlobTexPal, BlobImages );
	Tentakills.Init( TentakillTexPal, TentakillImages );
	Centipedes.Init( CentipedeTexPal, CentipedeImages );
	Sparkies.Init( SparkyTexPal, SparkyImages );
	RotoSparks.Init( SparkyTexPal, SparkyImages );
	Popcorns.Init( CancerTexPal, CancerImages );
	
	
	Lvl.Init( Stage02BGTexPal, Stage02BG, 2 );
	
	
	//DoEnding();
	
	Fx2D::Instance()->LoadPal( plasma_pal2Pal );
	Sound::Instance()->SetMasterVolume( 512 );
	Sound::Instance()->PlayBGM( E_BGM_INTRO, MM_PLAY_LOOP );
	
	if( DO_SPLASH ) DoSplash();
	
	
	
	
	
	// Player
	StarFighter Star;

	// Enemy Containers
		
	
	
	std::vector<EntityContainer*> Enemies;
	
	// order of drawing is from centipedes to tentakills
	Enemies.push_back( &Centipedes );
	Enemies.push_back( &Sparkies );
	Enemies.push_back( &RotoSparks );
	Enemies.push_back( &Metroids );
	Enemies.push_back( &Cancers );
	Enemies.push_back( &Blobs );
	Enemies.push_back( &Popcorns );
	Enemies.push_back( &Tentakills );
	
	
	// bosses
	Moai MoaiBoss;
	MoaiBoss.Init( MoaiTexPal, MoaiImages );
	
	CircleSaw CircleSawBoss;
	CircleSawBoss.Init( CircleSawTexPal, CircleSawImages );
	
	Bouncer BouncerBoss;
	BouncerBoss.Init( BouncerTexPal, BouncerImages );
	
	Tentaklaus TentaklausBoss;
	TentaklausBoss.Init( SmallEnemiesTexPal, SmallEnemiesImages );
	
	std::vector<BossEntity*> Boss;
	
	Boss.push_back( &MoaiBoss );
	Boss.push_back( &CircleSawBoss );
	Boss.push_back( &BouncerBoss );
	Boss.push_back( &TentaklausBoss );
	
	
	int CurrentBoss = 0;
	int HighScore = 0;
	bool GameActive = true;
	int Stage = 1;
	bool StageFinished = false; 
	bool IsPaused = false;
	bool GameOver = false;
	int CanContinueCounter = 60 * 13;
	int CanPressStartCounter = 60 * 3;
	bool PrintGameOver = false;
		
	
	int Frame = 0;

	s32 FontInterp = 0;
	bool Collided = false;
	bool ShowDebug = false;
	s32 BGInterp = 0; // SubBG fader
	s32 SoundInterp = 1 << 12;
	
while( 1 )
{
	GameActive = true;
	Stage = 1;
	CurrentBoss = 0;
	StageFinished = false; 
	IsPaused = false;
	GameOver = false;
	CanContinueCounter = 60 * 13;
	CanPressStartCounter = 60 * 3;
	PrintGameOver = false;
	
	// Intro
	if( DO_INTRO ) DoIntro();
	
	// load new palette for the gameplay sub bg
	u8* Plaz = Fx2D::Instance()->PlasmaTrans2();
	dmaCopy( Plaz, bgGetGfxPtr(SubBG3), SCREEN_WIDTH * SCREEN_HEIGHT );
	
	// Change BGM and rest volume
	Sound::Instance()->PlayBGM( E_BGM_LEVEL, MM_PLAY_LOOP );
	Sound::Instance()->SetMasterVolume( 512 );
	
	// Change pal
	Fx2D::Instance()->LoadPal( plasma_palPal );
	
	Star.Lives = 2;
	Star.NewLife();
	Star.Score = 0;
				
	while( GameActive )
	{
		// Reload Stage 
		switch( Stage )
		{
			case 1:
				Fx3D::Instance()->ReloadAscarisTexture( GL_RGB256,
													OrganTextureID,
													OrganTexPal
												  );
				
				break;
			case 3:
				Fx3D::Instance()->ReloadAscarisTexture( GL_RGB256,
													MuscleTextureID,
													MuscleTexPal
												  );
		}
		
		
		KillAllEnemies( Enemies, Boss[CurrentBoss] );
		
		SoundInterp =  1 << 12;
		FontInterp = 0;
		StageFinished = false; 
		Collided = false;
		Frame = 0;
		BGInterp = 0; // SubBG fader
		IsPaused = false;
		Sound::Instance()->PlaySFX(E_SFX_ENTER);
		while( !StageFinished )
		{
	
		
			Frame++;
			
			scanKeys();
			int KeyH = keysHeld();
			int KeyD = keysDown();
		
			if( (KeyD & KEY_SELECT) )
			{	
				ShowDebug = !ShowDebug; 
			}
			
			if( !GameOver )
			{
				if (KeyD & KEY_START)
					IsPaused = true;
			}
			else
			{
				if( CanContinueCounter > 0 )
				{
					CanContinueCounter--;
					if( CanPressStartCounter > 0 )
					{
						CanPressStartCounter--;
					}
					else
					{
						if (KeyD & KEY_START)
						{
							Star.Lives = 2;
							Star.Score = 0;
							GameOver = false;
							CanPressStartCounter = 60 * 3;
							CanContinueCounter = 60 * 13;
						}
						
					}
				}
				else	//Return to title
				{
					Sound::Instance()->FadeBGM( SoundInterp, -16 );
					if (KeyD & KEY_START)
					{
						GameActive = false;
						StageFinished = true;
					}
				}
			}
				
			
			
			if( Star.Lives == -1 )
			{
				GameOver = true;
			}
			if( (!Boss[CurrentBoss]->IsAlive()) && (Frame > START_BOSS) )
			{
				Boss[CurrentBoss]->DecDestroyedCounter();
				Sound::Instance()->FadeBGM( SoundInterp, -16 );
			}
				
			if( (Boss[CurrentBoss]->GetDestroyedCounter() < 0) )
			{
				if ( Boss[CurrentBoss]->GetDestroyedCounter() == -1 )
				{
					Boss[CurrentBoss]->SetDestroyedCounter(0xFFFFFF);
					Sound::Instance()->PlaySFX(E_SFX_ENTER);
					Star.Mode = StarFighter::E_EXIT;
					Star.State = StarFighter::E_LOCKED | StarFighter::E_INVINCIBLE;				
				}
			}
		
			if( (Frame > FADE_BGM) && (Frame < START_BOSS) )
			{
				Sound::Instance()->FadeBGM( SoundInterp, -16 );
			}
			if( Frame == START_BOSS )
			{
				SoundInterp = 1 << 12;
				Sound::Instance()->SetMasterVolume( 512 );
				Sound::Instance()->PlayBGM( E_BGM_BOSS, MM_PLAY_LOOP );
				Boss[CurrentBoss]->Spawn();
			}
			
			if( SPAWN_BADDIES )
				if( Frame < STOP_SPAWING ) GameSpawnEnemies( Frame );
			
			Boss[CurrentBoss]->Update();
			
			// Update
			GameUpdateAll( Frame,
						   KeyH,
						   KeyD,
						   Stage,
						   StageFinished,
						   Star,
						   Enemies,
						   Lvl
						 );
						 
			// collision
			Collided = false;
			std::vector<EntityContainer*>::iterator iter;
			for( iter = Enemies.begin(); iter != Enemies.end(); ++iter )
			{
				Collided = (*iter)->Collide(Star);
				//if( Collided ) break;
			}

			Boss[CurrentBoss]->Collide(Star);
			
			// check high score
			if( Star.Score > HighScore ) HighScore  = Star.Score;
			
			if( DRAW_3D ) Lvl.Draw3D(Stage, Frame );		
			
			// set up GL2D for 2d mode
			glBegin2D();

				
				Lvl.Draw2D(Stage, Frame );		
				
				Boss[CurrentBoss]->Draw();
				
				// draw all enemies
				for( iter = Enemies.begin(); iter != Enemies.end(); ++iter )
				{
					(*iter)->DrawEntities();
				}
				
				Explosion::Instance()->Draw();
		
				// draw star
				Star.Draw( StarTexPal, StarImages );
				
				if( ShowDebug )
					DrawDebug( Frame, Stage, StageFinished, Star, Enemies );
				
				// Draw score and lives left
				glColorTable(GL_RGB16, BubblaGLFontTexPal);
				glColor( RGB15(31,31,31) );
				BubblaGLFont.Print( 00, 0, "SCORE: " );				  
				BubblaGLFont.PrintScore( 56, 0, Star.Score, "0", 7 );
				
				BubblaGLFont.Print( 128, 0, "HIGH: " );				  
				BubblaGLFont.PrintScore( 128+48, 0, HighScore, "0", 7 );
				
				int LivesLeft = Star.Lives;
				if( LivesLeft < 0 ) LivesLeft = 0;
				BubblaGLFont.Print( 00, 10, "LEFT: ", LivesLeft );				  
				
				
				if( Frame < 512 )
				{
					
					glColorTable(GL_RGB16, KromGLFontTexPal);
					glColor( RGB15(31,0,31) );
				
					if( Frame < 256 )
					{
						FontInterp += 64;
						if( FontInterp > 4096 )  FontInterp = 4096;
						int x = UTIL::Lerp( 300 << 12, 48 << 12, FontInterp ) >> 12;
						int y = UTIL::Lerp( 200 << 12, 76 << 12, FontInterp ) >> 12;
						int spacing = UTIL::Lerp( 7 << 12, 0 << 12, FontInterp );
						KromGLFont.PrintSpaced( x, y, "BURST AWAY", 0, -spacing , -spacing );
					}
					else
					{
						if( Frame == 256 ) FontInterp = 0;
						FontInterp += 64;
						if( FontInterp > 4096 )  FontInterp = 4096;
						int x = UTIL::Lerp( 48 << 12, -200 << 12,FontInterp ) >> 12;
						int y = UTIL::Lerp( 76 << 12, -16 << 12,FontInterp ) >> 12;
						int spacing = UTIL::Lerp( 0 << 12, 7 << 12, FontInterp );
						KromGLFont.PrintSpaced( x, y, "BURST AWAY", 0, -spacing , spacing );					
					}
		
				}
				
				if( GameOver && (CanPressStartCounter <= 0))
				{
					glColorTable(GL_RGB16, KromGLFontTexPal);
					
					if( PrintGameOver )
					{
					glColor( RGB15(0,31,0) );
					
						KromGLFont.PrintCentered( 0, 76, "GAME OVER");
					}
					else
					{
						if( CanContinueCounter > 0 )
						{
							glColor( RGB15(31,31,31) );
							KromGLFont.PrintCentered( 0, 66, "PRESS START");
							KromGLFont.PrintCentered( 0, 86, "TO CONTINUE");
						}
						else
						{
							glColor( RGB15(31,31,0) );
							KromGLFont.PrintCentered( 0, 46, "PRESS START");
							KromGLFont.PrintCentered( 0, 66, "TO RETURN");
							KromGLFont.PrintCentered( 0, 86, "TO TITLE");
						}
						
					}
					
					if( (Frame & 31) == 0 ) PrintGameOver = !PrintGameOver;
					
					glColor( RGB15(31,31,31) );
					if( CanContinueCounter >= 0 )
						KromGLFont.PrintCentered( 0, 106, CanContinueCounter/60);
					 
				}
				
			// end 2D rendering mode		
			glEnd2D();
			
			glFlush(0); 
			
			
			swiWaitForVBlank();
		
			GameDoSubScreen( Frame, BGInterp );
		
			if( IsPaused )
			{
				GamePause( Frame,
						   Stage,
						   BGInterp,
						   Star,
						   Enemies,
						   Lvl
						  );
				IsPaused = false;
			}
		
		} // End while(StageFinished)
		
		Stage++;
		CurrentBoss = (CurrentBoss + 1 ) & 3;
		if( Stage > 4 )
		{
			Stage = 1;
			DoEnding();
		}
		Star.NewLife();
		// reset volume
		Sound::Instance()->SetMasterVolume( 512 );
		Sound::Instance()->PlayBGM( E_BGM_LEVEL, MM_PLAY_LOOP );
		
	}  // End GameActive
	
	// Load new BGM for the intro
	Fx2D::Instance()->LoadPal( plasma_pal2Pal );
	Sound::Instance()->SetMasterVolume( 512 );
	Sound::Instance()->PlayBGM( E_BGM_INTRO, MM_PLAY_LOOP );
	

} // End while(1)		
	
}


//--------------------------------------
//	
//--------------------------------------
void Engine::DoIntro()
{
	
	const int READY_TO_PLAY = 64 * 12;
	const int START_FONT_SINE  = 64 * 8;
	
	bool finished = false;
	int findelay = 60*3;
	int frame= 0 ;
	s32 PalInterp = 0;
	s32 ColInterp = 0;
	s32 HeightInterp = 0;
	bool PressStart = false;
	s32 SoundInterp = 1 << 12;
	
	s32 Spacing = 7 << 12;
			
	u8 *Plaz = Fx2D::Instance()->PlasmaTrans();
	dmaCopy( Plaz, bgGetGfxPtr(SubBG3), SCREEN_WIDTH * SCREEN_HEIGHT );
	
	
	while( (findelay > 0) )
	{
	
		frame++;
		scanKeys();
		int key_down = keysDown();
		
		if( frame > READY_TO_PLAY)
		{
			if (key_down & KEY_START)
			{
				//fade BG
				if( !finished ) PalInterp = 0;
				// SoundInterp is already 1 << 12 above
				finished = true;
			}
		}
		if( finished )
		{
			findelay--;
			Sound::Instance()->FadeBGM( SoundInterp,-16 );
		}
			
		
		frame++;
		Fx3D::Instance()->UpdateStars();
		Fx3D::Instance()->DrawParts();
		
		
		glBegin2D();

			if( frame < START_FONT_SINE )
			{
				Spacing -= 128;
				Spacing  = UTIL::Clamp( Spacing, 0, 7 << 12 );
				ColInterp += 16;
				ColInterp = UTIL::Clamp( ColInterp,0,4096 );
		
				int col = UTIL::Lerp( 1 << 12, 31 << 12, ColInterp ) >> 12;
				col = UTIL::Clamp( col, 1, 31 );
				
				glColorTable( GL_RGB16, KromGLFontTexPal );
				glColor( RGB15(col,col,col) );
				
				KromGLFont.PrintSpaced( 32, 60,  "BUBBLE", 0, Spacing, -Spacing  );
				KromGLFont.PrintSpaced( 32+16*7, 60,  "FIGHT", 0, -Spacing, Spacing  );
				
				KromGLFont.PrintSineVertical( 120, 40,  "E X", 2, 8, 3, 0 );
				
				glColorTable( GL_RGB16, BubblaGLFontTexPal );
				BubblaGLFont.PrintCentered(0,0, "RELMINATOR PRESENTS");
				BubblaGLFont.PrintCentered(0,8, "HTTP://REL.BETTERWEBBER.COM");
				
				BubblaGLFont.PrintCentered(0,105, "PRODUCER");
				BubblaGLFont.PrintCentered(0,117, "ANYA THERESE B. LOPE");
				BubblaGLFont.PrintCentered(0,140, "SPONSORS");
				BubblaGLFont.PrintCentered(0,152, "NINTENDOMAX:DEVKITPRO");
				BubblaGLFont.PrintCentered(0,162, "EASY GL2D:LIBNDS:MAXMOD");
				
				glColorTable( GL_RGB16, KromGLFontTexPal );
				KromGLFont.PrintCentered(0,176, "W34P0NZ R 4 K1DZ");
				
			}
			else
			{
				
				HeightInterp += 16;
				int h = UTIL::Lerp( 0 << 12, 16 << 12, HeightInterp ) >> 12;
				h = UTIL::Clamp( h, 0, 12 );
				
				glColorTable( GL_RGB16, KromGLFontTexPal );
				KromGLFont.PrintSine( 32, 60,  "BUBBLE FIGHT", 0, h, 4, frame << 8 );
				
				glColor( RGB15(frame,frame*2,31-frame) );
				KromGLFont.PrintSineVertical( 120, 40,  "E X", 2, 8, 3, frame << 9 );
				
				glColor( RGB15(31,31,31) );
				glColorTable( GL_RGB16, BubblaGLFontTexPal );
				BubblaGLFont.PrintCentered(0,0, "RELMINATOR PRESENTS");
				BubblaGLFont.PrintCentered(0,8, "HTTP://REL.BETTERWEBBER.COM");
				
				BubblaGLFont.PrintCentered(0,105, "PRODUCER");
				BubblaGLFont.PrintCentered(0,117, "ANYA THERESE B. LOPE");
				BubblaGLFont.PrintCentered(0,140, "SPONSORS");
				BubblaGLFont.PrintCentered(0,152, "NINTENDOMAX:DEVKITPRO");
				BubblaGLFont.PrintCentered(0,162, "EASY GL2D:LIBNDS:MAXMOD");
		
				glColorTable( GL_RGB16, KromGLFontTexPal );
				KromGLFont.PrintCentered(0,176, "W34P0NZ R 4 K1DZ");
				
		
			}
					
			
			
			// ready to play
			if( (frame > READY_TO_PLAY) && (!finished) )
			{
				if( (frame & 31)==0 )PressStart = !PressStart;
				if( PressStart )
				{
					glColorTable( GL_RGB16, KromGLFontTexPal );
					glColor( RGB15(-frame,frame*3,31-frame*4) );
					KromGLFont.PrintCentered(0,90, "PRESS START");
				}
						
			}
		
			if( finished )  // fade top screen
			{
				
				//s32 erp = PalInterp+16;
				//Fx2D::Instance()->Fade3D( 0, 0, 0 ,0, erp, 16 );
				
				int h = UTIL::Lerp( 0 << 12, 16 << 12, HeightInterp ) >> 12;
				h = UTIL::Clamp( h, 0, 12 );
						
				int col = UTIL::Lerp( 1 << 12, 31 << 12, 4096-PalInterp ) >> 12;
				col = UTIL::Clamp( col, 1, 31 );
				
				glColorTable( GL_RGB16, KromGLFontTexPal );
				glColor( RGB15(col,col,col) );
						
				KromGLFont.PrintSine( 32, 60,  "BUBBLE FIGHT", 0, h, 4, frame << 8 );
				
				KromGLFont.PrintSineVertical( 120, 40,  "E X", 2, 8, 3, frame << 9 );
				
				glColorTable( GL_RGB16, BubblaGLFontTexPal );
				BubblaGLFont.PrintCentered(0,0, "RELMINATOR PRESENTS");
				BubblaGLFont.PrintCentered(0,8, "HTTP://REL.BETTERWEBBER.COM");
				
				BubblaGLFont.PrintCentered(0,105, "PRODUCER");
				BubblaGLFont.PrintCentered(0,117, "ANYA THERESE B. LOPE");
				BubblaGLFont.PrintCentered(0,140, "SPONSORS");
				BubblaGLFont.PrintCentered(0,152, "NINTENDOMAX:DEVKITPRO");
				BubblaGLFont.PrintCentered(0,162, "EASY GL2D:LIBNDS:MAXMOD");
				
				glColorTable( GL_RGB16, KromGLFontTexPal );
				KromGLFont.PrintCentered(0,176, "W34P0NZ R 4 K1DZ");
				
				
			}	
		// end 2D rendering mode
        glEnd2D();
		
		glFlush(0); 
		swiWaitForVBlank();
		
		BubblaFont.Clear(); // deactivate every oam per frame
		KromFont.Clear(); // deactivate every oam per frame
		
		
		
		Fx2D::Instance()->CyclePlasmaPal();
		
		
		KromFont.PrintCentered(0, 20, "CODE::DESIGN");
		BubblaFont.PrintCentered(0, 40, "RELMINATOR");
		
		KromFont.PrintCentered(0, 60, "FONTS");
		BubblaFont.PrintCentered(0, 80, "MARC RUSSELL");
		
		KromFont.PrintCentered(0, 100, "SPECIAL THANKS");
		BubblaFont.PrintCentered(0, 120, "WINTERMUTE");
		BubblaFont.PrintCentered(0, 120+8, "ZEROMUS");
		BubblaFont.PrintCentered(0, 120+16, "CEARN");
		BubblaFont.PrintCentered(0, 120+24, "DHEART");
		BubblaFont.PrintCentered(0, 120+32, "DR.D");
		BubblaFont.PrintCentered(0, 120+40, "HELLFIRE");
		
		
		KromFont.PrintSineVertical( 10, 0,  "BUBBLE", 2, 8, 3, frame << 9 );
		KromFont.PrintSineVertical( 255-10-16, 0,  "FIGHT", 2, 8, 3, -frame << 9 );
		KromFont.PrintSine( 128-26, 191-16,  "E X", 2, 8, 3, frame << 9 );

		
		oamUpdate(&oamSub);

		if( !finished )	// fade to plasma from walar
		{
			Fx2D::Instance()->Fade( BG_PALETTE_SUB,
									Palettes::Instance()->GetBlack(),
									Fx2D::Instance()->GetPlasmaPal(),
									PalInterp,
									32,
									512
								  );
			
			Fx2D::Instance()->Fade( SPRITE_PALETTE_SUB,
									Palettes::Instance()->GetBlack(),
									font_bubblaPal,
									PalInterp,
									32,
									512
								  );
		}
		else	// fade sub BG on exit
		{
			Fx2D::Instance()->Fade( BG_PALETTE_SUB,
									Fx2D::Instance()->GetPlasmaPal(),
									Palettes::Instance()->GetBlack(),
									PalInterp,
									16,
									512
								  );

			Fx2D::Instance()->Fade( SPRITE_PALETTE_SUB,
									font_bubblaPal,
									Palettes::Instance()->GetBlack(),
									PalInterp,
									16,
									512
								  );
			
		}
				
	} // loop
	

}
	

void Engine::DoEnding()
{

	const int MAX_TEXT = 19;
	
	const int START_FADE_OUT = 64 * 16;
	const int DONE = 64 * 20;
	
	const char *Text[] =
	{ 
		"KANGEKI!",
		" ",
		"OGAMOTO!",
		" ",
		"NIKUI NIKUI!",
		" ",
		"FANTASTIC",
		"BUBBLE BURSTING!",
		" ",
		"HOWEVER,",
		"YOUR BURSTING",
		"ADVENTURES ISN'T",
		"OVER YET.",
		" ",
		"SEE YOU IN...",
		" ",
		" ",
		"GRADIUS",
		"DS"
		
	};
	
	u8 *Plaz = Fx2D::Instance()->PlasmaTrans();
	dmaCopy( Plaz, bgGetGfxPtr(SubBG3), SCREEN_WIDTH * SCREEN_HEIGHT );
	
	Sound::Instance()->SetMasterVolume( 512 );
	Sound::Instance()->PlayBGM( E_BGM_ENDING, MM_PLAY_LOOP );
	
	s32 SoundInterp = 1 << 12;
	bool finished = false;
	int frame= 0 ;
	s32 PalInterp = 0;
	int Scroll_X = SCREEN_HEIGHT;
	while( !finished )
	{
		
	
		frame++;
		if( frame > DONE ) finished = true;
		
		if( (frame & 1) == 0) Scroll_X--;
		
		Fx3D::Instance()->UpdateStars();		
		Fx3D::Instance()->DrawParts();
		
		
		
		if( frame < START_FADE_OUT )
		{
			
			

			// white to pal fade sub BG
			Fx2D::Instance()->Fade( BG_PALETTE_SUB,
									Palettes::Instance()->GetBlack(),
									Fx2D::Instance()->GetPlasmaPal(),
									PalInterp,
									32,
									512
								  );
			
		}
		else
		{
		
			
			// fade to black
			if( frame == START_FADE_OUT )
				PalInterp = 0;
			
			// fade to black sub BG
			Fx2D::Instance()->Fade( BG_PALETTE_SUB,
									Fx2D::Instance()->GetPlasmaPal(),
									Palettes::Instance()->GetBlack(),
									PalInterp,
									32,
									512
								  );
		
			Sound::Instance()->FadeBGM( SoundInterp,-32 );
		}
	
		glBegin2D();
			
			int Row = Scroll_X;
			for( int i = 0; i < MAX_TEXT; i++ )
			{
				//if ( ( i < 5) || (i > 16) )
				//{
					glColorTable(GL_RGB16, KromGLFontTexPal);
					glColor( RGB15(31,31,31) );
					KromGLFont.PrintCentered( 00, Row, Text[i] );
					Row += 16;
				//}
				//else
				//{
				//	glColorTable(GL_RGB16, BubblaGLFontTexPal);
				//	glColor( RGB15(31,31,31) );
				//	BubblaGLFont.PrintCentered( 00, Row, Text[i] );
				//	Row += 8;
				//}
			}
			
		// end 2D rendering mode
        glEnd2D();
		
		glFlush(0); 
		swiWaitForVBlank();
		
		BubblaFont.Clear(); // deactivate every oam per frame
		KromFont.Clear(); // deactivate every oam per frame
		
		
		Fx2D::Instance()->CyclePlasmaPal();
		
		KromFont.PrintCentered(0, 20, "CONGRATULATIONS!");
		
		KromFont.PrintCentered(0, 60, "ANG GALING MO");
		KromFont.PrintCentered(0, 80, "PARE!");
		
		KromFont.PrintCentered(0, 120, "THANKS");
		BubblaFont.PrintCentered(0, 140, "VGMUSIC");
		BubblaFont.PrintCentered(0, 140+8, "ADIGUN POLACK");
		BubblaFont.PrintCentered(0, 140+16, "DBF");
		BubblaFont.PrintCentered(0, 140+24, "FREEBASIC");
		BubblaFont.PrintCentered(0, 140+32, "GBADEV");
		BubblaFont.PrintCentered(0, 140+40, "ROSE LOPE");

	oamUpdate(&oamSub);
		
	}
	
	Plaz = Fx2D::Instance()->PlasmaTrans2();
	dmaCopy( Plaz, bgGetGfxPtr(SubBG3), SCREEN_WIDTH * SCREEN_HEIGHT );
	
		
}
	
void Engine::DoSplash()
{
	
	
	
	const int START_FADE_OUT = 64 * 8;
	const int DONE = 64 * 12;
	
	dmaCopy( walar1bBitmap, bgGetGfxPtr(SubBG3), SCREEN_WIDTH * SCREEN_HEIGHT );
	
	// Main splash
	// Load and save to copy later
	int WalarTextureID = glLoadTileSet( Walar1a,		// pointer to glImage array
				   256,				// sprite width
				   192,				// sprite height
				   256,				// bitmap image width
				   192,				// bitmap image height
				   GL_RGB16,		// texture type for glTexImage2D() in videoGL.h
				   TEXTURE_SIZE_256,	// sizeX for glTexImage2D() in videoGL.h
				   TEXTURE_SIZE_256,	// sizeY for glTexImage2D() in videoGL.h
				   TEXGEN_OFF,
				   (u8*)walar1aBitmap // image data generated by GRIT
				 );
	
	
	// copy walar texture to walar2
	// saves Vram
	// For the top screen Outro
	int i=0;
	// init sprites texture coords and texture ID
	for( int y = 0; y < (192/16); y++ )
	{
		for( int x = 0; x < (256/16); x++ ) 
		{
			WalarTiles[i].width 			= 16;
			WalarTiles[i].height 			= 16;
			WalarTiles[i].u_off				= x*16;
			WalarTiles[i].v_off				= y*16; 
			WalarTiles[i].textureID 		= WalarTextureID;
			i++;
		}
	}

	
	int Walar1aTexPal = gluTexLoadPal( walar1aPal, walar1aPalLen, GL_RGB16 );
    
	
	bool finished = false;
	int frame= 0 ;
	s32 PalInterp = 0;
	while( !finished )
	{
		
	
		frame++;
		if( frame > DONE ) finished = true;
		
		Fx3D::Instance()->UpdateStars();
		
		if( frame > START_FADE_OUT )
			Fx3D::Instance()->DrawParts();
		
		
		glBegin2D();

			if( frame < START_FADE_OUT )
			{
				
				
				Fx2D::Instance()->AnimateSplashIn( Walar1aTexPal, Walar1a );

				// white to pal fade sub BG
				Fx2D::Instance()->Fade( BG_PALETTE_SUB,
										Palettes::Instance()->GetWhite(),
										walar1bPal,
										PalInterp,
										32,
										512
									  );
				
			}
			else
			{
			
				Fx2D::Instance()->AnimateSplashOut( Walar1aTexPal, WalarTiles );
				
				// fade to black
				if( frame == START_FADE_OUT )
					PalInterp = 0;
				
				// fade to black sub BG
				Fx2D::Instance()->Fade( BG_PALETTE_SUB,
										walar1bPal,
										Palettes::Instance()->GetBlack(),
										PalInterp,
										32,
										512
									  );
			
			}
		
		// end 2D rendering mode
        glEnd2D();
		
		glFlush(0); 
		swiWaitForVBlank();
		
	}
	
}


void Engine::DrawDebug( int frames, 
						int Stage,
						int StageFinished,
						const StarFighter &Star,
						std::vector<EntityContainer*> en
					  )
{
	
	const char *EnemyNames[] =
	{ 
		"CENTIPEDES = ",
		"SPARKIES   = ",
		"ROTOSPARKS = ",
		"METROIDS   = ",
		"CANCERS    = ",
		"BLOBS      = ",
		"POPCORNS   = ",
		"TENTAKILLS = "
	};

	// calculate the amount of 
	// memory uploaded to VRAM in KB
	int TextureSize = star_spriteBitmapLen +
					  cancer_spriteBitmapLen +
					  metroid_spriteBitmapLen +
					  blob_spriteBitmapLen +
					  sparky_spriteBitmapLen +
					  centipede_spriteBitmapLen +
					  stage01bgBitmapLen +
					  stage02bgBitmapLen +
					  organBitmapLen +
					  xmasballsBitmapLen +
					  muscleBitmapLen +
					  glfont_bubblaBitmapLen +
					  glfont_kromBitmapLen +
					  walar1aBitmapLen +
					  explosions_spriteBitmapLen +
					  small_enemies_spriteBitmapLen +
					  moai_spriteBitmapLen +
					  circlesaw_spriteBitmapLen +
					  bouncer_spriteBitmapLen +
					  tentakill_spriteBitmapLen;
	
	glColorTable(GL_RGB16, BubblaGLFontTexPal);
	glColor( RGB15(31,31,31) );
			
	BubblaGLFont.Print( 00, 20, "FRAMES = ", frames );				  
	BubblaGLFont.Print( 00, 30, "TOTAL TEXTURE SIZE(KB) = ", TextureSize / 1024 );				  
	BubblaGLFont.Print( 00, 40, "RAM LEFT = ", mallinfo().uordblks );				  
	
	int i = 0;
	std::vector<EntityContainer*>::iterator iter;
	for( iter = en.begin(); iter != en.end(); ++iter )
	{
		BubblaGLFont.Print( 00, 50+(i*10), EnemyNames[i], (*iter)->NumEntities() );				  
	
		i++;
	}
	
	
	BubblaGLFont.Print( 00, 160, "IINVINCIBLE = ", Star.IsInvincible() );				  
	BubblaGLFont.Print( 00, 170, "STAGE = ", Stage );				  
	BubblaGLFont.Print( 00, 180, "STAGEDONE = ", StageFinished );				  
	
}
	
	
void Engine::KillAllEnemies( std::vector<EntityContainer*> Enemies,
						     BossEntity *&Boss
						   )

{
   
	//std::vector<BossEntity*> Boss
	// update all enemy types
	std::vector<EntityContainer*>::iterator iter;
	for( iter = Enemies.begin(); iter != Enemies.end(); ++iter )
	{
		(*iter)->KillAllEntities();
	}

	Boss->SetActive(false);
	Boss->SetAlive(false);
	Boss->SetX(600 << 12);
	Boss->SetY(96 << 12);
	
}



//------------------------------------------------------------------------------
//	Internal Private functions
//------------------------------------------------------------------------------

void SpawnRandomSparks( int Frame )
{
	static int EnemyType = 0;
	
	if( (Frame & 127) == 0 )
	{
		EnemyType = (EnemyType + 1) & 1;
		switch( EnemyType )
		{
			case 0:
				Sparkies.Spawn( 300, qran_range(16, 192-16) );
				break;
			case 1:
				RotoSparks.Spawn( 300, qran_range(16, 192-16), 
								  qran_range(0, 256) > 128 
								);
				break;
			default:
				Sparkies.Spawn( 300, qran_range(16, 192-16) );
				
		}
		
	}
	
}


//--------------------------------------
//	
//--------------------------------------
void SpawnRandomBlobs( int Frame )
{
	
	if( (Frame & 255) == 0 )
	{
		Blobs.Spawn( 300, qran_range(16, 192-16),
					-qran_range( 512, 1024 ),
					qran_range(15, 50)
				  );
	
	}
	
}

//--------------------------------------
//	
//--------------------------------------
void SpawnRandomCancers( int Frame )
{
	
	if( (Frame & 127) == 0 )
	{
		Cancers.Spawn( 300, qran_range(16, 192-16) );
					
	}
	
}

//--------------------------------------
//	
//--------------------------------------
void SpawnRandomCentipedes( int Frame )
{
	
	if( (Frame & 511) == 0 )
	{
		Centipedes.Spawn( 300, 96 );
	}
	
}

//--------------------------------------
//	
//--------------------------------------
void SpawnRandomMetroids( int Frame )
{
	
	if( (Frame & 127) == 0 )
	{
		Metroids.Spawn( 300, qran_range(16, 192-16),
						-qran_range( 1024, 2048 ),
						qran_range(10, 50)
					  );
		
	}
	
}

//--------------------------------------
//	
//--------------------------------------
void SpawnRandomPopcorns( int Frame )
{
	
	if( (Frame & 255) == 0 )
	{
		Popcorns.Spawn( 300, qran_range(16, 192-16),
					   -qran_range( 512, 1024 ),
						qran_range(25, 50)
					  );
		
	}
	
}

//--------------------------------------
//	
//--------------------------------------
void SpawnRandomTentakills( int Frame )
{
	
	if( (Frame & 255) == 0 )
	{
		Tentakills.Spawn( 320, qran_range(16, 192-16),
						 -qran_range( 512, 2048 ),
						  qran_range(10, 50), 
						  qran() 
						);
		
	}
	
}


