GP32 Speed Problem With Sprites


0-bake

Active Member
Joined
Dec 15, 2003
Messages
538
hi,

i have done some font-functions for my game and because of that i adapted some of mirkos functions.
i wanted to cut out sprites (letters) from a big image (320x200). i began to like this whole thing and wrote a "mysprites.h", because i like to have my own functions ;)

but the problem is a massive speed decrease by using the "new" PutSprite function and i really can't see why.
maybe some of you "real" coders can help me a little....

heres the whole mysprites.h:
Code:
#ifndef MYSPRITES_H
#define MYSPRITES_H

#include "string.h"

typedef struct {
 u16 *source_img;
 short source_x;
 short source_y;
 short width;
 short height;
 u16 trans;
} tSprite;

typedef struct {
 tSprite Letter[88];
} tFont;

void SetSprite(tSprite *sprite,u16 *source_img,u16 trans,short source_x,short source_y,short width,short height)
{
 sprite->source_img=source_img;
 sprite->source_x=source_x;
 sprite->source_y=source_y;
 sprite->width=width;
 sprite->height=height;
 sprite->trans=trans;
}

void PutSprite(tSprite sprite,float plotx, float ploty,u16 *framebuffer)
{
 SHEADER *sheader;
 sheader = (SHEADER*)sprite.source_img;
 u16 tiled_x = sheader->size_x;
 int y,x,offset;
 offset = 0;
 for (y=sprite.source_y;y<sprite.height+sprite.source_y;y++)
 for (x=sprite.source_x;x<sprite.width+sprite.source_x;x++) 
 {
  if ( (x-sprite.source_x+plotx>=0) && (x-sprite.source_x+plotx<320) && (y-sprite.source_y+ploty>=0) && (y-sprite.source_y+ploty<240) ) 
  {
   u16 point = sprite.source_img[6+x+offset+(y*tiled_x)];
   if (point != sprite.trans) gp_drawPixel16(x-sprite.source_x+plotx,y-sprite.source_y+ploty, point, framebuffer);
   }
 }
}

void FontOutXY(tFont font,short x,short y,char text[],u16 color,u16 *framebuffer)
{
 short length=strlen(text);
 short i;
 short num=0;
 short dist=0;
 for (i=0;i<length;i++)
 {
  if (text[i]=='A') num=0;
  if (text[i]=='B') num=1;
  if (text[i]=='C') num=2;
  if (text[i]=='D') num=3;
  if (text[i]=='E') num=4;
  if (text[i]=='F') num=5;
  if (text[i]=='G') num=6;
  if (text[i]=='H') num=7;
  if (text[i]=='I') num=8;
  if (text[i]=='J') num=9;
  if (text[i]=='K') num=10;
  if (text[i]=='L') num=11;
  if (text[i]=='M') num=12;
  if (text[i]=='N') num=13;
  if (text[i]=='O') num=14;
  if (text[i]=='P') num=15;
  if (text[i]=='Q') num=16;
  if (text[i]=='R') num=17;
  if (text[i]=='S') num=18;
  if (text[i]=='T') num=19;
  if (text[i]=='U') num=20;
  if (text[i]=='V') num=21;
  if (text[i]=='W') num=22;
  if (text[i]=='X') num=23;
  if (text[i]=='Y') num=24;
  if (text[i]=='Z') num=25;
  if (text[i]=='0') num=26;
  if (text[i]=='1') num=27;
  if (text[i]=='2') num=28;
  if (text[i]=='3') num=29;
  if (text[i]=='4') num=30;
  if (text[i]=='5') num=31;
  if (text[i]=='6') num=32;
  if (text[i]=='7') num=33;
  if (text[i]=='8') num=34;
  if (text[i]=='9') num=35;
  if (text[i]=='(') num=36;
  if (text[i]=='{') num=37;
  if (text[i]=='[') num=38;
  if (text[i]==']') num=39;
  if (text[i]=='}') num=40;
  if (text[i]==')') num=41;
  if (text[i]=='<') num=42;
  if (text[i]=='>') num=43;
  if (text[i]=='.') num=44;
  if (text[i]=='!') num=45;
  if (text[i]==';') num=46;
  if (text[i]==':') num=47;
  if (text[i]=='?') num=48;
  if (text[i]=='_') num=49;
  if (text[i]=='=') num=50;
  if (text[i]=='"') num=51;
  if (text[i]=='+') num=52;
  if (text[i]=='-') num=53;
  if (text[i]==' ') num=54;
  PutSprite(font.Letter[num],x+dist,y,framebuffer);
  dist=dist+font.Letter[num].width+1;
 }
}

