GP32 Graphics In Mr.mirko's Sdk


TheMrCul

Still Fresh
Joined
Apr 18, 2003
Messages
52
Hi all
I've just been converting my project to Mr.Mirko's great SDK, but run into problems with my tile engine. Any time I run the funtion gp_drawTiled16((u16*)RanchTiles, TransColour, TileSize, Tile, XPos, YPos, framebuffer[swapper]);
it compiles fine but crashes the GP32. I read on the help html file that images must have headers, so they must be converted with bmp2bin -x blah.bmp blah.raw
That's fine, but I can't include it in my project either with a #include "blah.raw" or including it in my make file under objects. I know this is a stupid question but I'm at my wit's end! How do I stop my GP32 from crashing? Can anyone help me? Thankyou
 
You'll need to convert the .bin to something the compiler/makefile understands.

Either .c or .h with bin2c for the compiler to create it
or bin2obj for the makefile to link it.

I don't know the exact command for doing a bin2obj, I use bin2c and include blah.c in my files to make
 
a pretty neato way to save yourself from the trouble of converting to an array is to include the .raw file in asm.

create an file called for example images.s and put that on the OBJS line in your makefile.

here i do two images just to demonstrate.

Code:
.ALIGN 2 
.ARM 

.GLOBAL gfx_logo 
.GLOBAL gfx_segments_dot 

gfx_logo:
.INCBIN "resource/logo.raw" 
gfx_segments_dot:
.INCBIN "resource/segments_dot.raw"

to use that just do:

Code:
extern u16 gfx_logo[];     // Tells the compiler that you want to use a variable declared in an other file.
	
gp_drawSpriteHT ((u16*)gfx_logo, 32, 100, video->GetFramebuffer(), TRANS_COL );
 
Hi! Thanks that fixed the problem and now my program has been ported from the official SDK to Mr Mirko's one. However it's running at less than 1/2 the speed that it was before I ported it! Everything is the same except the graphics functions. Are Mr.Mirko's tile funtions slow? Or is it something i've done wrong? Thanks for all your help so far!
 
Hi! Thanks that fixed the problem and now my program has been ported from the official SDK to Mr Mirko's one. However it's running at less than 1/2 the speed that it was before I ported it! Everything is the same except the graphics functions. Are Mr.Mirko's tile funtions slow? Or is it something i've done wrong? Thanks for all your help so far!

For what I have read in other posts, Mr Mirko blitting functions are slower than GP SDK equivalent functions.

BTW why have you changed your SDK?
 
Last edited by a moderator:
Yes, the blitting functions are a bit slow, only coded in c.
But there is a new arm asm blitting lib in the 0.95 SDK,
its twice the speed of the official SDK. :)
 
I'm using the .95 verson of Mr.Mirko's sdk i believe. I changed SDKs because 16bit graphics was giving me hell with the origional SDK and I wanted to use mods too. But even doubling the CPU speed (from 66 to 133) still doesn't get to the same speed that the orig. SDK did. Here is my tile blitting code:
btw, TileSize is 20x20 pixels.

Code:
inline void DrawTiles(int CameraX, int CameraY)
{
	int ScreenWidth, ScreenHeight, XTile, YTile, XPos, YPos, Tile;

	//Get the starting tile to draw with
	XTile = CameraX / TileSize;
	YTile = CameraY / TileSize;

	//The pixel offset
	XPos = CameraX % TileSize;
	YPos = CameraY % TileSize;

	//Now draw the tiles
	for(ScreenWidth = 0; ScreenWidth < 17; ScreenWidth++) //across the screen in increments of 20
	{
  for(ScreenHeight = 0; ScreenHeight < 13; ScreenHeight++) //down the screen, increments of 20
  {
  	//Get the tile number to draw and then draw it
  	Tile = CurrentMap[YTile + ScreenHeight][XTile + ScreenWidth];

  	gp_drawTiled16((u16*)RanchTiles, TransColour, TileSize, Tile,
      	ScreenWidth * TileSize - XPos,
      	ScreenHeight * TileSize - YPos,
      	framebuffer[swapper]);
  }
	}
}

Do you see any problems that might be slowing everything down here? I will look into the asm blitting code though! Thanks!

EDIT:
Just looked at the asm blitting code, and it wants an unsigned char* for the picture to be blitted - does that mean that it's only 8bit, not 16bit? and also, the function prototype looks like this:
gp_FastSolidBlit(void *framebuffer, int dx, const int dy, const int width, const int height, const unsigned char *src, const int trans, const int coul)
But why does it ask for a trans when it's supposed to be solid and what is this const int coul all about? I tried just putting a 0 for it, but it just prints black! What's wrong with it? Blah also had problems with this function I think! Thanks!
 
the gp_drawTiled16 functions still use the old blitting variation (putting pixel by pixel) which is far to slow when you need to fill the whole screen. you should look into combining the fastblit functions with the drawTiled functions, or maybe start using memcpy alltogheter.
 
Have you had experience with the gp_fastSolidBlit() functions? Do you know how to use them? otherwise do you know where some examples on how to use memcpy() with MrMirko's graphics in mind? Thanks for your help kissbengt.
 
I still can't figure those out. For now I'm using the Fastblit function by Pea (as part of DemonicaGameLib by Unit3). You need to have your pictures flipped 90 deg by using the -r option in bmp2bin.
 
I still can't figure those out. For now I'm using the Fastblit function by Pea (as part of DemonicaGameLib by Unit3). You need to have your pictures flipped 90 deg by using the -r option in bmp2bin.

Right I'll give that a go too. Thanks blah. :)
 
Last edited by a moderator:
Here is the code I use, slightly modified from Pea's code to be more similar to Mirko's functions:

Code:
//Simple lib for drawing prerotated sprites with alpha and/or mirko style headers.
//By Pea and Blah

#define max(a, B) ((a) > (B) ? (a) : (B)) 
#define min(a, B) ((a) < (B) ? (a) : (B)) 

