Easy GL2D DS

User's Guide

Official Site
Http://Rel.Phatcode.Net 

Email
vic_viperph(at)yahoo.com

Introduction


    Easy GL2D is a very small, very fast, yet easy to use hardware abstraction layer for 2D graphics rendering.  Easy GL2D uses the DS' 3D hardware to render in 2D mode.  

Reasons to use Easy GL2D:


Limitations:




Installation:

1 . Copy the distributable/libnds folder to your devkitPro directory.
    or you can copy the /include and /lib folders under the /libnds directory of devkitPro.
    ie.
    *Assuming you installed devkitPro in c:/devkitPro/
   
    c:/devkitPro/libnds/include/gl2d.h  
    c:/devkitPro/libnds/lib/libgl2d.a


2.  Edit this line in your makefile and add gl2d before libnds
    ie.
    LIBS    := -lnds9

    to

    LIBS    := -lgl2d -lnds9

4. Add #include <gl2d.h> to your source.
5. Done! You can now use Easy GL2D.



Getting Started



Notice:


    Easy GL2D DS is always qualified with the word "easy" because it is extremely easy to use it hurts. Anybody who have used the OAM to render their sprites knows all too well how cumbersome it is to manage.  Plus the fact that your limited to just 128 sprites per frame means bullet-hell games cannot be made using the OAM as a rendering context. Bullet-Hell is my middle name.

    Assuming you have successfully installed Easy GL2D, a minimal easy GL2D application should look like this:

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

int main( void )
{
   // Set it to my favorite mode (Any mode that supports 3D should work)
    videoSetMode( MODE_5_3D );
   
     
    // Initialize GL2D
    glScreen2D();
   

    while( 1 )
    {

        // set up GL2D for 2d mode
        glBegin2D();

        // call Easy GL2D's 2D rendering functions here

        // end 2D rendering mode
        glEnd2D();
   
        glFlush(0);                    
        swiWaitForVBlank();
   
    }
   
   
}


    The above code shows how easy it is to use Easy GL2D. First thing to do  is set a video mode that supports 3D, initialize GL2D and call your 2D code in between glBegin2D()  and glEnd2D().  What could be easier than that?


Rendering Primitives


    Easy GL2D supports redering some of the most basic 2D primitives.  They are listed below:
    * See the Easy GL2D Programmer'sRreference for more details...

void glPutPixel( int x, int y, int color );

void glLine( int x1, int y1, int x2, int y2, int color );

void glBox( int x1, int y1, int x2, int y2, int color );

void glBoxFilled( int x1, int y1, int x2, int y2, int color );

void glBoxFilledGradient( int x1, int y1, int x2, int y2,
                          int color1, int color2, int color3, int color4
                        );

void glTriangle( int x1, int y1, int x2, int y2, int x3, int y3, int color );

void glTriangleFilled( int x1, int y1, int x2, int y2, int x3, int y3, int color );

void glTriangleFilledGradient( int x1, int y1, int x2, int y2, int x3, int y3,
                               int color1, int color2, int color3
                             );
 
You can use direct scalar values to pass colors or use libnds' internal macros RGB15() and ARGB16().

Here's an example that draws some of the above primitives...


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

// Binary Radian PI cosLerp() and sinLerp()
// Expects to be used
#define BRAD_PI (1 << 14)

