# 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:

- Works perfectly on a real DS
- Library size is very small (less than 10 kb)
- Very fast
- Can render more sprites than you can handle as opposed to the OAM's 128 sprites limit.
- Easy to maintain and refactor existing code
- Abstracted interface
- Code is easily portable to other platforms
- Can combine 2D and 3D seamlessly
- Almost unlimited palette usage in a single frame
- Can handle non-power of 2 sprites
- 3 types of translucency (2 via textures and 1 via polygon format)
- Lots of sprite effects (colors, alpha, rotation, scaling, shearing, etc.)
- Optimum VRAM use
- Paletted(almost limitless) and high-color mode can be used together.
- Can be used alongside existing libnds OpenGL functions seamlessly.

Limitations:

- Emulators are slower in emulating the 3d hardware than the OAM.
- glPutPixel, glLine and glBox only works on a real DS and No$GBA and not on deSmuMe.
- You still have to learn how to use the sub OAM and sub BG since this lib is main engine only. You can use the video capture to render on both screens but that would limit your FPS and would use valuable VRAM.

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:

- All the examples (source, images and binaries) can be found on the /docs/examples folder.
- glColorTable() has been deprecated since the release of libnds 1.5.0.
  Because of the it, stencil effects are not possible w/o some hacks so
  I just disabled it altogether. However, rendering sprites in any palette
  is a lot easier now since palettes are automatically managed by libnds.
- You also need to tell libnds what VRAM bank you want allocate for
  texture palettes. See the example files.
- There is also a zip file that contains all the examples for the lazy here: All Doc Examples

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:
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

- We should always use "-gb" for bitmap modes (never use tile modes) in Easy GL2D.
- The sprite is 16 color so we set the bitdepth to "gB4".
- We include the palette with the "-p" switch (not needed since it is the default).

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:
* I've commented the source as much as I can so it should be self-explanatory. Things to note are:

- #include "shuttle.h" includes a GRIT generated header.
- glImage Shuttle[1] instantiates our single image sprite localy and statically. You should however, use malloc() or new[] in a real engine to allocate arrays of glImage[] dynamically.
- Scaling and rotation accepts 20.12 values (1 = 4096).
- glLoadTileSet() can be used to load single images or a tileset.
- Never forget to call vramSetBank[x]() before uploading textures or you'll get an all-white texture.
- You can color a sprite with glcolor()
- Rotations are in libnds standard format.-32768 to 32767. I made it that way to be consistent with libnds.
- Scaling are also libnds standard format (f32 where (1 = 4096) . I made it that way to be consistent with libnds.

## 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:

- Tilesets are sets of smaller fixed-width and fixed-height images inside a single image.
- Spritesets are sets of smaller variable-width and variable-height images inside a single image.

Tileset image:
Spriteset image:
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)…
When you click the launcher...
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.

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.
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.

- enemies.png -> 256x256, 8bit, 256 colors (texture packer generated)
- tiles.bmp -> 256x256, 8bit, 256 colors (non-texture packer generated)
- shuttle.bmp -> 64x64, 4 bit, 16 colors (Patater's)
- anya.bmp -> 128x128, 16bit, high color (to show that we could combine palettized and non-palettized images)

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:
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:

- You don't need the Texture Packer for fixed-dimension tilesets and single images, just load them using glLoadTileSet().
- You can combine different color formats (palettized and 16 bit colors) seamlessly.
- You can use glColor() to "colorize" the sprites.
- Transcluceny and colorization can be applied to any of Easy GL2D's rendering functions.

## 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