typedef struct tGP_alphaLUT{
	unsigned char values[1024];
}tGP_alphaLUT;
static tGP_alphaLUT gp_alphaLUT[32];
 
//Use this function like so: gp_drawSpriteFH(sprite,x,y,framebuffer);
//Where sprite is your sprite as an unsigned short  pointer(u16) and x and y are 
//your coordinates, and framebuffer is the unsigned short pointer(u16) your 
//blitting to.

void gp_drawSpriteFH( u16 *sprite, short put_x, short put_y, u16 *framebuffer){
	unsigned short xx,yy;
	unsigned short vw,vh;
	unsigned long doff;
	unsigned long coff;
	unsigned short px,py;
            
	short tx,ty;
	unsigned  width, height;
	SHEADER *sheader;
	
	sheader = (SHEADER*) sprite;
	height = sheader->size_y;
	width = sheader->size_x;

	// If rect is off the screen, exit
	if ((put_x>=LCD_WIDTH) || (put_y>=LCD_HEIGHT)){ return; }
	tx = put_x+width; ty = put_y+height;
	if ((tx<0) || (ty<0)){ return; }
	
	// The rest of the coordinates are calculated based on a screen rotation
	// of 90 degrees clockwise.
	ty = put_y;
	put_y = put_x;
	put_x = LCD_HEIGHT - ty - height;
	tx = put_x+height; ty = put_y+width;
	
	// Positional offsets
	px = max( (short)0, put_x );
	py = max( (short)0, put_y );
	// Visible height
	if (put_y<0){
  vh = min( ty, (short)LCD_WIDTH );
	}else{
  if (ty>LCD_WIDTH){
  	vh = width - (ty-LCD_WIDTH);
  }else{
  	vh = width;
  }
	}
	// Visible width
	if (put_x<0){
  vw = min( tx, (short)LCD_HEIGHT );
	}else{
  	if (tx>LCD_HEIGHT){
  	vw = height - (tx-LCD_HEIGHT);
  }else{
  	vw = height;
  }
	}
	// Data offset
	doff = ( height * max( 0, -put_y ) ) + max( 0, -put_x ) + 6; // +6 to jump the header data
	// Canvas data offset
	coff = py*LCD_HEIGHT + px;
	
	// Draw visible pixels only
	for ( yy=0; yy<vh; yy++ ){
  memcpy( &framebuffer[coff], &sprite[doff], vw*2 );
  doff += height;
  coff += LCD_HEIGHT;
	}
}

void gp_createAlphaLUT( void ){
tGP_alphaLUT *level;
char a,d,s;

// Create alpha look up table. The look up table is implemented
// as a series of shorter tables in the hope that it is cached.
for (a=0; a<32; a++){ // alpha
level = &gp_alphaLUT[a];
for (s=0; s<32; s++){ // source
for (d=0; d<32; d++){ // destination
level->values[(s<<5)+d] = ((s*a)+(d*(31-a)))/31;
}
}
}
}

//Use this function like so: gp_drawSpriteFHA(sprite,x,y,framebuffer,alpha);
//Where sprite is your sprite as an unsigned short  pointer(u16) and x and y are 
//your coordinates, and framebuffer is the unsigned short pointer(u16) your 
//blitting to, and alpha is the a number between 1 and 30. What's cool about this
//function is, when alpha is set to 0, it doesn't render, and when alpha is set past 
//30, it renders using gp_drawSpriteFH, which is faster.

void gp_drawSpriteFHA(u16 *sprite,short x, short y, u16 *framebuffer, unsigned char alpha){
// If alpha is max, render fast method
if (alpha>30){
gp_drawSpriteFH(sprite,x,y,framebuffer);
return;
}
// If no alpha, simply exit (none of source is rendered)
if (alpha==0){
return;
}

unsigned short xx,yy;
unsigned short vw,vh;
unsigned short *doff, *coff;
short dstep, cstep;
unsigned short px,py;
short tx,ty;
unsigned short scolour, dcolour;
unsigned short rs, gs, bs;
unsigned char rd, gd, bd;
unsigned char ra, ga, ba;
tGP_alphaLUT *level;
unsigned  width, height;
SHEADER *sheader;
sheader = (SHEADER*) sprite;
height = sheader->size_y;
width = sheader->size_x;

// If rect is off the screen, exit
if ((x>=LCD_WIDTH) || (y>=LCD_HEIGHT)){ return; }
tx = x+width; ty = y+height;
if ((tx<0) || (ty<0)){ return; }

// The rest of the coordinates are calculated based on a screen rotation
// of 90 degrees clockwise.
ty = y;
y = x;
x = LCD_HEIGHT - ty - height;
tx = x+height; ty = y+width;

// Positional offsets
px = max( 0, x );
py = max( 0, y );
// Visible height
if (y<0){ 
vh = min( ty, LCD_WIDTH );
}else{
if (ty>LCD_WIDTH){
vh = width - (ty-LCD_WIDTH);
}else{
vh = width;
}
}
// Visible width
if (x<0){
vw = min( tx, LCD_HEIGHT );
}else{
if (tx>LCD_HEIGHT){
vw = height - (tx-LCD_HEIGHT);
}else{
vw = height;
}
}
// Data offset
doff = sprite + ( height * max( 0, -y ) ) + max( 0, -x ) +6;
dstep = height - vw;
// Canvas data offset
coff = framebuffer + (py*LCD_HEIGHT + px);
cstep = LCD_HEIGHT - vw;

// Get the row of the LUT we need
level = &gp_alphaLUT[alpha];

// Draw visible pixels only
for ( yy=0; yy<vh; yy++ ){
for (xx=0; xx<vw; xx++ ){
// Get source colour components pre-multiplied by 32 (for LUT)
scolour = *doff;
rs = (((scolour) >> 6) & 0x03E0);
gs = (((scolour) >> 1) & 0x03E0);
bs = (((scolour) << 4) & 0x03E0);
// Get existing (destination) colour components
dcolour = *coff;
rd = (((dcolour) >> 11) & 0x1F);
gd = (((dcolour) >> 6) & 0x1F);
bd = (((dcolour) >> 1) & 0x1F);
// Blend using LUT
ra = level->values[rs+rd];
ga = level->values[gs+gd];
ba = level->values[bs+bd];
// Combine colours and set
*coff = ((ra<<11)+(ga<<6)+(ba<<1));
coff++; doff++;
}
coff += cstep;
doff += dstep;
}
}