int main( void )
{
   // Set it to my favorite mode (Any mode that supports 3D should work)
    videoSetMode( MODE_5_3D );
  
    
    // Initialize GL2D
    glScreen2D();
  

    while( 1 )
    {

        // set up GL2D for 2d mode
        glBegin2D();

        
        // call Easy GL2D's 2D rendering functions here

        // Draw some primitives
        
        // fill the whole screen with a gradient box
        glBoxFilledGradient( 0, 0, 255, 191,
                             RGB15(  0, 31,  0 ),
                             RGB15( 31,  0,  0 ),
                             RGB15(  0,  0, 31 ),
                             RGB15( 31, 31, 31 )
                           );
        
        // draw a black box on the right
        glBoxFilled( 200, 10,
                     250, 180,
                     RGB15(0,0,0)
                    );
        
        // draw a border around the black box
        glBox( 200, 10,
               250, 180,
               RGB15(0,31,0)
             );
        
        
        // draw a triangle
        glTriangle(  20, 100,
                    200,  30,
                     60,  40,
                    RGB15(31,0,31)
                   );
   
        // Draw some lines from the center
        // with a radius of 20
        int i;
        int radius = 60;
        for( i = 0; i < BRAD_PI * 2; i += 1024 )
        {
            int x = cosLerp(i) * radius;
            int y = sinLerp(i) * radius;
            // since sinLerp and cosLerp returns
            // a 20.12 fixed point value
            // we need to convert the results back
            // to standard integers
            x = f32toint(x);     // same as x >> 12
            y = f32toint(y);
            
            // draw the lines radiating from the center
            glLine( 128, 96, 128 + x, 96 + y, RGB15(20,15,31) );
 
 
        }
        // draw a gradient triangle in
        // translucent mode with
        // Poly ID 1
        // POLY_ALPHA(16) controls how translucent
        // the current polygon is. 8/31
        glPolyFmt(POLY_ALPHA(8) | POLY_CULL_NONE | POLY_ID(1));
        glTriangleFilledGradient(  30, 10,
                                  200, 80,
                                  60, 140,
                                  RGB15(31,0,0),
                                  RGB15(0,31,31),
                                  RGB15(31,0,31)
                                );
        
        // end 2D rendering mode
        glEnd2D();
  
        glFlush(0);                   
        swiWaitForVBlank();
  
    }
  
  
}
Screenshot:
sandbox

The above shows how to draw some primitives.  It also shows how to do translucency on a per-polygon basis.


Sprites



Easy GL2D supports a plethora of  sprite rendering and loading functions:
* See the Easy GL2D Programmer'sRreference for more details...

Rendering Functions:

void glSprite( int x, int y, int flipmode, const glImage *spr );

void glSpriteScale( int x, int y, s32 scale, int flipmode, const glImage *spr );

void glSpriteScaleXY( int x, int y, s32 scaleX, s32 scaleY, int flipmode, const glImage *spr );

void glSpriteRotate( int x, int y, s32 angle, int flipmode, const glImage *spr );

void glSpriteRotateScale( int x, int y, s32 angle, s32 scale, int flipmode, const glImage *spr);

void glSpriteRotateScaleXY( int x, int y, s32 angle, s32 scaleX, s32 scaleY, int flipmode, const glImage *spr);

void glSpriteStretchHorizontal(int x, int y, int length_x, const glImage *spr );

void glSpriteOnQuad( int x1, int y1,
                     int x2, int y2,
                     int x3, int y3,
                     int x4, int y4,
                     int flipmode, const glImage *spr
                   );


Loading Functions:

int glLoadSpriteSet( glImage              *sprite,
                     const unsigned int   numframes,
                     const unsigned int   *texcoords,
                     GL_TEXTURE_TYPE_ENUM type,
                     int                   sizeX,
                     int                   sizeY,
                     int                   param,
                     const uint8          *texture     
                   );

int glLoadTileSet( glImage              *sprite,
                   int                  tile_wid,
                   int                  tile_hei,
                   int                  bmp_wid,
                   int                  bmp_hei,
                   GL_TEXTURE_TYPE_ENUM type,
                   int                     sizeX,
                   int                     sizeY,
                   int                     param,
                   const uint8          *texture     
                 );


    Sprites are the bread an butter of just about every DS game.  With Easy GL2D, blitting sprites on screen is as easy as drawing primitives. Let me give you a very simple example.
 
I'm gonna use Patater's shuttle sprite in this example.

Here's the shuttle.grit file expected by GRIT.

    # Set the warning/log level to 3
    -W3


    #bitmap mode
    -gb


    # Set the bit depth to 4 (16 colors)
    -gB4


    #include pal
    -p


shuttle.bmp specifications:
        Bitdepth = 4 bits per pixel (16 colors)
    Width = 64 pixels
    Height = 64 Pixels

* We put the files shuttle.bmp and shuttle.grit inside the /gfx folder


Fire up Programmer's Notepad(or any editor of your choice) and start typing this:


/******************************************************************************
*******************************************************************************
    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:
    Patater (Jaeden Amero) for the shuttle sprites
*******************************************************************************
******************************************************************************/
#include <nds.h>
#include <stdio.h>
#include <gl2d.h>
// GRIT auto-generated header
// can be found inside the /build directory
#include "shuttle.h"
int main( void )
{
    // Instantiate a glImage object
    glImage  Shuttle[1];  // only a single sprite for now
    
    
    // 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. (enough for our needs)
    // since the sprite we're using is just
    // 2 kb
    vramSetBankA( VRAM_A_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 single image
    // sprite.
    // Note that glLoadTileset can also
    // load single images.
    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 16 colors
                   TEXTURE_SIZE_64,    // sizeX for glTexImage2D() in videoGL.h
                   TEXTURE_SIZE_64,    // sizeY for glTexImage2D() in videoGL.h
                                    // Set texture params setting color 0 as transparent
                   GL_TEXTURE_WRAP_S|GL_TEXTURE_WRAP_T|TEXGEN_OFF|GL_TEXTURE_COLOR0_TRANSPARENT,
                   256,                    // Length of the palette to use (256 colors)
                   (u16*)shuttlePal,    // Load our 16 color shuttle palette
                    (u8*)shuttleBitmap  // image data generated by GRIT
                 );
    
    // 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 Patater");
    
    
    // calculate the amount of
    // memory uploaded to VRAM in KB
    int TextureSize = shuttleBitmapLen;
                      
                      
    iprintf("\x1b[15;1HTotal Texture size= %i kb", TextureSize / 1024);
    
    int frame = 0;
    
    while( 1 )
    {
    
        frame++;
        
        // set up GL2D for 2d mode
        glBegin2D();
        
            // call Easy GL2D's 2D rendering functions here
            // Draw some primitives
            
            // fill the whole screen with a gradient box
            glBoxFilledGradient( 0, 0, 255, 191,
                                 RGB15(  0, 31,  0 ),
                                 RGB15( 31,  0,  0 ),
                                 RGB15(  0,  0, 31 ),
                                 RGB15( 31, 31, 31 )
                               );
            
            // draw a row of sprites in different flipping
            // modes
            glSprite( 64* 0, 0, GL_FLIP_NONE, Shuttle );
            glSprite( 64* 1, 0, GL_FLIP_V, Shuttle );
            glSpriteScale( 64* 2, 0, floattof32(0.6),GL_FLIP_H, Shuttle );
            glSpriteScaleXY( 64* 3, 0, floattof32(1.2), floattof32(1.6), GL_FLIP_V | GL_FLIP_H, Shuttle );
            
            // draw a row of sprites in colored modes
            glColor( RGB15(31,0,0) );
            glSprite( 64* 0, 64, GL_FLIP_NONE, Shuttle );
            
            glColor( RGB15(0,31,0) );
            glSprite( 64* 1, 64, GL_FLIP_V, Shuttle );
            
            // make the last two sprites translucent
            // giving them a unique Polygon ID for translucency
            // to work.
            glPolyFmt(POLY_ALPHA(16) | POLY_CULL_NONE | POLY_ID(1));
            glColor( RGB15(16,31,0) );
            glSprite( 64* 2, 64, GL_FLIP_H, Shuttle );
            
            glColor( RGB15(0,0,0) );
            glSprite( 64* 3, 64, GL_FLIP_V | GL_FLIP_H, Shuttle );
            // Go back to normal mode
            // POLY_ALPHA(31) is none translucent
            // Again, give it another poly ID
            glPolyFmt(POLY_ALPHA(31) | POLY_CULL_NONE | POLY_ID(2));
            
            // Also restore color to normal
            glColor( RGB15(31,31,31) );
            glSpriteRotate( 64 * 0 + 32, 128 + 32, frame * 40, GL_FLIP_NONE, Shuttle );
            
            // Scale by Sinlerp
            int scale = sinLerp(frame*60);
            glSpriteRotateScale( 64 * 1 + 32, 128 + 32, -frame * 40, scale, GL_FLIP_NONE, Shuttle );
            // Independently scale the 3rd image
            int scaleX = sinLerp(frame*90);
            int scaleY = sinLerp(frame*30);
            glSpriteRotateScaleXY( 64 * 2 + 32, 128 + 32, frame * 100, scaleX, scaleY,
                                   GL_FLIP_NONE, Shuttle
                                 );
            // reverse scale the 4th image,
            // make it translucent and
            // do some coloring
            glColor( RGB15(0,31,0) );
            glPolyFmt(POLY_ALPHA(16) | POLY_CULL_NONE | POLY_ID(3));
            glSpriteRotateScaleXY( 64 * 3 + 32, 128 + 32, -frame * 200, scaleX, scaleY,
                                   GL_FLIP_NONE, Shuttle
                                 );
        // end 2D rendering mode
        glEnd2D();
   
        glFlush(0);                    
        swiWaitForVBlank();
   
    }
   
   
}

