Page 1 of 6

Easy GL2D

Posted: Fri Nov 19, 2010 6:00 am
by relminator
Poll added by WinterMute

A very small, simple, yet very fast DS 2D rendering lib using the DS' 3D core.



* 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.
Update 02/17/2011
* Code overhaul for libnds 1.5.0 compatibility
* Added 2 parameters to glSpriteLoad() and glSpriteLoad()
* Fixed the examples to reflect changes
* Doxygen generated reference
* Bug fixes(reported by Enay, MJHaune, Alex Sinclair, etc)

Update 11/25/2010

* Documentation and user's guide done. (User's guide is also a mini-tutorial of sorts)
* Added a dual_screen example.
* Updated the sprites example

Update 11/23/2010

* Fixed a bug where drawing primitives messed up the sprite colors. (missing currenttexture = 0 call)

Reasons to use Easy GL2D:

1. Library size is very small (less than 10 kb)
2. Very fast
3. Easy to maintain and refactor existing code
4. Abstracted interface
5. Code is easily portable to other platforms
6. Can combine 2D and 3D seamlessly
7. Almost unlimited palette usage in a single frame
8. Can handle non-power of 2 sprites
9. 3 types of translucency (2 via textures and 1 via polygon format)
10. Lots of sprite effects (colors, alpha, rotation, scaling, shearing, etc.)
11. Optimum VRAM use
12. Paletted(almost limitless) and high-color mode can be used together.


1. Emulators are slower in emulating the 3d hardware than the OAM.
2. glPutPixel, glLine and glBox only works on a real DS and No$GBA and not on deSmuMe.
3. 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.


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.
*Assuming you installed devkitPro in c:/devkitPro/


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


LIBS := -lgl2d -lnds9

4. Add #include <gl2d.h> to your source.

5. Done! You can now use gl2d


Easy GL2D DS works perfectly on a Real DS.

However, if you are running this on an emulator...
No$GBA - works perfectly.
deSmuMe - use the soft rasterizer instead of OpenGL

* I'm in the process of writing a documentation as well as a user's guide that would
essentially be a mini tutorial of sorts.

@WinterMute: You are free to add this to devkitPro if you deem it good enough. :*)

Re: Easy GL2D

Posted: Fri Nov 19, 2010 12:31 pm
by coreyh2
thanks for releasing this. :)

Re: Easy GL2D

Posted: Fri Nov 19, 2010 4:56 pm
by relminator
No problem. Just my way of giving back to the community.

Anyways, I would really appreciate it if you can test it for bugs and such.

Re: Easy GL2D

Posted: Sat Nov 20, 2010 12:43 am
by coreyh2
I'll do my best. I haven't done much with 3d engine so I may not know bugs when I see them. I going to try to get a couple layers of background and a character moving around. Also try to get the dual screens working.

Re: Easy GL2D

Posted: Sat Nov 20, 2010 10:05 am
by coreyh2
This is the texture packer that is used in the examples?

Is this a accurate description of how to move textures from main memory to vram frame by frame? ... ++textures

Re: Easy GL2D

Posted: Thu Nov 25, 2010 7:49 am
by relminator
coreyh2 wrote:This is the texture packer that is used in the examples?

Is this a accurate description of how to move textures from main memory to vram frame by frame? ... ++textures
Yes that's the texture packer.

If I were you, I'd load my textures on a per-level basis and not on a per frame basis.

BTW, I've uploaded a newer version. Some bugfix, updated examples and a new example where it shows how to do dual screen in Easy GL2D.

Also check out the "user's guide" as it has some nice examples and acts as a mini tutorial.

Re: Easy GL2D

Posted: Fri Nov 26, 2010 9:29 am
by coreyh2
Thanks for making more documentation.

While I was working on pixel art a while ago I spent some time seeing how much detail I could get with different sprite sizes while still keeping the figures proportional. My vague plan involved using really large sprites. I won't have room to store the amount of animation I want in vram all the time. I'll have to store it in main memory and probably on the flash card.