I think I might use some stuff from this also, as my/Pea's code doesn't support transparency.

Una-i Sprite Library
 
Ok, I've updated it to include transparency and non-header support.

Here is the updated BLIT.C:

Code:
//Simple lib for drawing prerotated sprites with alpha and/or mirko style headers.
//By Pea and Blah

#define max(a, B) ((a) > (B) ? (a) : (B)) 
#define min(a, B) ((a) < (B) ? (a) : (B))

void gp_drawSpriteF( u16 *sprite, short put_x, short put_y, unsigned width, unsigned height,u16 *framebuffer){
unsigned short xx,yy;
unsigned short vw,vh;
unsigned long doff;
unsigned long coff;
unsigned short px,py;
           
short tx,ty;
// If rect is off the screen, exit
if ((put_x>=LCD_WIDTH) || (put_y>=LCD_HEIGHT)){ return; }
tx = put_x+width; ty = put_y+height;
if ((tx<0) || (ty<0)){ return; }

// The rest of the coordinates are calculated based on a screen rotation
// of 90 degrees clockwise.
ty = put_y;
put_y = put_x;
put_x = LCD_HEIGHT - ty - height;
tx = put_x+height; ty = put_y+width;

// Positional offsets
px = max( (short)0, put_x );
py = max( (short)0, put_y );
// Visible height
if (put_y<0){
 vh = min( ty, (short)LCD_WIDTH );
}else{
 if (ty>LCD_WIDTH){
  vh = width - (ty-LCD_WIDTH);
 }else{
  vh = width;
 }
}
// Visible width
if (put_x<0){
 vw = min( tx, (short)LCD_HEIGHT );
}else{
  if (tx>LCD_HEIGHT){
  vw = height - (tx-LCD_HEIGHT);
 }else{
  vw = height;
 }
}
// Data offset
doff = ( height * max( 0, -put_y ) ) + max( 0, -put_x ); // removed + 6, no sprite header here.
// Canvas data offset
coff = py*LCD_HEIGHT + px;

// Draw visible pixels only
for ( yy=0; yy<vh; yy++ ){
 memcpy( &framebuffer[coff], &sprite[doff], vw*2 );
 doff += height;
 coff += LCD_HEIGHT;
}
}

typedef struct tGP_alphaLUT{
unsigned char values[1024];
}tGP_alphaLUT;
static tGP_alphaLUT gp_alphaLUT[32];

void gp_createAlphaLUT( void ){
tGP_alphaLUT *level;
char a,d,s;

// Create alpha look up table. The look up table is implemented
// as a series of shorter tables in the hope that it is cached.
for (a=0; a<32; a++){ // alpha
level = &gp_alphaLUT[a];
for (s=0; s<32; s++){ // source
for (d=0; d<32; d++){ // destination
level->values[(s<<5)+d] = ((s*a)+(d*(31-a)))/31;
}
}
}
}

void gp_drawSpriteFA(u16 *sprite,short x, short y, unsigned height, unsigned width, u16 *framebuffer, unsigned char alpha){
// If alpha is max, render fast method
if (alpha>30){
gp_drawSpriteF(sprite,x,y,width,height,framebuffer);
return;
}
// If no alpha, simply exit (none of source is rendered)
if (alpha==0){
return;
}

unsigned short xx,yy;
unsigned short vw,vh;
unsigned short *doff, *coff;
short dstep, cstep;
unsigned short px,py;
short tx,ty;
unsigned short scolour, dcolour;
unsigned short rs, gs, bs;
unsigned char rd, gd, bd;
unsigned char ra, ga, ba;
tGP_alphaLUT *level;

// If rect is off the screen, exit
if ((x>=LCD_WIDTH) || (y>=LCD_HEIGHT)){ return; }
tx = x+width; ty = y+height;
if ((tx<0) || (ty<0)){ return; }

// The rest of the coordinates are calculated based on a screen rotation
// of 90 degrees clockwise.
ty = y;
y = x;
x = LCD_HEIGHT - ty - height;
tx = x+height; ty = y+width;

// Positional offsets
px = max( 0, x );
py = max( 0, y );
// Visible height
if (y<0){ 
vh = min( ty, LCD_WIDTH );
}else{
if (ty>LCD_WIDTH){
vh = width - (ty-LCD_WIDTH);
}else{
vh = width;
}
}
// Visible width
if (x<0){
vw = min( tx, LCD_HEIGHT );
}else{
if (tx>LCD_HEIGHT){
vw = height - (tx-LCD_HEIGHT);
}else{
vw = height;
}
}
// Data offset
doff = sprite + ( height * max( 0, -y ) ) + max( 0, -x ); //removed +6, no sprite header here.
dstep = height - vw;
// Canvas data offset
coff = framebuffer + (py*LCD_HEIGHT + px);
cstep = LCD_HEIGHT - vw;

// Get the row of the LUT we need
level = &gp_alphaLUT[alpha];

// Draw visible pixels only
for ( yy=0; yy<vh; yy++ ){
for (xx=0; xx<vw; xx++ ){
// Get source colour components pre-multiplied by 32 (for LUT)
scolour = *doff;
rs = (((scolour) >> 6) & 0x03E0);
gs = (((scolour) >> 1) & 0x03E0);
bs = (((scolour) << 4) & 0x03E0);
// Get existing (destination) colour components
dcolour = *coff;
rd = (((dcolour) >> 11) & 0x1F);
gd = (((dcolour) >> 6) & 0x1F);
bd = (((dcolour) >> 1) & 0x1F);
// Blend using LUT
ra = level->values[rs+rd];
ga = level->values[gs+gd];
ba = level->values[bs+bd];
// Combine colours and set
*coff = ((ra<<11)+(ga<<6)+(ba<<1));
coff++; doff++;
}
coff += cstep;
doff += dstep;
}
}

