Caanoo / WIZ Gaming Wiz Slow With Sdl_Ttf.h


frano486

Still Fresh
Joined
Jun 21, 2009
Messages
4
Age
34
Location
Rome
I wrote a small game in C, like snake, and to keep the score I used the library, the PC version works fine but on wiz slows dramatically, about 2/3fps.
If I comment the code on the score, is about fast as on PC. I tried to compile it with Code::Blocks and devcpp, and use the latest sdl in the archive.
I tried with different fonts, but nothing has changed.
Any ideas?
 
hmn said:
You should post some code.
Code:
void ScoreFunc(int counter, int position) {
    DrawText("Score:",0,0);
    if (counter==0) DrawText("0",position,1);
    if (counter==1) DrawText("1",position,1);
    if (counter==2) DrawText("2",position,1);
    if (counter==3) DrawText("3",position,1);
    if (counter==4) DrawText("4",position,1);
    if (counter==5) DrawText("5",position,1);
    if (counter==6) DrawText("6",position,1);
    if (counter==7) DrawText("7",position,1);
    if (counter==8) DrawText("8",position,1);
    if (counter==9) DrawText("9",position,1);
}
 if(ScoreCount==9) {
            ScoreCount=0;
            if(ScoreD==0) ScorePosU+=8;
                ScoreD+=1;
            //   if(ScoreD==9 && ScoreCount==9) {
            }
        else
            ScoreCount+=1;

     while(!done) {
//
      ScoreFunc(ScoreCount,ScorePosU);
      if (ScoreD>0) ScoreFunc(ScoreD,ScorePosD);
//
}
void DrawText(char *text, int x, int y) {
    TTF_Font *font;
    font=TTF_OpenFont("gfx/font.ttf",12);
    SDL_Color color = { 255, 255, 255 };
    SDL_Rect coordinates;
    coordinates.x = (int)x;
    coordinates.y = (int)y;
    SDL_Surface *message = NULL;
    message=TTF_RenderText_Solid(font,text,color);

    SDL_BlitSurface(message,0,tmp_screen,&coordinates);

    TTF_CloseFont(font);
    SDL_FreeSurface(message);
}
 
Last edited by a moderator:
You should not load the font everytime you draw text!

Just load the font once at the start of your program and then pass it as an argument

Code:
void DrawText( TTF_Font* font, const char* text, int x, int y )
{
   ...
}
 
Also the score function looks a little weird, maybe something like this would be better:

Code:
#include <stdio.h>

// ...

void DrawScore( TTF_Font* font, int score, int x, int y )
{
    char buffer[ 100 ];
    snprintf( buffer, sizeof( buffer ), "Score: %d", score );

    DrawText( font, buffer, x, y );
}
 
Also, if you're using DrawText to blit a bitmap for every character each time, and there's only 10 possible characters, wouldn't it be easier to generate the 10 bitmaps at the start (or whenever that screen is displayed) and then just keep them in memory in case they are needed again. 10 x (say) 20 x 20 monochrome bitmaps isn't going to take an awful lot of memory at all.
 
hmn said:
Also the score function looks a little weird, maybe something like this would be better:

Code:
#include <stdio.h>

// ...

void DrawScore( Font* font, int score, int x, int y )
{
    char buffer[ 100 ];
    snprintf( buffer, sizeof( buffer ), "Score: %d", score );

    DrawText( font, buffer, x, y );
}
Thanks a lot ;)

ledow said:
Also, if you're using DrawText to blit a bitmap for every character each time, and there's only 10 possible characters, wouldn't it be easier to generate the 10 bitmaps at the start (or whenever that screen is displayed) and then just keep them in memory in case they are needed again. 10 x (say) 20 x 20 monochrome bitmaps isn't going to take an awful lot of memory at all.

I also tried with the code of hmn but is still slow <_<
 
Last edited by a moderator:
How slow?

Not loading the font every time should give a BIG speedup. I actually wrote a little benchmark for this:

Loading font every time -> 6 FPS
Loading font just once --> 195 FPS

Code:
#include <SDL.h>
#include <SDL_ttf.h>

#include <assert.h>

const char* fontFilename = "DejaVuSans.ttf";
const int fontSize = 20;

void DrawTextOld( SDL_Surface* screen, char *text, int x, int y) {

  TTF_Font *font;
  //font=TTF_OpenFont("gfx/font.ttf",12);
  font = TTF_OpenFont( fontFilename, fontSize );
  SDL_Color color = { 255, 255, 255 };
  SDL_Rect coordinates;
  coordinates.x = (int)x;
  coordinates.y = (int)y;
  SDL_Surface *message = NULL;
  message=TTF_RenderText_Solid(font,text,color);

  SDL_BlitSurface(message,0,screen,&coordinates);

  TTF_CloseFont(font);
  SDL_FreeSurface(message);
}

void DrawTextNew( SDL_Surface* screen, TTF_Font* font, char *text, int x, int y) {

  //TTF_Font *font;
  //font=TTF_OpenFont("gfx/font.ttf",12);
  SDL_Color color = { 255, 255, 255 };
  SDL_Rect coordinates;
  coordinates.x = (int)x;
  coordinates.y = (int)y;
  SDL_Surface *message = NULL;
  message=TTF_RenderText_Solid(font,text,color);

  SDL_BlitSurface(message,0,screen,&coordinates);

  //TTF_CloseFont(font);
  SDL_FreeSurface(message);
}

