/******************************************************************************
*******************************************************************************
	Easy GL2D 
	Sprites example
	Shows a some sprite capabilities of easy GL2D
	
	Relminator (Richard Eric M. Lope BSN RN)
	Http://Rel.Phatcode.Net
	
	Thanks to:
	Anya Therese B. Lope for letting me use her picture
	Adigun A. Polack for the enemies sprites
	Patater (Jaeden Amero) for the shuttle sprites
	capcom for Zero's image

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

#include <nds.h>
#include <stdio.h>
#include <gl2d.h>


// GRIT auto-generated header
// can be found inside the /build directory
#include "enemies.h"
#include "tiles.h"
#include "shuttle.h"
#include "anya.h"


// Texture Packer auto-generated UV coords
#include "uvcoord_enemies.h"


// Declare our BG drawing routine
void DrawBG( glImage *images );


// I declare my glImage[] arrays globally here
// but you should use either malloc() or new[] to 
// dynamically instantiate the arrays

// This imagesets would use our texture packer generated coords so it's kinda
// safe and easy to use 
// ENEMIES_NUM_IMAGES is a value from "uvcoord_crono.h"
glImage  Enemies[ENEMIES_NUM_IMAGES];	// spriteset

// This tileset won't make use of our texture packer generated coords.
// Messy, manual and prone to errors.
// BMP is 256x256 and tiles are 16x16 so.. (256/16) * (256 /16) = 16 * 16
glImage  Tiles[(256/16) * (256/16)];  

// These sprites are single texture only so no need to
// do anything special
glImage  Shuttle[1];					// single image	
glImage  Anya[1];



int main( void )
{

	
    // Set it to my favorite mode (Any mode that supports 3D should work)
    videoSetMode( MODE_5_3D );
   

	// Init console so that we could
	// print some stuff
	consoleDemoInit();
	
	// Set up enough texture memory for our textures
	// Bank A is 128kb. Not enough(we are using 164 kb) so we also map
	// Vram B to texture
	vramSetBankA( VRAM_A_TEXTURE );     
	vramSetBankB( VRAM_B_TEXTURE );

    // Very important or you'll get black textures
	vramSetBankE(VRAM_E_TEX_PALETTE);  // Allocate VRAM bank for all the palettes
	
	
	// Initialize GL2D
    glScreen2D();
   
	
	// Load our Enemies texture
	// We used glLoadSpriteSet since the texture was made
	// with my texture packer.
	int EnemiesTextureID = 
		glLoadSpriteSet( Enemies,				// pointer to glImage array
						 ENEMIES_NUM_IMAGES, 	// Texture packer auto-generated #define
						 enemies_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_256,		// sizeY for glTexImage2D() in videoGL.h
						 GL_TEXTURE_WRAP_S|GL_TEXTURE_WRAP_T|TEXGEN_OFF|GL_TEXTURE_COLOR0_TRANSPARENT, // param for glTexImage2D() in videoGL.h
						 256,					// Length of the palette to use (256 colors)
						 (u16*)enemiesPal,		// Load our 256 color enemies palette
					     (u8*)enemiesBitmap	 	// image data generated by GRIT
					   );
	
	
	
	// Our texture handle for our tiles
	// I used glLoadTileSet since the texture 
	// is just a bunch of 16x16 tiles in a 256x256
	// tileset so we don't need a texture packer for this.
	int TilesTextureID = 
		glLoadTileSet( Tiles,				// pointer to glImage array
					   16,					// sprite width
					   16,					// sprite height
					   256,					// bitmap width
					   256,					// bitmap height
					   GL_RGB256,			// 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
					   GL_TEXTURE_WRAP_S|GL_TEXTURE_WRAP_T|TEXGEN_OFF|GL_TEXTURE_COLOR0_TRANSPARENT, // param for glTexImage2D() in videoGL.h
					   256,					// Length of the palette to use (256 colors)
					   (u16*)tilesPal,		// Load our 256 color tiles palette
					   (u8*)tilesBitmap		// image data generated by GRIT
					 );
	
	
	// Shuttle
	// Since the shuttle is just a single 64x64 image,
	// We use glLoadTileSet() giving the right dimensions.
	int ShuttleTextureID = 
		glLoadTileSet( Shuttle,			// pointer to glImage array
					   64,				// sprite width
					   64,				// sprite height
					   64,				// bitmap image width
					   64,				// bitmap image height
					   GL_RGB16,		// texture type for glTexImage2D() in videoGL.h
					   TEXTURE_SIZE_64,	// sizeX for glTexImage2D() in videoGL.h
					   TEXTURE_SIZE_64,	// sizeY for glTexImage2D() in videoGL.h
					   GL_TEXTURE_WRAP_S|GL_TEXTURE_WRAP_T|TEXGEN_OFF|GL_TEXTURE_COLOR0_TRANSPARENT,
					   16,					// Length of the palette to use (16 colors)
					   (u16*)shuttlePal,	// Load our 16 color tiles palette
					   (u8*)shuttleBitmap  // image data generated by GRIT
					 );

	

	// Anya
	// This is a 16 bit image
	int AnyaTextureID = 
		glLoadTileSet( Anya,
					   128,
					   128,
					   128,
					   128,
					   GL_RGB,
					   TEXTURE_SIZE_128,
					   TEXTURE_SIZE_128,
					   GL_TEXTURE_WRAP_S|GL_TEXTURE_WRAP_T|TEXGEN_OFF,
					   0,    // Just use 0 if we don't want to use a palette
					   0,	 // Just use 0 if we don't want to use a palette
					   (u8*)anyaBitmap
					 );


	// print some stuff
	iprintf("\x1b[1;1HEasy GL2D Sprites Demo");
	iprintf("\x1b[2;1HRelminator");
	iprintf("\x1b[4;1HHttp://Rel.Phatcode.Net");
	
	iprintf("\x1b[6;1HA demo showing some sprite");
	iprintf("\x1b[7;1Hcapabilities of Easy GL2D");
	
	iprintf("\x1b[ 9;1HSprites by:");
	iprintf("\x1b[10;1HAdigun A. Polack, Patater,");
	iprintf("\x1b[11;1HCapcom and Anya Therese Lope");
	
	iprintf("\x1b[13;1HTextureIDs = %i, %i, %i, %i", 
			EnemiesTextureID,
			TilesTextureID,
			ShuttleTextureID,
			AnyaTextureID
		   );
	
	
	// calculate the amount of 
	// memory uploaded to VRAM in KB
	int TextureSize = enemiesBitmapLen +
					  tilesBitmapLen +
					  shuttleBitmapLen +
					  anyaBitmapLen;
					  
					  
	iprintf("\x1b[15;1HTotal Texture size= %i kb", TextureSize / 1024);
	
	
	int Frame = 0;				// frame counter
	int PhoenixFrame = 0;		// animation frame for our firebird
	int BeeFrame = 0;			// animation frame for the bee
	int ZeroFrame = 0;			// animation frame for zero
	
    while( 1 )
    {
	
		Frame++;
	
		// animate some of our animated sprites
		// every 8th frame
		if ( (Frame & 7) == 0 )
		{
			BeeFrame = (BeeFrame + 1) & 1;
			PhoenixFrame++;
			if (PhoenixFrame > 2) PhoenixFrame = 0;
			
		}

		// Faster zero animation
		// Every 4th frame
		if ( (Frame & 3) == 0 )
		{

			ZeroFrame++;
			if (ZeroFrame > 9) ZeroFrame = 0;
		}
		
        // set up GL2D for 2d mode
        glBegin2D();

		
			// call Easy GL2D's 2D rendering functions here
			
			// Draw out tiled BG
			DrawBG( Tiles );
			
			// Make the Anya's rotoscaled sprite translucent just for kicks
			// Use glSpriteRotateScaleXY() for some effect
			// Give it a unique polygon ID so that transluceny would work
			// No need to use glColorTable since "anya.bmp"
			// is not palettized.
			glPolyFmt(POLY_ALPHA(16) | POLY_CULL_NONE | POLY_ID(1));
			glSpriteRotateScaleXY( SCREEN_WIDTH/2, SCREEN_HEIGHT/2, Frame*140, sinLerp(Frame*120) * 3, sinLerp(Frame*210) * 2,  GL_FLIP_NONE, Anya );
			
			
			
			// Draw our enemies
			// Give  the them a different polygon ID
			// so that translucency works
			// Some phoenix enemies on the right
			// Note the flipmodes 
			// Also shows how we can draw in "color mode" and shadow mode
			// 36 + PhoenixFrame means that the base frame on our spriteset
			// see "enemies_idx.bmp" for details
			glPolyFmt(POLY_ALPHA(20) | POLY_CULL_NONE | POLY_ID(2));
			glSprite( 200, 0,  GL_FLIP_NONE,            &Enemies[36 + PhoenixFrame]);
			glColor ( RGB15(31,0,0) );
			glSprite( 200, 30,  GL_FLIP_H,              &Enemies[36 + PhoenixFrame]);
			glColor ( RGB15(0,31,20) );
			glSprite( 200, 60,  GL_FLIP_V,              &Enemies[36 + PhoenixFrame]);
			glColor ( RGB15(0,0,0) );
			glSprite( 200, 90,  GL_FLIP_V | GL_FLIP_H , &Enemies[36 + PhoenixFrame]);
			
			// restore color to normal and draw in opaque mode
			glColor( RGB15(31,31,31) );
			glPolyFmt(POLY_ALPHA(31) | POLY_CULL_NONE | POLY_ID(3));
			
			// draw zero
			// 23 is Zero's baseframe
			glSprite( 0, 0, GL_FLIP_NONE, &Enemies[23 + ZeroFrame] );
		
			// Draw a horizontally  flipped "disco" zero
			// Disco fex is done with glColor
			int color = (Frame*4) & 31;
			glColor( RGB15(color, 31-color, 16+color*2) );
			glSprite( 0, 42, GL_FLIP_H, &Enemies[23 + ZeroFrame] );
			
			// Normal color
			glColor( RGB15(31,31,31) );
			glSprite( 0, 84, GL_FLIP_V, &Enemies[23 + ZeroFrame] );
		
			// disco 
			glColor( RGB15(color, 31-color, 16+color*2) );
			glSprite( 0, 84+42, GL_FLIP_H | GL_FLIP_V, &Enemies[23 + ZeroFrame] );
			
			
			// Bee translucent and rotating
			glPolyFmt(POLY_ALPHA(16) | POLY_CULL_NONE | POLY_ID(4)); 
			glSpriteRotate( 64, 170, Frame * 120, GL_FLIP_NONE, &Enemies[12 + BeeFrame] );
			
			
			// restore translucency to opaque
			glPolyFmt(POLY_ALPHA(31) | POLY_CULL_NONE | POLY_ID(5));
			
			glSpriteRotate( 110, 170, -Frame * 120, GL_FLIP_NONE, &Enemies[12 + BeeFrame] );
			
			
			// restore color to normal
			glColor( RGB15(31,31,31) );
			
			
			// do the stretched shuttle
			glSpriteStretchHorizontal( 128, 135, 64 + (abs(sinLerp(Frame*100) * 100) >> 12), Shuttle );
			
		// end 2D rendering mode
        glEnd2D();
   
        glFlush(0);                    
        swiWaitForVBlank();
   
    }
   
   
}




// Draws the background
void DrawBG( glImage *images )
{

	int x, y, i;
	
	for( y = 0; y < 256 / 16; y++ )
	{
		for( x = 0; x < 256 / 16; x++ )
		{
			i = y * 16 + x;
			glSprite( x * 16, y * 16, GL_FLIP_NONE, &images[i & 255] );
		}
	}
	
	
}