void gp_drawSpriteFAT(u16 *sprite,short x, short y, unsigned height, unsigned width, u16 *framebuffer, u16 trans, unsigned char alpha){
// If alpha is max, render fast method
if (alpha>30){
gp_drawSpriteF(sprite,x,y,width,height,framebuffer);
return;
}
// If no alpha, simply exit (none of source is rendered)
if (alpha==0){
return;
}

unsigned short xx,yy;
unsigned short vw,vh;
unsigned short *doff, *coff;
short dstep, cstep;
unsigned short px,py;
short tx,ty;
unsigned short scolour, dcolour;
unsigned short rs, gs, bs;
unsigned char rd, gd, bd;
unsigned char ra, ga, ba;
tGP_alphaLUT *level;

// If rect is off the screen, exit
if ((x>=LCD_WIDTH) || (y>=LCD_HEIGHT)){ return; }
tx = x+width; ty = y+height;
if ((tx<0) || (ty<0)){ return; }

// The rest of the coordinates are calculated based on a screen rotation
// of 90 degrees clockwise.
ty = y;
y = x;
x = LCD_HEIGHT - ty - height;
tx = x+height; ty = y+width;

// Positional offsets
px = max( 0, x );
py = max( 0, y );
// Visible height
if (y<0){ 
vh = min( ty, LCD_WIDTH );
}else{
if (ty>LCD_WIDTH){
vh = width - (ty-LCD_WIDTH);
}else{
vh = width;
}
}
// Visible width
if (x<0){
vw = min( tx, LCD_HEIGHT );
}else{
if (tx>LCD_HEIGHT){
vw = height - (tx-LCD_HEIGHT);
}else{
vw = height;
}
}
// Data offset
doff = sprite + ( height * max( 0, -y ) ) + max( 0, -x ); //removed +6, no sprite header here.
dstep = height - vw;
// Canvas data offset
coff = framebuffer + (py*LCD_HEIGHT + px);
cstep = LCD_HEIGHT - vw;

// Get the row of the LUT we need
level = &gp_alphaLUT[alpha];

// Draw visible pixels only
for ( yy=0; yy<vh; yy++ ){
for (xx=0; xx<vw; xx++ ){
// Get source colour components pre-multiplied by 32 (for LUT)
scolour = *doff;
if (scolour != trans) {
rs = (((scolour) >> 6) & 0x03E0);
gs = (((scolour) >> 1) & 0x03E0);
bs = (((scolour) << 4) & 0x03E0);
// Get existing (destination) colour components
dcolour = *coff;
rd = (((dcolour) >> 11) & 0x1F);
gd = (((dcolour) >> 6) & 0x1F);
bd = (((dcolour) >> 1) & 0x1F);
// Blend using LUT
ra = level->values[rs+rd];
ga = level->values[gs+gd];
ba = level->values[bs+bd];
// Combine colours and set
*coff = ((ra<<11)+(ga<<6)+(ba<<1));
}
coff++; doff++;
}
coff += cstep;
doff += dstep;
}
}

void gp_drawSpriteFT(u16 *sprite,short x, short y, unsigned height, unsigned width, u16 *framebuffer, u16 trans){
unsigned short xx,yy;
unsigned short vw,vh;
unsigned short *doff, *coff;
short dstep, cstep;
unsigned short px,py;
short tx,ty;
unsigned short color;

// If rect is off the screen, exit
if ((x>=LCD_WIDTH) || (y>=LCD_HEIGHT)){ return; }
tx = x+width; ty = y+height;
if ((tx<0) || (ty<0)){ return; }

// The rest of the coordinates are calculated based on a screen rotation
// of 90 degrees clockwise.
ty = y;
y = x;
x = LCD_HEIGHT - ty - height;
tx = x+height; ty = y+width;

// Positional offsets
px = max( 0, x );
py = max( 0, y );
// Visible height
if (y<0){ 
vh = min( ty, LCD_WIDTH );
}else{
if (ty>LCD_WIDTH){
vh = width - (ty-LCD_WIDTH);
}else{
vh = width;
}
}
// Visible width
if (x<0){
vw = min( tx, LCD_HEIGHT );
}else{
if (tx>LCD_HEIGHT){
vw = height - (tx-LCD_HEIGHT);
}else{
vw = height;
}
}
// Data offset
doff = sprite + ( height * max( 0, -y ) ) + max( 0, -x ); //removed +6, no sprite header here.
dstep = height - vw;
// Canvas data offset
coff = framebuffer + (py*LCD_HEIGHT + px);
cstep = LCD_HEIGHT - vw;

// Draw visible pixels only
for ( yy=0; yy<vh; yy++ ){
for (xx=0; xx<vw; xx++ ){
// Get source colour components pre-multiplied by 32 (for LUT)
color = *doff;
if (color != trans) {
*coff = color;
}
coff++; doff++;
}
coff += cstep;
doff += dstep;
}
}

void gp_drawSpriteFH(u16 *sprite, short put_x, short put_y, u16 *framebuffer){
unsigned  width, height;
SHEADER *sheader;
sheader = (SHEADER*) sprite;
height = sheader->size_y;
width = sheader->size_x;
gp_drawSpriteF(sprite+6, put_x, put_y, width, height, framebuffer);
}

void gp_drawSpriteFHA(u16 *sprite,short x, short y, u16 *framebuffer, unsigned char alpha){
unsigned  width, height;
SHEADER *sheader;
sheader = (SHEADER*) sprite;
height = sheader->size_y;
width = sheader->size_x;
gp_drawSpriteFA(sprite + 6, x, y, height, width, framebuffer, alpha);
}