The plan is based on me actually being able to produce the art first. I'll have an idea of how big everything will be later.

Re: Easy GL2D

Posted: Fri Jan 21, 2011 2:27 pm
I will and try and post this again as it seemed to get lost last time. I wish I had backed up my post last time :)

Ok, I have been trying to use this library for the past few days. It looks really great but unfortunately my images come out black. This also happens when I compile the GL2D tutorials as well, most of the images render black. I thought it might be my fault but I have been looking for ages at what could be wrong and found nothing. The example precompiled binaries for GL2D work on all DeSmuME.0.9.4-win32, no$gba-w.2.6a and the real DS but it is when I simply load up the project in programmers notepad and try to compile myself and make new binaries that there are problems. Problems occur on both emulators and a real DS.

So I was wondering whether maybe something new in libnds 1.4.9 has broken this library 2 months since it has been posted or something along those lines, sadly I can't download the old version of libnds to check for myself. The 'Sprites' example has the Anya picture displaying ok but all other sprites are black. The scrolling example with Chronos shows the pinky window only and everything else is black. I have tried uninstalling and reinstalling both GL2D and all of devkidpro and no changes. :( All other source codes and tutorials compile ok, just when I try to use the GL2D library I get problems. Well anyway I am totally stuck and was wondering whether anyone has the same problem or confirm that it's not just me going crazy.

Thanks in advance :)

Re: Easy GL2D

Posted: Mon Jan 24, 2011 7:03 am
by relminator
Thanks for pointing this out. I believe it's not your code or you.

After you pointed out that the anya pic works well and everything is black I can assume that this is the problem:
(In bold)
libnds 1.4.9

* correct copy size for GLRGB.
* add some macros for DISPCAP related registers.
* rename vramSetMainBanks/vramRestoreMainBanks to vramSetPrimaryBanks/vramRestorePrimaryBanks.
* texture palettes: support any assortment of banks E,F,G.
* documentation fixes and code cleanup.
I was using the libnds version I downloaded last December. The old lib puts all its palettes to Vram E.

I can't DL the new lbnds with my current connection speeds right now but the good news is that I'll be in the city in the next few days(where I have a better connection). I'll update the lib when I get there.


After talking with zeromus(he was the one who changed it), this should fix things:

Instead of just this:

Code: Select all

vramSetBankA( VRAM_A_TEXTURE );
Use this:

Code: Select all

vramSetBankA( VRAM_A_TEXTURE );
Tell me if it works.


I just tried it and it works.

New code for the /sprites demo. Only needed to add 1 line of code.

Code: Select all

	Easy GL2D 
	Sprites example
	Shows a some sprite capabilities of easy GL2D
	Relminator (Richard Eric M. Lope BSN RN)
	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 <string.h>
#include <gl2d.h>

// GRIT auto-generated  files
#include "enemies.h"
#include "zero.h"
#include "tiles.h"
#include "shuttle.h"
#include "anya.h"

// Texture Packer auto-generated UV coords

#include "uvcoord_enemies.h"
#include "uvcoord_zero.h"

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

const int BRAD_PI = 1 << 14;

