Simple Scalable Fonts

From OSDev Wiki
Jump to navigation Jump to search

So you got a multi-tasking kernel up and running, have created a simple GUI and want to add some sexy scalable fonts. This short tutorial is intended to give you some ideas on how you might want to implement scalable fonts, Drawing In Protected Mode has an example of printing fixed width fonts. This technique uses instruction based drawing to achieve scalable fonts.

The first thing you'll need is some utility functions:

  • PutPixel to plot a pixel
  • PutLine to draw a straight line
  • PutRect to draw a square
  • PutCurve to draw a curve

Assume we want to print a large "A scaled font demo" at 100x100 on the screen using a 25 point font in black:

PrintScaledString(100,100,25,25,"A scaled font demo", rbgBlack);

The PrintScaledString function looks at each character and calls a separate method to render each character. For simplicity's sake I'll only focus on the capital letter 'A'.

void PrintScaledString(int x, int y, int charWidth, int charHeight, char * str, int RGB)
 {
    int charX=x, charY=y;
    while (*str)
    {
       switch (*str)
       {
          case '\n':
              charX=x;
              charY=charY+charHeight;
              break;
          case 'A':
              DrawA(charX, charY, charWidth, charHeight, RGB);
              break;
          case 'B':
              DrawB(charX, charY, charWidth, charHeight, RGB);
          ... call more draw methods here for each character
       }
       if (*str != '\n') charX+=charWidth;
       str++;
    }
 }

You have several options for drawing scalable fonts, but the better looking fonts are more difficult to code. It's not very difficult to code very ugly fonts but if you want quality you'll need some skills. The letter 'A' is very simple:

void DrawA(int x, int y, int charWidth, int charHeight, int RGB
 {
    //first draw a line along the left side:
    PutLine(x, y, x, y+charHeight,RGB);
    //draw a line across the top:
    PutLine(x,y,x+charWidth,y,RGB);
    //draw a line along the right side:
    PutLine(x+charWidth,y,x+charWidth,y+charHeight,RGB);
    //finally close in the box half way up
    PutLine(x,y+(charHeight/2),x+charWidth,y+(charHeight/2),RGB);
 }

The capital 'A' is very simple to render, more complex characters will require more code and calculations. You will probably want to research collision detection, Bezier curves plus Bresenham's line and circle algorithms

Of course hardwiring typeface into a renderer is a very bad idea. You should store the glyphs in data array, and use the combination of the appropriate PutLine(), PutBezier() etc. calls. There are OpenSource libraries to exactly do that, so that you don't have to reinvent the wheel. See Scalable Screen Font which comes with a single ANSI C header implementation and has almost no dependencies.

Alternatively, if you have a functioning C Library for your OS then it may be desirable to port FreeType 2. FreeType 2 supports many different font formats and has it's own fast, high quality font rendering engine that directly draws into bitmaps in memory. FreeType 2 is used as the basis for QT, Atheos, Cairo, and many other GUI projects.