#endif


edit:
oh, i have just recognized that the slowdowns in the game and the split screen are caused by this functions. if i use the "normal" gp_drawSpriteHT, i have no slowdowns and no split screen at all. -> http://www.gp32x.de/board/index.php?act=S...t=0#entry261167
 
Last edited by a moderator:
hi,

you cant have more than 1 caractere by I in your FontOutXY, so i suggess you to use:

for (i=0;i<length;++i)
{
switch (text)
{
case 0: num=0; break;
case 1: num=1; break;
.
.
.
}
PutSprite(font.Letter[num],x+dist,y,framebuffer);
dist=dist+font.Letter[num].width+1;
}
}

it's faster than your testing all letter :)
but for me it's not a good way :) i prefere to use ASCII norme to display caractere , it's easier :)

here a little part of ASCII table:
= 32 - 0x20 - 040 - %00100000
! = 33 - 0x21 - 041 - %00100001
" = 34 - 0x22 - 042 - %00100010
# = 35 - 0x23 - 043 - %00100011
$ = 36 - 0x24 - 044 - %00100100
% = 37 - 0x25 - 045 - %00100101
& = 38 - 0x26 - 046 - %00100110
' = 39 - 0x27 - 047 - %00100111
( = 40 - 0x28 - 050 - %00101000
) = 41 - 0x29 - 051 - %00101001
* = 42 - 0x2A - 052 - %00101010
+ = 43 - 0x2B - 053 - %00101011
, = 44 - 0x2C - 054 - %00101100
- = 45 - 0x2D - 055 - %00101101
. = 46 - 0x2E - 056 - %00101110
/ = 47 - 0x2F - 057 - %00101111
0 = 48 - 0x30 - 060 - %00110000
1 = 49 - 0x31 - 061 - %00110001
2 = 50 - 0x32 - 062 - %00110010
3 = 51 - 0x33 - 063 - %00110011
4 = 52 - 0x34 - 064 - %00110100
5 = 53 - 0x35 - 065 - %00110101
6 = 54 - 0x36 - 066 - %00110110
7 = 55 - 0x37 - 067 - %00110111
8 = 56 - 0x38 - 070 - %00111000
9 = 57 - 0x39 - 071 - %00111001
: = 58 - 0x3A - 072 - %00111010
; = 59 - 0x3B - 073 - %00111011
< = 60 - 0x3C - 074 - %00111100
= = 61 - 0x3D - 075 - %00111101
> = 62 - 0x3E - 076 - %00111110
? = 63 - 0x3F - 077 - %00111111
@ = 64 - 0x40 - 0100 - %01000000
A = 65 - 0x41 - 0101 - %01000001
B = 66 - 0x42 - 0102 - %01000010
C = 67 - 0x43 - 0103 - %01000011
D = 68 - 0x44 - 0104 - %01000100
E = 69 - 0x45 - 0105 - %01000101
F = 70 - 0x46 - 0106 - %01000110
G = 71 - 0x47 - 0107 - %01000111
H = 72 - 0x48 - 0110 - %01001000
I = 73 - 0x49 - 0111 - %01001001
J = 74 - 0x4A - 0112 - %01001010
K = 75 - 0x4B - 0113 - %01001011
L = 76 - 0x4C - 0114 - %01001100
M = 77 - 0x4D - 0115 - %01001101
N = 78 - 0x4E - 0116 - %01001110
O = 79 - 0x4F - 0117 - %01001111
P = 80 - 0x50 - 0120 - %01010000
Q = 81 - 0x51 - 0121 - %01010001
R = 82 - 0x52 - 0122 - %01010010
S = 83 - 0x53 - 0123 - %01010011
T = 84 - 0x54 - 0124 - %01010100
U = 85 - 0x55 - 0125 - %01010101
V = 86 - 0x56 - 0126 - %01010110
W = 87 - 0x57 - 0127 - %01010111
X = 88 - 0x58 - 0130 - %01011000
Y = 89 - 0x59 - 0131 - %01011001
Z = 90 - 0x5A - 0132 - %01011010
[ = 91 - 0x5B - 0133 - %01011011
\ = 92 - 0x5C - 0134 - %01011100
] = 93 - 0x5D - 0135 - %01011101
^ = 94 - 0x5E - 0136 - %01011110
_ = 95 - 0x5F - 0137 - %01011111
` = 96 - 0x60 - 0140 - %01100000

to have all google is your friend ;)
 
thanks, but the font-function isn't the problem at all.
the problem seems to be in the PutSprite, because putting sprites this way is much slower than the gp_putSpriteHT and i don't know why. and causes slowdowns and splitscreens after a while.

thx anyways
 
Yup, if you really need to translate a character to a number, I would recommend a translation table rather than using an huge amount of 'if' or 'case' statements...

unsigned char xlate[256] = {0,0,0,0,0,0... 1,2,3... mapping for each character ... };

As for your slowness, well your doing a comparison and function call for every single pixel, which is going to soak up major processing time. You don't need to do the comparison ever time (just do it at the beginning), and you certainly don't need the function call either - it can be made inlined.

Finally, the split screen is usually caused because you are modifying the lcd start address without waiting for the vblank - probably the cause of an incorrectly written double buffering routine.
 
As for your slowness, well your doing a comparison and function call for every single pixel, which is going to soak up major processing time. You don't need to do the comparison ever time (just do it at the beginning), and you certainly don't need the function call either - it can be made inlined.

i don't get it. can you explain what you mean in other words?
if i put a sprite with my PutSprite, what do i have to do just one time?
 
You are doing the following condition every time you plot a pixel:

Code:
 if ( (x-sprite.source_x+plotx>=0) && (x-sprite.source_x+plotx<320) && (y-sprite.source_y+ploty>=0) && (y-sprite.source_y+ploty<240) )

This is bad - it's 4 conditions that must be evaluation for every pixel draw (and probably more inside the the gp_drawPixel16 routine, which you should also remove), and so will soak up *lots* of processor time. You need to find a way for your routine not to use this, and instead to calculate it before hand (before entering the loop).

If you need an example of this, have a look at my BOR port - I rewrote a lot of the sprite drawing routines to use up less memory, and calculated a lot of the conditions before actually entering a loop to draw the sprite. It may also give you an idea of how to compress your sprites, so that they take up less room in memory (I'm not sure if compression was actually in my last release, but It'll be in one of them).
 
ok, i give up. i wanted to make a getsprite and putsprite routine like that, because i like to handle sprites this way (and i learned it in a similar way, 10 years ago..).

basically, i just want to have my sprites in the form i posted above.
for example an explosion: tSprite: Explosion[10];
-> a explosion animation with 10 pics and i can easily get this an screen like PutSprite(Explosion[AnimationNumber],x,y);

the "normal" way that was explained to me to include graphics with devkitpro was, to include the bmp-file (wich is converted automatically into the .h-file which i include).

but going this way, i would have (for my explosion-example) 10 single sprites, named like: Explosion1, Explosion2,....
so i can't animate them anymore, like i could animate an array of sprites (Explosion[AnimationNumber]);

or how can i solve this problem? how are you doing this? the problem is that i actually can't speak any c, i just can do pascal (and that was many years ago).
 
if you have something like:

tSprite explosion1;
tSprite explosion2;
tSprite explosion3;

you can do:

tSprite ExplositionSprite[3];
ExplosionSprite[0] = &explosion1;
ExplosionSprite[1] = &explosion2;
ExplosionSprite[2] = &explosion3;

then ExplosionSprite is your animated version.

Normally though, I just load the sprites directly from files, rather than #include'ing them.
 
thx for that.
but: for the font-thing it is very very complicated to have a single file for every letter and other characters. so i thought, it is much easier to cut out the letters from an image, which contains all.
otherwise, if you would like to change some colors or whatever, you would have to edit 80 single files instead of just one.

and what do you mean by "loading directly from files"? that is exactly what i was looking for the whole time, but many users in #gp32dev said, it is very complicated. if it is easily possible, you can load an big image, cut out the sprites you need, and free the image.
 
JyCet posted on Aug 20 2005 at 08:45 PM said:
Complicate ?
Use the tile methode, you can display a little part of one picture

that is exactly the topic of this thread and the main problem i posted ;)
 
Last edited by a moderator:
For a font, I wouldn't bother making up loads of little sprites for each of the characters, I would instead have them in a single bitmap, and then copy directly from this bitmap to the screen in your font printing routine.

File loading is very easy - you just basically open the file, read the contents into memory, and then close the file. There's no need to release the memory, as you can easily just copy the characters required directly to the screen buffer, rather than building up all the sprites, and then releasing.

If you using Mirko's SDK, then have a look at fopen, fread, fclose, etc.
 
For a font, I wouldn't bother making up loads of little sprites for each of the characters, I would instead have them in a single bitmap, and then copy directly from this bitmap to the screen in your font printing routine.
Code:
but my letters have different sizes, so i would have to write a line with the coordinates of the letter in the bitmap every time i print it to the screen.
putting them in sprites is easier, because i just hve to do this one time at the beginning of my game.
 
In line with my policy of letting other people do the hard work I learned to love the existing blit functions.
For displaying fonts - create one long bitmap the height of the character set, containing all printable characters in ASCII order. All chars have to be the same width. ( I use Gp32Converter to create a source file and include it. But each to their own)
You can then write a short print function that takes a string and coordinates. For each character in the string subtract 32 (cos its ascii and the graphic starts at 'space'), multiply by the width of one of your graphic chars (assuming fixed width font) and use the result as an x offset into the bitmap for the blit function.
 
if you have something like:

tSprite explosion1;
tSprite explosion2;
tSprite explosion3;

you can do:

tSprite ExplositionSprite[3];
ExplosionSprite[0] = &explosion1;
ExplosionSprite[1] = &explosion2;
ExplosionSprite[2] = &explosion3;

then ExplosionSprite is your animated version.

this gives me a warning for every line: assignment from incompatible pointer type
but why? it is working, but i don't understand the warning

edit:
and i have to say:
tSprite *Explosion[3]=&explosion1;

otherwise the program crashes and the compiler gives a other warning: assignment makes integer from pointer without a cast
 
I think it should read tSprite *ExplositionSprite[3]; rather than tSprite ExplositionSprite[3];
 
Yup, I missed a rather important asterisk in my code there - sorry!

As for your character problem, the way I get around that is I have every character starting at a multipliable place in the bitmap (eg. every 10 pixels or so a new character starts), and then I have a certain color at the end of it. The program looks for this color to know the size of each character. This is done at the start of the program to increase performance for later on. All the highs of the characters are exactly the same.

Alternatively, you could just make the widths all the same, like digitaljez says, but I don't think this looks as good.
 
ok, but what about the warning, the compiler gives me. i mean the warning, i posted in my last post.
i mean, even if i don't have to care about them, it gets very confused. especially if i have to some real errors and have to find them in dozens of these warnings :(
 
Adding the asterisk should remove the warnings. Most compilers allow you to turn warnings off but I would stongly advise against it - they can be very helpful.

Squidge - Are you are saying you use a marker in the bitmap to generate a kerning table for proportional fonts ? That is a cool idea. The first program I wrote when I got my GP32 last xmas (Bocket - listed as Bocked Docket in the downloads ??) uses a proportional font and I painstakingly created the offsets in a data array. Could have saved myself the effort and added a useful function - Damn! Come to think of it The Wub mentioned a similar sounding system that uses an extra line (undisplayed) in the graphic font to record the widths.
 
hm, i've added the asterisk already, when i posted that i get the warning.

it's now;

tSprite *explo[10];
Explo[0] = &explo1;

warning: assignment from incompatible pointer type;

btw: explo1 is from a bitmap, i included.
the explo1.h contains:

extern const u32 Spr_Ex1_end[];
extern const u8 Spr_Ex1[];
extern const u32 Spr_Ex1_size[];

so i guess, the picture information is u8 Spr_Ex1[];

my original code is:

include "Spr_Ex1.h"

u8 *Explosion[10];

and in main()

Explosion[0]=&Spr_Ex1;

or am i doing something asically wrong?
 
Back
Top