The SDL forums have moved to discourse.libsdl.org.
This is just a read-only archive of the previous forums, to keep old links working.


SDL Forum Index
SDL
Simple Directmedia Layer Forums
Performance question about font rendering
BadManiac


Joined: 07 Aug 2014
Posts: 7
I'm working on porting features from my old software blitting library to SDL 2.0 for a hobby project, and I've gotten to font rendering. Yes I'm aware of the available TTF library but where's the fun in that?
In my old library, which was written in assembler, mostly using 64 bit MMX instructions, simply used the classic bitmap font idea where you have a surface containing all the glyphs, and blit them one by one as you traverse the string you want to print. I understand that this is potentially a waste of performance when it comes to hardware accelerated textures? So what are my options?

Should I not create textures with the complete glyph sets, and then use SDL_RenderCopy once per character to print?
Is the only reasonably fast way to do what the TTF lib does and blit the complete string to a texture, and then copy the complete text each time?
How should I go about creating that texture? Use SDL surface with all the glyphs, SDL_BlitSurface the entire strring to a surface and creating a texture from that? (That sounds horribly inefficient to me)
Or can I use a texture with the glyphs, SDL_RenderCopy each character in the string to the final text texture, and then RenderCopying that each frame?

Is there any way to do it "the old way" and render each character every frame and maintain performance?
MrTAToad


Joined: 13 Feb 2014
Posts: 205
Location: Chichester, England
Using a sprite sheet with all characters held in them, and then displaying each character works fine as long as you dont need too many, by which I mean several hundred.

For optimal performance, it would be better to put all text in each line (or sentence) into one texture, which would require knowing what text to display in advance.
BadManiac


Joined: 07 Aug 2014
Posts: 7
That sounds promising, I thought doing that was a complete performance killer in hardware.
MrTAToad


Joined: 13 Feb 2014
Posts: 205
Location: Chichester, England
This is my sprite text routine :

Code:
DGNat    __GLBASIC__::PRINTPROFONT(const DGStr& text,DGInt x,DGInt y,DGInt angle,DGInt xScale,
                           DGInt yScale, DGNat shadowX, DGNat shadowY,
                           DGNat textColour,DGNat shadowColour)
{
DGNat one,loop,charLoop,amount;
SDL_Rect destRect;
//DGInt xPos,yPos,cWidth,cHeight;
DGNat vX, vY, vW, vH;
DGNat sprite;
SDL_Color tempF;

   GETVIEWPORT(vX, vY, vW, vH);

   try {
      if (__CURRENTPROFONT < 0 || __CURRENTPROFONT >= BOUNDS(proFonts, 0)) throw(CMP_INVALID_INDEX);
      if (LEN(text) == 0) return true;

      amount = (shadowX != 0 || shadowY != 0 ? 2 : 1);

      tempF = foreColour.colour;

      for (charLoop = 0; charLoop < amount; charLoop++)
      {
         destRect.x = (DGNat) (x + (charLoop == 0 && amount == 2 ? shadowX : 0));
         destRect.y = (DGNat) (y + (charLoop == 0 && amount == 2 ? shadowY : 0));

         SETCOLOUR((charLoop == 0 && amount == 2 ? shadowColour : textColour));
         for (loop = 0; loop < LEN(text); loop++)
         {
            sprite = NOT_FOUND;
            one = ASC(MID_Str(text, loop, 1));
            if (one >= 1 && one <= 9)
            {
               sprite = proFontSprites[one - 1];
               if (sprite >= 0)
               {
                  GETSPRITESIZE(sprite, destRect.w, destRect.h);
               }
               else
               {
                  destRect.w = 0;
                  destRect.h = 0;
               }
            }
            else
            {
               destRect.w = (DGNat) PROFONTWIDTH(__CURRENTPROFONT, xScale, one);
               destRect.h = (DGNat) PROFONTHEIGHT(__CURRENTPROFONT, yScale, one);

               if (one == 10 || one == 13)
               {
                  destRect.y += destRect.h;                  
                  destRect.x = (DGNat)(x + (charLoop == 0 && amount == 2 ? shadowX : 0));
                  continue;
               }
            }

            if ((destRect.y + destRect.h >= 0) && (destRect.y <= vH) &&
               (destRect.x + destRect.w >= 0) && (destRect.x <= vW))
            {
               if (useBackground)
               {
                  __DRAWBACKGROUND(&destRect);
               }

               if (sprite!=NOT_FOUND)
               {
                  DRAWSPRITE(sprite, (DGInt) destRect.x, (DGInt) destRect.y);
               }
               else
               {
                  one -= proFonts(__CURRENTPROFONT).startingChar;
                  if (one >= 0 && one < proFonts(__CURRENTPROFONT).numChars)
                  {
                     __DRAWSPRITE(&proFonts(__CURRENTPROFONT).sprite, SCALE, one,
                                 (DGInt) destRect.x, (DGInt) destRect.y,
                                 0.0, xScale, yScale);
                  }
               }               
            }

            destRect.x += destRect.w;
         }
      }

      foreColour.colour = tempF;
      return true;
   }
   catch (DGNat error)
   {
      __Error(error);
      return false;
   }
}