// 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"
// ZERO_NUM_IMAGES is a value from "uvcoord_zero.h"
glImage  Enemies[ENEMIES_NUM_IMAGES];	// spriteset
glImage  Zero[ZERO_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() 

	int i;
	//set mode 5, enable BG0 and set it to 3D
	videoSetMode( MODE_5_3D );
	// initialize gl2d
	// Set up enough texture memory for our textures
	// Bank A is just 128kb and we are using 194 kb of
	// sprites
	vramSetBankA( VRAM_A_TEXTURE );
	vramSetBankB( VRAM_B_TEXTURE );

	// Make an all-white palette for stencil effects
	unsigned short *hitPal = malloc( 256 * sizeof(unsigned short) );
	for( i = 0; i < 256; i++ )
		hitPal[i] = (0xFF << 8 ) | 0xFF;
	int hitTexPal = gluTexLoadPal( hitPal, 512, GL_RGB256 );

	free( hitPal );
	// 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
						 (u8*)enemiesBitmap	 	// image data generated by GRIT
	// Load our 256 color enemies palette
	// enemiesPal, enemiesPalLen are found in a GRIT generated header
	// Also save the return value for reference later since we
	// are using more than 1 palette.
	int EnemiesTexPal = gluTexLoadPal( enemiesPal, enemiesPalLen, GL_RGB256 );

	// Load our Zero texture
	// We used glLoadSpriteSet since the texture was made
	// with my texture packer.
	// No need to load the palette since enemies and zero
	// share the same palette.
	int ZeroTextureID = 
		glLoadSpriteSet( Zero,					// pointer to glImage array
						 ZERO_NUM_IMAGES, 		// Texture packer auto-generated #define
						 zero_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_256,		// sizeY for glTexImage2D() in videoGL.h
						 (u8*)zeroBitmap	 	// 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
					   (u8*)tilesBitmap		// image data generated by GRIT
	// Load palette of the tiles
	// We are using a #define auto-generated by GRIT
	// Can be found in the /build directory
	int TilesTexPal = gluTexLoadPal( tilesPal, tilesPalLen, GL_RGB256 );

	// 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
					   (u8*)shuttleBitmap // image data generated by GRIT

	// Load our 16 color shuttle palette
	int ShuttleTexPal = gluTexLoadPal( shuttlePal, shuttlePalLen, GL_RGB16 );

	// Anya
	// This is a 16 bit image
	int AnyaTextureID = 
		glLoadTileSet( Anya,

	// Print some console stuff
	iprintf("\x1b[1;1HEasy GL2D Sprites Demo");
	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, %i", 
	// calculate the amount of 
	// memory uploaded to VRAM in KB
	int TextureSize = enemiesBitmapLen +
					  zeroBitmapLen +
					  tilesBitmapLen +
					  shuttleBitmapLen +
	iprintf("\x1b[15;1HTotal Texture size= %i kb", TextureSize / 1024);
	iprintf("\x1b[17;1HEnemies use a 256 color pal");
	iprintf("\x1b[18;1HZero uses a 256 color pal");
	iprintf("\x1b[19;1HTiles use a 256 color pal");
	iprintf("\x1b[20;1HShuttle uses a 16 color pal");
	iprintf("\x1b[21;1HAnya is a 16 bit image");
	// some variables for our demo
	int Frame = 0;				// just the standard 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
	int Rotation = 0;			// rotation value of the rotating sprites
	while( 1 ) 
		Rotation = Frame * 240;		// speed up our rotation
		// animate some of our animated sprites
		// every 8th frame
		if ( (Frame & 7) == 0 )
			BeeFrame = (BeeFrame + 1) & 1;
			if (PhoenixFrame > 2) PhoenixFrame = 0;

		// Faster zero animation
		if ( (Frame & 3) == 0 )

			if (ZeroFrame > 9) ZeroFrame = 0;
		// calculate positions for our rotating sprites
		int x = 128 + ((cosLerp(Frame)+sinLerp(BRAD_PI+Rotation) * 100) >> 12);
		int y = 96 + ((cosLerp(Frame)+cosLerp(-Rotation) * 80) >> 12);
		// Start 2D mode

			// Set our palette to our tiles (256 colors)
			// and draw our background
			glColorTable( GL_RGB256, TilesTexPal );
			DrawBG( Tiles );
			// Make the Anya's rotoscaled sprite translucent just for kicks
			// Use glSpriteRotateScaleXY() for some effect
			// Give it a polygon ID so that transluceny would work
			glPolyFmt(POLY_ALPHA(20) | 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 );
			// Set our palette to the enemies spriteset (256 colors)
			glColorTable( GL_RGB256, EnemiesTexPal );
			// Draw our enemies
			// draw some rotated and/or animated sprites
			// Give  the other sprites different polygon IDs
			// so that translucency works
			glPolyFmt(POLY_ALPHA(20) | POLY_CULL_NONE | POLY_ID(2));
			glSpriteRotate(    x,     y,      Rotation,          GL_FLIP_NONE, &Enemies[30+BeeFrame]);
			glSpriteRotate(255-x, 191-y,  Rotation * 4,             GL_FLIP_H, &Enemies[84]);
			glSpriteRotate(255-x,     y,     -Rotation,             GL_FLIP_V, &Enemies[32]);
			glSpriteRotate(    x, 191-y, -Rotation * 3, GL_FLIP_H | GL_FLIP_V, &Enemies[81]);
			// Some phoenix enemies on the right
			// Note the flipmodes 
			// Also shows how we can draw in "color mode" and shadow mode
			glPolyFmt(POLY_ALPHA(20) | POLY_CULL_NONE | POLY_ID(3));
			glSprite(200, 0,  GL_FLIP_NONE,           &Enemies[87 + PhoenixFrame]);
			glColor( RGB15(31,0,0) );
			glSprite(200, 30,  GL_FLIP_H,              &Enemies[87 + PhoenixFrame]);
			// Make the last two sprites translucent
			glPolyFmt(POLY_ALPHA(20) | POLY_CULL_NONE | POLY_ID(4));
			glColor( RGB15(0,31,20) );
			glSprite(200, 60,  GL_FLIP_V,              &Enemies[87 + PhoenixFrame]);
			glColor( RGB15(0,0,0) );
			glSprite(200, 90, GL_FLIP_V | GL_FLIP_H , &Enemies[87 + PhoenixFrame]);
			//Restore color and translucency to normal 
			glColor( RGB15(31,31,31) );
			glPolyFmt(POLY_ALPHA(31) | POLY_CULL_NONE | POLY_ID(5));
			// Set palette to shuttle's palette (16 colors)
			// "Clean Stretch" the sprite
			// Useful for lasers and some effects
			glColorTable( GL_RGB16, ShuttleTexPal );
			glSpriteStretchHorizontal( 0, 135, 64 + (abs(sinLerp(Frame*100) * 200) >> 12), Shuttle );
			glColorTable( GL_RGB256, hitTexPal );
			// Use the enemies palette since zero share the same palette
			//glColorTable( GL_RGB256, EnemiesTexPal );
			glSprite( 0, 42*0, GL_FLIP_NONE, &Zero[ZeroFrame] );
			// Draw a horizontally  flipped "disco" zero
			// Disco fx is done with glColor
			int color = (Frame*4) & 31;
			glColor( RGB15(color, 31-color, 16+color*2) );
			glSprite( 0, 42*1, GL_FLIP_H, &Zero[ZeroFrame] );
			// restore pal to enemies
			glColorTable( GL_RGB256, EnemiesTexPal );
			glColor( RGB15(31-color, 16 + color*2, color) );
			glSprite( 0, 42*2, GL_FLIP_V, &Zero[ZeroFrame] );
			// Normalize color
			glColor( RGB15(31, 31, 31) );
			glSprite( 0, 42*3, GL_FLIP_V |GL_FLIP_H, &Zero[ZeroFrame] );

		glFlush( 0 );


	return 0;

}//end main 

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

Re: Easy GL2D

Posted: Mon Jan 24, 2011 7:37 am
Hi relminator,

You beat me too it! :) I finally tracked down an earlier build from around december and was just about to say that everything is working ok now that I compile in the older version. I have only been tinkering around with the DS for about a week so I don't really know where much is yet, but quite clearly if the texture banks have been updated in devkitpro then there lies the problem. Especially since I had a feeling it was to do with banks.

Please post here again when you have an update. I'd really appeciate it.
For now at least I can actually see what I am doing. It's very difficult to code anything when everything is appearing black! :) Thanks for reading my post. Seeya.