Screenshot:
simplesprites

* I've commented the source as much as I can so it should be self-explanatory. Things to note are:

 


Spritesets and Tilesets


    So far we have been using only a single image per sprite.  Easy GL2D also supports arrays of sprites via Spritesets or tilesets. Both could draw non-power of  2 images and they are rendered with the same calls.  The difference between the two is that:


Tileset image:
tileset

Spriteset image:
spriteset

    Since tilsesets are fixed-sized images, we don't need to do too much to load them.  We use use glLoadTileset() and call it a day.  It's not so easy with Spritesets as you would have to manually calculate each image's location and size within the Spriteset to upload them to our glImage structure.  However, I have made a tool called "Texture packer" to  automate the process (much like how GRIT automates the image conversion for your sprites).  Using my texture packer would essentially make Spritesets as easy to handle as Tilesets.  It also makes your code safer and easier to refactor later.

Rel's texture Packer

 
Mini tutorial on how to use the texture packer

  1. First you need to download and extract it.
  2. Then put a bunch of tiles inside the “images/” folder.
  3. Double-click “launcher.exe”
  4. Set up parameters.
  5. Go!
  6. Check out the “textures/” folder


Assuming you have these tiles inside the images folder (note that the names don't matter the indices would be arranged alphabetically in the final texture)…
Images for texture packing


When you click the launcher...

Launcher Image



    I set it up to have a name of “enemies”, Width = 256, Height = 256 pixels and 8 BPP. My texture packer only supports 8 and 32 bits but you can convert the resulting texture into any bitdepth of your choice using your favorite photo editor.

After pressing “Go!” you will have these files at the “texture/” folder…

  1.  “uvcoord_enemies.h”
  2.  “enemies.bmp” - I converted this to PNG using a photo editor to show you that external editors can also be useful.
packed enemies
    These 2 files are what we're gonna use to load our Spriteset into our DS application. Enemies.bmp is the actual spriteset and uvcoord is the texture atlas that references where a particular sprite can be found.

* There are other files the application spits out but they are not important.
  1. "enemies_idx_[h].bmp" - are helper images so that you will know the index of a particular sprite for use with glSpriteXXXX() functions.enemies packed with index
  2. “uvcoord_enemies.bi” and “uvcoord_enemies.txt” - are files to be used by other languages aside from C/C++.


* You will also notice that the texture packer rearranges the images inside the texture atlas.  It does that to find the smallest possible area that can be occupied by the sprite.  Doing that reduces the amount of DS VRAM our application would use. 


Before we start coding let me show you the sprites were gonna use for this demo.



Instructions:

1.  Put all this images,  along with their *.grit counterparts inside the /gfx folder
     * We will also include all the palettes (by using the -p GRIT switch) of the palettized images since they have different palettes.
2.  Put "uvcoord_enemies.h' in your source folder.
     Edit this line if you are coding in C (CPP users need not do this)
        extern const unsigned int enemies_texcoords[] = {
        to
        const unsigned int enemies_texcoords[] = {


Now that you have done some Images, GRIT and  Texture Packer related stuff, we are ready to go back to coding.

Again fire up Programmer's Notepad(or any editor of your choice) and start typing this:

/******************************************************************************
*******************************************************************************
    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] );
        }
    }
    
    
}


Screenshot:
sprites

As you can see, Easy GL2D can do very complex rendering with very little effort on the programmer.

Things to note in the above demo:


 


Miscellaneous Stuff


1.  You can use the actual glImage struct to extract the images dimensions for collision detection.
     ie:
    glImage Anya;
    // do some loading ghere
    w = Anya.width;
    h = Anya.height;

2. You can draw to both screens at once by using the DS' video capture registers. See the GL2D  example "dual_screen.nds"

3. Try to limit texture use by reusing the same images with different palettes. I know lots of games do this.

4. See the example files,  the source are well commented and they can teach you more than this user's guide can.

5. The lib as far as I'm concerned is more than fast enough for a bullet-hell game.  Which means, it should be fast enough for any 2D genre.  Want to see it in action?  
        Space Impakto DS     This game could put enough bullets on screen it's not funny at all.
        Bubble Fight EX         This completed game is a showcase of Easy GL2D's capabilities.

EOF