void gp_drawSpriteFHAT(u16 *sprite,short x, short y, u16 *framebuffer, u16 trans, unsigned char alpha){
unsigned  width, height;
SHEADER *sheader;
sheader = (SHEADER*) sprite;
height = sheader->size_y;
width = sheader->size_x;
gp_drawSpriteFAT(sprite + 6, x, y, height, width, framebuffer, trans,alpha);
}

void gp_drawSpriteFHT(u16 *sprite,short x, short y, u16 *framebuffer, u16 trans){
unsigned  width, height;
SHEADER *sheader;
sheader = (SHEADER*) sprite;
height = sheader->size_y;
width = sheader->size_x;
gp_drawSpriteFT(sprite + 6, x, y, height, width, framebuffer, trans);
}

It works just like the ones included in Mirko's SDK, except you have to use prerotated data. To get that use bmp2bin with the -r command. Also, when using
alpha functions, you have to generate the alpha LUT (look up table) first like so:
Code:
gp_createAlphaLUT(); //Its just that simple!

So here's what the sprite.c example that came with Mirko's would be like:
Code:
// written 2004 Mirko Roller   mirko@mirkoroller.de
// Example shows you how to use sprites, and clear the screen...
// The sprites are generated with: bmp2raw -x name.bmp name.raw


#include "gp32.h"
#include "blit.c"

//extern unsigned char modfile[];
extern unsigned char garfield[];
extern unsigned char odie[];
extern unsigned char test[];

u16 *framebuffer[2];

char swapper=0;
void swap_screen () {
   gp_setFramebuffer(framebuffer[swapper],1);
   swapper++; if (swapper == 2) swapper=0;
}

int main() {

  int spritex=-150;
  int x;
  int framerate=0;
  int refreshrate=0;
  char buffer[64]="Framerate:         ";
  framebuffer[0] = (u16*)  FRAMEBUFFER1;
  framebuffer[1] = (u16*)  FRAMEBUFFER2;

  gp_setCpuspeed(133);
  
  gp_initRTC();
  refreshrate=gp_initFramebuffer(framebuffer[0],16,85);
  gp_clearRTC();
  gp_createAlphaLUT();

 while (1) {

  // Drawing in Sprite header mode, only usefull if the sprite got a header.
  // Use it only, if your Sprite is converted with ./bmp2raw -x
  // You can use:  gp_drawSpriteT,gp_drawSprite  if your sprite data, are in raw data format.

  swap_screen();
    gp_clearFramebuffer16(framebuffer[swapper],0xffff); // very very fast asm, faster than memset
    for (x=200;x<320;x+=4) gp_drawLine16 (319,239,x,  0,0xf800,framebuffer[swapper]);
    gp_drawSpriteFH  ( (u16*)    test,100, 10, framebuffer[swapper]);
    gp_drawSpriteFHT ( (u16*)garfield, 90, 50, framebuffer[swapper], 0xFFFE );
    gp_drawSpriteFHAT( (u16*)    odie,   spritex, spritex++,framebuffer[swapper], 0xFFFE,15);



  framerate++;
  if (gp_getRTC() > 63) {sprintf(buffer,"Framerate: %d,%d    ",framerate,refreshrate);framerate=0;gp_clearRTC(); }
  gp_drawString(20,220,20,buffer,0x0000,framebuffer[swapper]);

  if (spritex>300) spritex=-150;
  if (gp_getButton()&BUTTON_A) gp_Reset();
 }
  
}

And its very fast. (Use NetBSD foundations memcpy.s ASM memcopy for more speed).

TODO:
Scaling functions
Rotating functions
Color "tinting" functions
Palleted functions
Function to rotate graphics to framebuffer alignment
Testing
Packaging
Releaseing
...and anything else I can think of

Also, its faster than Una-I's library according to my testing!
 
@Blah: good work so far, I pasted my scaling at pea's site. Maybe this helps you, I have a nearly complete gfx package if you want some ideas... Next would be some tile functions (because I could need some too ;)

snippet: Synkro - Anamorphic Sprite Scaling

Does that scaling code clip the output or not? And also, where are these other routines you speak of?

If it doesn't clip, I'll add that to it. From there it will be easy to add alpha and trans support (blit to temp buffer, then blit with alpha/trans or both).

On the subject of rotation, I found a lot of interesting methods. Using allegro-style degrees (255 total instead of 360) and a sin/cos implementation using a LUT, sounds like the fastest way.

For prerotating graphics to framebuffer style before blit, I think I can just re-purpose Mirko's blitting functions, which are too slow for "real" blitting, but should work perfectly for this application.
 
Last edited by a moderator:
@Blah: good work so far, I pasted my scaling at pea's site. Maybe this helps you, I have a nearly complete gfx package if you want some ideas... Next would be some tile functions (because I could need some too ;)

snippet: Synkro - Anamorphic Sprite Scaling

Does that scaling code clip the output or not? And also, where are these other routines you speak of?

If it doesn't clip, I'll add that to it. From there it will be easy to add alpha and trans support (blit to temp buffer, then blit with alpha/trans or both).


yes, that function clips (ugly way, there is room for speed ups), it is implemented to work not to be fast. it needs some more tweaks (transparency, alpha blending) and speed ups.

the other routines I spoke of are here: synlib WIP june 2005
this is intended to work with the mirko SDK as it uses some basic functions, but it also replaces the graphic routines and adds some functions I use often. I tried to comment everything and make it as clear (and fast) as possible but there is still some work to do.

Keep in mind:

1) this is WIP and not a release candidate
2) you can only use it under the terms of the GPL and beer-ware license

Nice to see the site being used :)

