Custom BMP font engine

Last night I threw this together as a custom BMP font displayer that I could use in a game I’m working on. The BMP file has already been loaded onto a surface “pFont12g”. The BMP was 12px high and 10px wide per letter. The image starts with a blank space ASCII 32 and goes up to ASCII 126. The function scans each character of the string submitted to be displayed and sets the x pos of the Src Rect based on the ASCII value. I also check for ‘\n’ and effectively create a newline. It works really well, but I’m wondering if there is a faster way to do this? I’m also a little shaky with pointers, so I created a duplicate of the message and manipulate that rather than accidentally frying the original (is this needed or just my own fear?).

I was hoping you folks might have an insight or two.

drawMsg(pMainSurface,strMsg,x,y);

void drawMsg(SDL_Surface * surface, const char * message, Sint16 x, Sint16 y)
{
const char * msg = message;
setRect(&rSrc,0,0,10,12);
setRect(&rDest,x,y,10,12);
for(int i=0;i<strlen(message);i++)
{
if((Uint8)*msg>=32 && (Uint8)*msg<=126)
{
rSrc.x=((Uint8)*msg-32)*10;
SDL_BlitSurface(pFont12g,&rSrc,surface,&rDest);
rDest.x+=10;
}
else if((Uint8)*msg==’\n’)
{
rDest.y+=12;
rDest.x=x;
}
msg++;
}
}

Thanks!

  • Joby
    http://jobybednar.com
    Give someone a program - frustrate them for a day.
    Teach them how to program - frustrate them for a lifetime.

Joby Bednar wrote:

Last night I threw this together as a custom BMP font displayer that I could use in a game I’m working on. The BMP file has already been loaded onto a surface “pFont12g”. The BMP was 12px high and 10px wide per letter. The image starts with a blank space ASCII 32 and goes up to ASCII 126. The function scans each character of the string submitted to be displayed and sets the x pos of the Src Rect based on the ASCII value. I also check for ‘\n’ and effectively create a newline. It works really well, but I’m wondering if there is a faster way to do this? I’m also a little shaky with pointers, so I created a duplicate of the message and manipulate that rather than accidentally frying the original (is this needed or just my own fear?).

Nope, isn’t strictly necessary. Modifying the pointer inside your function won’t modify it outside of it; it is a local variable in the same way that ‘Sint16 x’ is a local variable. The memory pointed to is NOT local, of course, but the pointer ITSELF is. And you’re protected from writing to the memory pointed to message anyhow, since it’s a CONST char *… the compiler won’t let you write to that memory without a type-cast.

It’s still a good idea to keep message unmodified, though, in case you decide to tack some more code onto the bottom of that, and want to use message again… Otherwise you could be scratching your head for hours wondering why your strings are always blank. :slight_smile:

As for your code, I can’t see too many ways to improve it… mebbe store strlen(message) in a local variable, so you’re not measuring the length of the string every loop? That’d be a negligible performance increase tho. Also make sure you’re converting the surfaces to display format.> drawMsg(pMainSurface,strMsg,x,y);

void drawMsg(SDL_Surface * surface, const char * message, Sint16 x, Sint16 y)
{
const char * msg = message;
setRect(&rSrc,0,0,10,12);
setRect(&rDest,x,y,10,12);
for(int i=0;i<strlen(message);i++)
{
if((Uint8)*msg>=32 && (Uint8)*msg<=126)
{
rSrc.x=((Uint8)*msg-32)*10;
SDL_BlitSurface(pFont12g,&rSrc,surface,&rDest);
rDest.x+=10;
}
else if((Uint8)*msg==’\n’)
{
rDest.y+=12;
rDest.x=x;
}
msg++;
}
}

Thanks!

  • Joby
    http://jobybednar.com
    Give someone a program - frustrate them for a day.
    Teach them how to program - frustrate them for a lifetime.

SDL mailing list
SDL at libsdl.org
http://www.libsdl.org/mailman/listinfo/sdl

At 2003-01-30 01:16, you wrote:

Last night I threw this together as a custom BMP font displayer that I
could use in a game I’m working on. The BMP file has already been loaded
onto a surface “pFont12g”. The BMP was 12px high and 10px wide per
letter. The image starts with a blank space ASCII 32 and goes up to ASCII
126. The function scans each character of the string submitted to be
displayed and sets the x pos of the Src Rect based on the ASCII value. I
also check for ‘\n’ and effectively create a newline. It works really
well, but I’m wondering if there is a faster way to do this? I’m also a
little shaky with pointers, so I created a duplicate of the message and
manipulate that rather than accidentally frying the original (is this
needed or just my own fear?).

What I did in my game is something similar. However, I added an array of
character widths, so effectively I created a proportional font (depending
on the way you use the font it may be an improvement or not).

To get one, you can (for example) scan each vertical line of pixels for
each character, to see the vertical line that contains the last pixels,
then that is the width of that character. Something like this (very quickly
written pseudo-code, but you get the idea):
for (ch=32;ch<126;ch++)
{
charwidth[ch]=0;
for (x=0;x<max_char_width;x++)
for (y=0;y<char_height;y++)
if (pixel_in_char(ch,x,y) != blank)
charwidth[ch]=x;
}

Note that you might want to take special care of the space to make sure it
doesn’t end up as zero-length. In addition I tweaked my code to display all
digits at the same width. (Actually, I have prepared the character widths
and just read them from a datafile).

    const char * msg = message;
    setRect(&rSrc,0,0,10,12);
    setRect(&rDest,x,y,10,12);
    for(int i=0;i<strlen(message);i++)

You can change the ‘for’ to:
while (*msg)
it is more efficient than checking strlen every loop, and easier than
storing the strlen() value beforehand… The rest looks pretty decent.

Maarten.