void DrawText( SDL_Surface* screen, TTF_Font* font, char *text, int x, int y, int old ) {

  if( old )
    DrawTextOld( screen, text, x, y );
  else 
    DrawTextNew( screen, font, text, x, y );
}

int main( int argc, char** argv )
{
  assert( !SDL_Init( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK ) );
  assert( SDL_JoystickOpen( 0 ) );
  SDL_Surface* screen = SDL_SetVideoMode( 320, 240, 0, SDL_SWSURFACE );
  assert( screen );
  assert( !TTF_Init() );

  TTF_Font* font = TTF_OpenFont( fontFilename, fontSize );
  assert( font );
  
  int old = 1;
  Uint32 ticks0 = SDL_GetTicks();
  Uint32 ticks = 0;
  Uint32 frames = 0;
  Uint32 fps = 0;
  
  for( ;; ) {
    
    int run = 1;
    SDL_Event e;
    while( SDL_PollEvent( &e ) ) {
      
      if( e.type == SDL_QUIT ) {

	run = 0;
      }
      else if( e.type == SDL_JOYBUTTONDOWN ) {
	
	if( e.jbutton.button == 8 ) {
	  
	  run = 0;
	}
	else if( e.jbutton.button == 9 ) {

	  old = old ? 0 : 1;
	}
      }
    }
    if( !run )
      break;

    SDL_FillRect( screen, 0, 0 );

    const int x = 16;
    int y = 16;

    DrawText( screen, font, "Press menu to quit", x, y, old );
    y += 30;
    DrawText( screen, font, "Press select to change routine", x, y, old );
    y += 30;
    DrawText( screen, font, old ? "Old routine" : "New routine", x, y, old );
    y += 30;
    
    char buffer[ 100 ];
    snprintf( buffer, sizeof( buffer ), "FPS: %d", fps );
    DrawText( screen, font, buffer, x, y, old );
         
    SDL_Flip( screen );

    frames++;

    Uint32 ticks1 = SDL_GetTicks();
    ticks += ticks1 - ticks0;
    ticks0 = ticks1;
    if( ticks >= 1000 ) {
      
      fps = ( 1000 * frames ) / ticks;
      ticks = 0;
      frames = 0;
    }
  }

  TTF_Quit();
  SDL_Quit();

  return 0;
}
 
I have to agree - if a simple blit of a pre-rendered bitmap takes "too long" you're doing something enormously wrong or doing it far too many times. If a simple rendering of a text item into a bitmap takes "too long" then you're still doing something crazy somewhere.

I wrote STPPC2x using SDL_TTF and it's been ported to Wiz, Dingoo, etc. without any changes to the code. It has games that blit text all over the place, completely unoptimised and out of my control because the games are written mostly by other people for other operating systems, and it even uses the exact same routines to "draw" all the menus in realtime (i.e. the menus are literally redrawn by SDL_RenderTextBlended - which is MUCH slower than RenderTextSolid because it does alpha-blending on a 32-bit surface - line-by-line, on top of a black bitmap covering the screen every time the user selects the next option, etc.). In-game you don't notice a thing, it just looks like a smooth window and that's on a 200MHz GP2X.

Something is wrong here... Open the font in the right size at the beginning of the program (OpenFont), don't close it until the end of the program (CloseFont) then render (RenderText) from that font to a bitmap (fresh or not, it doesn't matter) and then blit (BlitSurface) that bitmap to the screen somehow. You shouldn't be resizing those bitmaps, you shouldn't be closing the font, you barely even need to bother with getting that blitted surface into the right display format first or anything. You should be able to do hundreds if not thousands of calls a second without hitting performance issues at all. You're either doing this millions of times and not realising, constantly re-opening the font file, or rendering every character on the screen separately somehow.
 
P.S. In your routine you should also be filling out the coordinates of the blitting rectangle h/w as "0" if you're not using them - otherwise they just assume the value of whatever was in memory before them and you could end up with completely invalid, invisible or huge blitting rectangles. Any uninitialised values like that can really mess your program up. Over-initialising something will never cause you a problem. Under-initialising will (notice also that your SDL_Color is actually three elements instead of the four specified in the SDL headers, but that one will pass relatively unnoticed, I think). Explicitly zero your blitting rectangle height/width each time.

Your DrawText should be nothing more than:

Code:
void DrawText(char *text, int x, int y, TTF Font *font, SDL_Color color) {
    SDL_Rect coordinates;
    coordinates.x = (int)x;
    coordinates.y = (int)y;
    coordinates.w = 0;
    coordinates.h = 0;

    SDL_Surface *message = NULL;
    message=TTF_RenderText_Solid(font, text, color);
    SDL_BlitSurface(message,0,tmp_screen,&coordinates);
    SDL_FreeSurface(message);
}
everything else should be in your initialisation and/or shutdown routines.
 
It's also a good idea to call SDL_DisplayFormat on newly created surfaces, the TTF_RENDER* functions create a new surface, however i'm not certain if they call it themselves or not .. might be worth trying it out... This applies to loading assets like sprites (so basically images) as well.. otherwise you'll get a serieus performance impact...
 
Remember, try avoiding use a excessive I/O on disk (SD), is slow... doing a "Initializing" method (try loading almost on startup) is always a good practice :) (being aware of high RAM usage of course)
 
Back
Top