Advertisement

Make this function faster!

Started by February 06, 2000 01:53 PM
6 comments, last by Bigshot 25 years, 1 month ago
int Blit_Text(char *text, int x, int y, LPDIRECTDRAWSURFACE7 lpdds) { int index, // character index numofchars, // # of characters in string cx; // x position in ascii surface RECT character; // holds a 12x12 character...used for blitting // get number of characters in string numofchars = strlen(text); // blit characters one by one for (index = 0; index < numofchars; index++) { // find position of character in surface cx = text[index] * 13 + 1; // setup rectangle character.left = cx; character.top = 1; character.right = cx + 12; character.bottom = 13; // blit helluva fast lpdds->BltFast(x, y, ascii_surface, &character, DDBLTFAST_SRCCOLORKEY / DDBLTFAST_WAIT); // move cursor for next letter x += 12; } // return success return(1); } //////////////////////////////////////////////////////////// Obviously the function blits text, but are there any optimizations to make it even faster? It''s actually pretty fast I guess, and I wrote it all by myself! During initialization the program copies a bitmap that has all the ascii characters to a surface (that''s in a different function). Then in this function it just extracts characters from the surface so that way I can use DirectDraw''s hardware acceleration. It runs fast on my computers, but a poor man with a shitty computer might not appreciate it if the text is too slow. The only potential optimization I can find is using bitshifting to do the multiplication, but I would have to change the size of the text because 13 isn''t a power of 2. Any other ideas? Thanks, Al
Alexbigshot@austin.rr.comFoolish man give wife grand piano. Wise man give wife upright organ.
You aren''t going to shave much off this, but there are a few things you can do - that might be worth it if there is a lot of text in your game. Remember, its never really worth optimizing something that doesn''t get called a lot in a time-critical context!

Here are some ideas.... n refers to the number of characters in the string.

Set character.top and character.bottom outside of the for loop - there is no point in setting it to the same value (numofchars) times. Thats worth around n*2 cycles.

You don''t really need to calculate the text position into cx and then assign it to character.left - you never use cx again, as far as I can see. You can save n cycles with this - although the compiler may well have picked up on it anyway.

If you are really paranoid about the time it takes for an IMUL and an add, you could create a small lookup table for cx (the position of character in surface). If you create the lookup table before the game itself starts, this should be worth n*2 cycles on a Pentium II (more on Pentiums).

Hope that helps!
Advertisement
some pretty trivial stuff....

> for (index = 0; index < numofchars; index++)
change that to ''++index'', it''s technically faster.

> character.left = cx;
> character.top = 1;
> character.right = cx + 12;
> character.bottom = 13;
put the top and bottom assignment outside the loop, it''s a constant.

I''m not totally sure what bltfast is doing, but from what little i know about directx, you''re doing this to a secondary surface then swapping it right? if not, use a secondary surface, blt all the text then swap it. Text might appear a little later, but it will all be in one burst, if that''s what you''re looking for.

Like i said, that''s pretty trival stuff. But it save you a cycle or two.






"That which the flame does not consume...consumes the flame. "
"That which the flame does not consume...consumes the flame. "
That was stupid of me to leave those constants in the loop. I probably forgot to take them out because when I was first writing the function I had to calculate the y position of the characters since the characters were stored in rows and columns, but then I just put all the characters in a single row to make it easier and faster.

Thanks for the advice!
Al
Alexbigshot@austin.rr.comFoolish man give wife grand piano. Wise man give wife upright organ.
Hm. You could perhaps do 2 things not mentioned above...

You could use a pointer instead of your text[index] and use that pointer instead of indirect addressing. So you could simply caclulate the text''s end address and use that as the loop''s exit condition.Then you could increase the pointer directily instead.

The second thing is to unroll the loop. E.g. you could blit 2 characters at once. If the text''s length has not been even then you would have to perform a last blit outdside the loop.

But I think the time U loose/win heavily depends on the time the function call needs. So this may perhaps have no effect on performance

NextS
P.S. I hope someone actually reads this
You could always make the function an inline function.
Advertisement
well, if you get rid of the x, y, and change it to a pointer to a point structure instead, it will lower the number of arguments to 3, few enough to make the function call by register -- if in vc++ add __fastcall to the declaration
that will make a tiny difference, but when performance counts...
-PoesRaven

At the same time that you fill ascii_surface with
your text bitmaps, fill in an array (called
ascii_start below) with the starting x position
of each character. Then try this:

int Blit_Text( const char *text, int x, int y,
LPDIRECTDRAWSURFACE7 lpdds)
{
int index, // character index

RECT character; // holds a 12x12 character...used for blitting
character.top = 1;
character.bottom = 13;

const char *str = text;
// blit characters one by one
while( (index=*str++) ) // loop until character 0 is found
{
// find position of character in surface
character.left = ascii_start[index];
character.right = character.left + 12;

// blit helluva fast
lpdds->BltFast( x, y, ascii_surface, &character,
DDBLTFAST_SRCCOLORKEY / DDBLTFAST_WAIT);

// move cursor for next letter
x += 12;

}

// return success
return(1);
}

This topic is closed to new replies.

Advertisement