that site is great! I hope you are patient enough till the word is spread all over (specially at #gp32dev - I know you live at the end of the world, but would nice to see you there more often)
 
Last edited by a moderator:
Heres a little update:

Code:
 /* Library for drawing sprites - Blit.c - By Blah on gp32x.de based on code by Pea (pea.co.nz)
 *
 *  Note - Sprites must be rotated to framebuffer orientation.
 *  Also, I reccomend viewing this code in a good IDE, or it'll get confusing.  
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *  Changelog:
 *  
 *  June 10 2005 - Blah on gp32x.de
 *  First release
 *
 *  June 11 2005 - Blah on gp32x.de
 *  Added transparency and headerless graphics support
 *
 *  June 18 2005 - Blah on gp32x.de
 *  Added GNU GPL License
 *  Added basic tile support
 *  Added basic 8bit (256 color) graphics support
 *  Changed function names to make more sense (and be shorter and easier on the typist)
 *
 *  Todo:
 *  Clean up commenting
 *  Add support for blitting 8bit graphics in 16bit mode
 *  Add 8bit transparency support
 *  Add rotation support
 *  Add scaling support
 *  Add "hardware scrolling" (changing framebuffer pointer)
 *  Add DMA support?
 *  Fix bugs?
 *  Anything else?
 */

#define max(a, B) ((a) > (B) ? (a) : (B)) 
#define min(a, B) ((a) < (B) ? (a) : (B))

void gp_blit_16( u16 *sprite, short put_x, short put_y, unsigned width, unsigned height,u16 *framebuffer){
unsigned short xx,yy;
unsigned short vw,vh;
unsigned long doff;
unsigned long coff;
unsigned short px,py;
     
short tx,ty;
// If rect is off the screen, exit
if ((put_x>=LCD_WIDTH) || (put_y>=LCD_HEIGHT)){ return; }
tx = put_x+width; ty = put_y+height;
if ((tx<0) || (ty<0)){ return; }

// The rest of the coordinates are calculated based on a screen rotation
// of 90 degrees clockwise.
ty = put_y;
put_y = put_x;
put_x = LCD_HEIGHT - ty - height;
tx = put_x+height; ty = put_y+width;

// Positional offsets
px = max( (short)0, put_x );
py = max( (short)0, put_y );
// Visible height
if (put_y<0){
 vh = min( ty, (short)LCD_WIDTH );
}else{
 if (ty>LCD_WIDTH){
  vh = width - (ty-LCD_WIDTH);
 }else{
  vh = width;
 }
}
// Visible width
if (put_x<0){
 vw = min( tx, (short)LCD_HEIGHT );
}else{
  if (tx>LCD_HEIGHT){
  vw = height - (tx-LCD_HEIGHT);
 }else{
  vw = height;
 }
}
}

void gp_blit_8(unsigned char *sprite, short put_x, short put_y, unsigned width, unsigned height,unsigned char *framebuffer){
unsigned short xx,yy;
unsigned short vw,vh;
unsigned long doff;
unsigned long coff;
unsigned short px,py;
     
short tx,ty;
// If rect is off the screen, exit
if ((put_x>=LCD_WIDTH) || (put_y>=LCD_HEIGHT)){ return; }
tx = put_x+width; ty = put_y+height;
if ((tx<0) || (ty<0)){ return; }

// The rest of the coordinates are calculated based on a screen rotation
// of 90 degrees clockwise.
ty = put_y;
put_y = put_x;
put_x = LCD_HEIGHT - ty - height;
tx = put_x+height; ty = put_y+width;

// Positional offsets
px = max( (short)0, put_x );
py = max( (short)0, put_y );
// Visible height
if (put_y<0){
 vh = min( ty, (short)LCD_WIDTH );
}else{
 if (ty>LCD_WIDTH){
  vh = width - (ty-LCD_WIDTH);
 }else{
  vh = width;
 }
}
// Visible width
if (put_x<0){
 vw = min( tx, (short)LCD_HEIGHT );
}else{
  if (tx>LCD_HEIGHT){
  vw = height - (tx-LCD_HEIGHT);
 }else{
  vw = height;
 }
}
// Data offset
doff = ( height * max( 0, -put_y ) ) + max( 0, -put_x ); // removed + 6, no sprite header here.
// Canvas data offset
coff = py*LCD_HEIGHT + px;

// Draw visible pixels only
for ( yy=0; yy<vh; yy++ ){
 memcpy( &framebuffer[coff], &sprite[doff], vw);
 doff += height;
 coff += LCD_HEIGHT;
}
}



typedef struct tGP_alphaLUT{
unsigned char values[1024];
}tGP_alphaLUT;
static tGP_alphaLUT gp_alphaLUT[32];

void gp_createAlphaLUT( void ){
tGP_alphaLUT *level;
char a,d,s;

// Create alpha look up table. The look up table is implemented
// as a series of shorter tables in the hope that it is cached.
for (a=0; a<32; a++){ // alpha
level = &gp_alphaLUT[a];
for (s=0; s<32; s++){ // source
for (d=0; d<32; d++){ // destination
level->values[(s<<5)+d] = ((s*a)+(d*(31-a)))/31;
}
}
}
}

void gp_blitA_16(u16 *sprite,short x, short y, unsigned height, unsigned width, u16 *framebuffer, unsigned char alpha){
// If alpha is max, render fast method
if (alpha>30){
gp_blit_16(sprite,x,y,width,height,framebuffer);
return;
}
// If no alpha, simply exit (none of source is rendered)
if (alpha==0){
return;
}

unsigned short xx,yy;
unsigned short vw,vh;
unsigned short *doff, *coff;
short dstep, cstep;
unsigned short px,py;
short tx,ty;
unsigned short scolour, dcolour;
unsigned short rs, gs, bs;
unsigned char rd, gd, bd;
unsigned char ra, ga, ba;
tGP_alphaLUT *level;

// If rect is off the screen, exit
if ((x>=LCD_WIDTH) || (y>=LCD_HEIGHT)){ return; }
tx = x+width; ty = y+height;
if ((tx<0) || (ty<0)){ return; }

// The rest of the coordinates are calculated based on a screen rotation
// of 90 degrees clockwise.
ty = y;
y = x;
x = LCD_HEIGHT - ty - height;
tx = x+height; ty = y+width;

// Positional offsets
px = max( 0, x );
py = max( 0, y );
// Visible height
if (y<0){ 
vh = min( ty, LCD_WIDTH );
}else{
if (ty>LCD_WIDTH){
vh = width - (ty-LCD_WIDTH);
}else{
vh = width;
}
}
// Visible width
if (x<0){
vw = min( tx, LCD_HEIGHT );
}else{
if (tx>LCD_HEIGHT){
vw = height - (tx-LCD_HEIGHT);
}else{
vw = height;
}
}
// Data offset
doff = sprite + ( height * max( 0, -y ) ) + max( 0, -x ); //removed +6, no sprite header here.
dstep = height - vw;
// Canvas data offset
coff = framebuffer + (py*LCD_HEIGHT + px);
cstep = LCD_HEIGHT - vw;

// Get the row of the LUT we need
level = &gp_alphaLUT[alpha];

// Draw visible pixels only
for ( yy=0; yy<vh; yy++ ){
for (xx=0; xx<vw; xx++ ){
// Get source colour components pre-multiplied by 32 (for LUT)
scolour = *doff;
rs = (((scolour) >> 6) & 0x03E0);
gs = (((scolour) >> 1) & 0x03E0);
bs = (((scolour) << 4) & 0x03E0);
// Get existing (destination) colour components
dcolour = *coff;
rd = (((dcolour) >> 11) & 0x1F);
gd = (((dcolour) >> 6) & 0x1F);
bd = (((dcolour) >> 1) & 0x1F);
// Blend using LUT
ra = level->values[rs+rd];
ga = level->values[gs+gd];
ba = level->values[bs+bd];
// Combine colours and set
*coff = ((ra<<11)+(ga<<6)+(ba<<1));
coff++; doff++;
}
coff += cstep;
doff += dstep;
}
}

void gp_blitAT_16(u16 *sprite,short x, short y, unsigned height, unsigned width, u16 *framebuffer, u16 trans, unsigned char alpha){
unsigned short xx,yy;
unsigned short vw,vh;
unsigned short *doff, *coff;
short dstep, cstep;
unsigned short px,py;
short tx,ty;
unsigned short scolour, dcolour;
unsigned short rs, gs, bs;
unsigned char rd, gd, bd;
unsigned char ra, ga, ba;
tGP_alphaLUT *level;

// If rect is off the screen, exit
if ((x>=LCD_WIDTH) || (y>=LCD_HEIGHT)){ return; }
tx = x+width; ty = y+height;
if ((tx<0) || (ty<0)){ return; }

// The rest of the coordinates are calculated based on a screen rotation
// of 90 degrees clockwise.
ty = y;
y = x;
x = LCD_HEIGHT - ty - height;
tx = x+height; ty = y+width;

// Positional offsets
px = max( 0, x );
py = max( 0, y );
// Visible height
if (y<0){ 
vh = min( ty, LCD_WIDTH );
}else{
if (ty>LCD_WIDTH){
vh = width - (ty-LCD_WIDTH);
}else{
vh = width;
}
}
// Visible width
if (x<0){
vw = min( tx, LCD_HEIGHT );
}else{
if (tx>LCD_HEIGHT){
vw = height - (tx-LCD_HEIGHT);
}else{
vw = height;
}
}
// Data offset
doff = sprite + ( height * max( 0, -y ) ) + max( 0, -x ); //removed +6, no sprite header here.
dstep = height - vw;
// Canvas data offset
coff = framebuffer + (py*LCD_HEIGHT + px);
cstep = LCD_HEIGHT - vw;

// Get the row of the LUT we need
level = &gp_alphaLUT[alpha];

// Draw visible pixels only
for ( yy=0; yy<vh; yy++ ){
for (xx=0; xx<vw; xx++ ){
// Get source colour components pre-multiplied by 32 (for LUT)
scolour = *doff;
if (scolour != trans) {
rs = (((scolour) >> 6) & 0x03E0);
gs = (((scolour) >> 1) & 0x03E0);
bs = (((scolour) << 4) & 0x03E0);
// Get existing (destination) colour components
dcolour = *coff;
rd = (((dcolour) >> 11) & 0x1F);
gd = (((dcolour) >> 6) & 0x1F);
bd = (((dcolour) >> 1) & 0x1F);
// Blend using LUT
ra = level->values[rs+rd];
ga = level->values[gs+gd];
ba = level->values[bs+bd];
// Combine colours and set
*coff = ((ra<<11)+(ga<<6)+(ba<<1));
}
coff++; doff++;
}
coff += cstep;
doff += dstep;
}
}

void gp_blitT_16(u16 *sprite,short x, short y, unsigned height, unsigned width, u16 *framebuffer, u16 trans){
unsigned short xx,yy;
unsigned short vw,vh;
unsigned short *doff, *coff;
short dstep, cstep;
unsigned short px,py;
short tx,ty;
unsigned short color;

// If rect is off the screen, exit
if ((x>=LCD_WIDTH) || (y>=LCD_HEIGHT)){ return; }
tx = x+width; ty = y+height;
if ((tx<0) || (ty<0)){ return; }

// The rest of the coordinates are calculated based on a screen rotation
// of 90 degrees clockwise.
ty = y;
y = x;
x = LCD_HEIGHT - ty - height;
tx = x+height; ty = y+width;

// Positional offsets
px = max( 0, x );
py = max( 0, y );
// Visible height
if (y<0){ 
vh = min( ty, LCD_WIDTH );
}else{
if (ty>LCD_WIDTH){
vh = width - (ty-LCD_WIDTH);
}else{
vh = width;
}
}
// Visible width
if (x<0){
vw = min( tx, LCD_HEIGHT );
}else{
if (tx>LCD_HEIGHT){
vw = height - (tx-LCD_HEIGHT);
}else{
vw = height;
}
}
// Data offset
doff = sprite + ( height * max( 0, -y ) ) + max( 0, -x ); //removed +6, no sprite header here.
dstep = height - vw;
// Canvas data offset
coff = framebuffer + (py*LCD_HEIGHT + px);
cstep = LCD_HEIGHT - vw;

// Draw visible pixels only
for ( yy=0; yy<vh; yy++ ){
for (xx=0; xx<vw; xx++ ){
color = *doff;
if (color != trans) {
*coff = color;
}
coff++; doff++;
}
coff += cstep;
doff += dstep;
}
}

void gp_blitH_16(u16 *sprite, short put_x, short put_y, u16 *framebuffer){
unsigned  width, height;
SHEADER *sheader;
sheader = (SHEADER*) sprite;
height = sheader->size_y;
width = sheader->size_x;
gp_blit_16(sprite+6, put_x, put_y, width, height, framebuffer);
}

void gp_blitH_8(unsigned char *sprite, short put_x, short put_y, unsigned char *framebuffer){
unsigned  width, height;
SHEADER *sheader;
sheader = (SHEADER*) sprite;
height = sheader->size_y;
width = sheader->size_x;
gp_blit_8(sprite+12, put_x, put_y, width, height, framebuffer);
}

void gp_blitHA_16(u16 *sprite,short x, short y, u16 *framebuffer, unsigned char alpha){
unsigned  width, height;
SHEADER *sheader;
sheader = (SHEADER*) sprite;
height = sheader->size_y;
width = sheader->size_x;
gp_blitA_16(sprite + 6, x, y, height, width, framebuffer, alpha);
}

void gp_blitHAT_16(u16 *sprite,short x, short y, u16 *framebuffer, u16 trans, unsigned char alpha){
unsigned  width, height;
SHEADER *sheader;
sheader = (SHEADER*) sprite;
height = sheader->size_y;
width = sheader->size_x;
gp_blitAT_16(sprite + 6, x, y, (int) height, (int) width, framebuffer, trans,alpha);
}

void gp_blitHT_16(u16 *sprite,short x, short y, u16 *framebuffer, u16 trans){
unsigned  width, height;
SHEADER *sheader;
sheader = (SHEADER*) sprite;
height = sheader->size_y;
width = sheader->size_x;
gp_blitT_16(sprite + 6, x, y, height, width, framebuffer, trans);
}

void gp_blitTile_16(u16 *sprite, unsigned x_len, unsigned plot_number, short put_x, short put_y, unsigned height, u16 *framebuffer) {
int offset;
offset = plot_number * x_len * height;
gp_blit_16(sprite+offset, put_x, put_y, x_len, height, framebuffer);
}

void gp_blitTile_8(unsigned char *sprite, unsigned x_len, unsigned plot_number, short put_x, short put_y, unsigned height, unsigned char *framebuffer) {
int offset;
offset = plot_number * x_len * height;
gp_blit_8(sprite+offset, put_x, put_y, x_len, height, framebuffer);
}

void gp_blitTileA_16(u16 *sprite, unsigned x_len, unsigned plot_number, short put_x, short put_y, unsigned height, u16 *framebuffer, unsigned char alpha) {
int offset;
offset = plot_number * x_len * height;
gp_blitA_16(sprite+offset, put_x, put_y, x_len, height, framebuffer, alpha);
}

void gp_blitTileT_16(u16 *sprite, unsigned x_len, unsigned plot_number, short put_x, short put_y, unsigned height, u16 *framebuffer, u16 trans) {
int offset;
offset = plot_number * x_len * height;
gp_blitT_16(sprite+offset, put_x, put_y, x_len, height, framebuffer, trans);
}
void gp_blitTileAT_16(u16 *sprite, unsigned x_len, unsigned plot_number, short put_x, short put_y, unsigned height, u16 *framebuffer, u16 trans, unsigned char alpha){
int offset;
offset = plot_number * x_len * height;
gp_blitAT_16(sprite+offset, put_x, put_y, x_len, height, framebuffer, trans, alpha);
}

void gp_blitTileH_16(u16 *sprite, unsigned x_len, unsigned plot_number, short put_x, short put_y,u16 *framebuffer) {
unsigned  width, height;
SHEADER *sheader;
sheader = (SHEADER*) sprite;
height = sheader->size_y;
gp_blitTile_16(sprite+6, x_len, plot_number, put_x, put_y, height, framebuffer);
}

void gp_blitTileH_8(unsigned char *sprite, unsigned x_len, unsigned plot_number, short put_x, short put_y,unsigned char *framebuffer) {
unsigned  width, height;
SHEADER *sheader;
sheader = (SHEADER*) sprite;
height = sheader->size_y;
gp_blitTile_8(sprite+12, x_len, plot_number, put_x, put_y, height, framebuffer);
}

void gp_blitTileHA_16(u16 *sprite, unsigned x_len, unsigned plot_number, short put_x, short put_y,u16 *framebuffer, unsigned char alpha) {
unsigned  width, height;
SHEADER *sheader;
sheader = (SHEADER*) sprite;
height = sheader->size_y;
gp_blitTileA_16(sprite+6, x_len, plot_number, put_x, put_y, height, framebuffer, alpha);
}
void gp_blitTileHT_16(u16 *sprite, unsigned x_len, unsigned plot_number, short put_x, short put_y,u16 *framebuffer, u16 trans) {
unsigned  width, height;
SHEADER *sheader;
sheader = (SHEADER*) sprite;
height = sheader->size_y;
gp_blitTileT_16(sprite+6, x_len, plot_number, put_x, put_y, height, framebuffer, trans);
}
void gp_blitTileHAT_16(u16 *sprite, unsigned x_len, unsigned plot_number, short put_x, short put_y,u16 *framebuffer, u16 trans, unsigned char alpha) {
unsigned  width, height;
SHEADER *sheader;
sheader = (SHEADER*) sprite;
height = sheader->size_y;
gp_blitTileAT_16(sprite+6, x_len, plot_number, put_x, put_y, height, framebuffer, trans, alpha);
}

edit: There will be no 8bit alpha code, with all the trickery involved in every method of doing it, it just isn't worth it, you might as well do it in 16bit.

It is very easy to use your own palette, like this:

Code:
extern u32 my_palette[];
u32 *palette = (u32*) PALETTE;
memcpy(palette,my_palette,256);
 
Last edited by a moderator:
Back
Top