# Making fonts in GLFW

**URL:** <https://discourse.glfw.org/t/making-fonts-in-glfw/490>\
**Category:** support\
**Created:** [August 24, 2008, 2:21pm UTC](https://discourse.glfw.org/t/making-fonts-in-glfw/490 "2008-08-24T14:21:35Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex035/uploads/glfw/original/1X/b8cdefe6b61b8d5aee6c43b2c56e9cf5eabecfe4.svg) [@system](https://discourse.glfw.org/u/system)\
**Post date:** [August 24, 2008, 2:21pm UTC](https://discourse.glfw.org/t/making-fonts-in-glfw/490/1 "2008-08-24T14:21:35Z")

</div>

**[uthegental](https://sourceforge.net/u/uthegental/)** wrote on [Sunday, August 24, 2008](https://sourceforge.net/p/glfw/discussion/247562/thread/cc5f9a19/#6061):

I have read in this forum that it is possible to modify GLFW to use fonts under windows. Could somone tell me how to do that?

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex035/uploads/glfw/original/1X/b8cdefe6b61b8d5aee6c43b2c56e9cf5eabecfe4.svg) [@system](https://discourse.glfw.org/u/system)\
**Post date:** [May 14, 2009, 10:35pm UTC](https://discourse.glfw.org/t/making-fonts-in-glfw/490/2 "2009-05-14T22:35:07Z")

</div>

**[nexekho](https://sourceforge.net/u/nexekho/)** wrote on [Thursday, May 14, 2009](https://sourceforge.net/p/glfw/discussion/247562/thread/cc5f9a19/#6061/e1c1):

I have a fairly simple function that generates 256 display lists, one for each character, from a 512x512 texture automatically doing crude spacing. It’s currently hardcoded to interface/font.tga but it’s pretty easy to use. You interested?

[code]  
uint8\_t ui8CharacterOffsetA[256];  
uint8\_t ui8CharacterOffsetB[256];  
uint8\_t ui8CharacterWidth[256];

GLuint gluiFont = 0;  
GLuint gluiCharacter[256];

void RenderSingleLineTextRight( char \* cText, uint8\_t ui8Characters, uint16\_t ui16Width );  
void RenderSingleLineTextCentred( char \* cText, uint8\_t ui8Characters, uint16\_t ui16Width );  
void RenderSingleLineText( char \* cText, uint8\_t ui8Characters, uint16\_t ui16Width );  
void RenderText( char \* cText, uint8\_t ui8Characters );

uint8\_t InitFont( void );  
void TerminateFont( void );  
[/code]

[code]  
void RenderSingleLineTextRight( char \* cText, uint8\_t ui8Characters, uint16\_t ui16Width )  
{

```
glPushMatrix\(\);

    glBindTexture\( GL\_TEXTURE\_2D, gluiFont \);

    uint8\_t ui8MyCharacter = ui8Characters - 1;

    uint8\_t ui8EscapeWidth = \( ui8CharacterWidth\[46 \] \* 3 \) + 6;
    uint16\_t ui16Progress = 0;
    uint8\_t ui8CharactersToDraw = ui8Characters;

    while\( ui8MyCharacter &lt; UINT8\_MAX \)
    \{

        if\( \( ui16Width - ui16Progress \) - ui8CharacterWidth\[\( uint8\_t \) cText\[ ui8MyCharacter \] \] &lt; ui8EscapeWidth \)
        \{

            ui16Progress += ui8EscapeWidth;

            ui8MyCharacter = UINT8\_MAX;

        \}
        else
        \{

            ui16Progress += ui8CharacterWidth\[\( uint8\_t \) cText\[ ui8MyCharacter \] \] + 2;

            ui8MyCharacter--;
            ui8CharactersToDraw--;

        \}

    \}

    glTranslatef\( ui16Width - ui16Progress, 0, 0 \);

    ui8MyCharacter = ui8CharactersToDraw;

    if\( ui8CharactersToDraw &gt; 0 \)
    \{

        glCallList\( gluiCharacter\[46 \] \);
        glCallList\( gluiCharacter\[46 \] \);
        glCallList\( gluiCharacter\[46 \] \);

    \}

    while\( ui8MyCharacter &lt; ui8Characters \)
    \{

        glCallList\( gluiCharacter\[\( uint8\_t \) cText\[ ui8MyCharacter \] \] \);

        ui8MyCharacter++;

    \}

glPopMatrix\(\);

return;

```

}

void RenderSingleLineTextCentred( char \* cText, uint8\_t ui8Characters, uint16\_t ui16Width )  
{

```
glPushMatrix\(\);

    glBindTexture\( GL\_TEXTURE\_2D, gluiFont \);

    uint8\_t ui8MyCharacter = 0;

    uint8\_t ui8EscapeWidth = \( ui8CharacterWidth\[46 \] \* 3 \) + 6;
    uint16\_t ui16Progress = 0;
    uint8\_t ui8CharactersToDraw = 0;

    while\( ui8MyCharacter &lt; ui8Characters \)
    \{

        if\( \( ui16Width - ui16Progress \) - ui8CharacterWidth\[\( uint8\_t \) cText\[ ui8MyCharacter \] \] &lt; ui8EscapeWidth \)
        \{

            ui16Progress += ui8EscapeWidth;

            ui8MyCharacter = UINT8\_MAX;

        \}
        else
        \{

            ui16Progress += ui8CharacterWidth\[\( uint8\_t \) cText\[ ui8MyCharacter \] \] + 2;

            ui8MyCharacter++;
            ui8CharactersToDraw++;

        \}

    \}

    glTranslatef\( floor\( \( ui16Width - ui16Progress \) / 2.0 \), 0, 0 \);

    ui8MyCharacter = 0;

    while\( ui8MyCharacter &lt; ui8CharactersToDraw \)
    \{

        glCallList\( gluiCharacter\[\( uint8\_t \) cText\[ ui8MyCharacter \] \] \);

        ui8MyCharacter++;

    \}

    if\( ui8MyCharacter &lt; ui8Characters \)
    \{

        glCallList\( gluiCharacter\[46 \] \);
        glCallList\( gluiCharacter\[46 \] \);
        glCallList\( gluiCharacter\[46 \] \);

    \}

glPopMatrix\(\);

return;

```

}

void RenderSingleLineText( char \* cText, uint8\_t ui8Characters, uint16\_t ui16Width )  
{

```
glPushMatrix\(\);

    glBindTexture\( GL\_TEXTURE\_2D, gluiFont \);

    uint8\_t ui8MyCharacter = 0;

    uint8\_t ui8EscapeWidth = \( ui8CharacterWidth\[46 \] \* 3 \) + 6;
    uint16\_t ui16Progress = 0;

    while\( ui8MyCharacter &lt; ui8Characters \)
    \{

        uint8\_t ui8Character = cText\[ui8MyCharacter \];

        if\( \( ui16Width - ui16Progress \) - ui8CharacterWidth\[ui8Character \] &lt; ui8EscapeWidth \)
        \{

            glCallList\( gluiCharacter\[46 \] \);
            glCallList\( gluiCharacter\[46 \] \);
            glCallList\( gluiCharacter\[46 \] \);

            ui8MyCharacter = UINT8\_MAX;

        \}
        else
        \{

            glCallList\( gluiCharacter\[ui8Character \] \);

            ui16Progress += ui8CharacterWidth\[ui8Character \] + 2;

            ui8MyCharacter++;

        \}

    \}

glPopMatrix\(\);

return;

```

}

void RenderText( char \* cText, uint8\_t ui8Characters )  
{

```
glPushMatrix\(\);

    glBindTexture\( GL\_TEXTURE\_2D, gluiFont \);

    uint8\_t ui8MyCharacter = 0;

    while\( ui8MyCharacter &lt; ui8Characters \)
    \{

        glCallList\( gluiCharacter\[\( uint8\_t \) cText\[ ui8MyCharacter \] \] \);

        ui8MyCharacter++;

    \}

glPopMatrix\(\);

return;

```

}

uint8\_t InitFont( void )  
{

```
GLFWimage glfwiFont;

//Try to load a font file.
if\( glfwReadImage\( &quot;interface/font.tga&quot;, &amp;glfwiFont, 0 \) \!= GL\_TRUE \)
\{

    printf\( &quot;\[Font texture couldn't load\!\]&quot; \);

    return 1;

\}

//The file should be 24-bit. 8 bits per channel RGB.
if\( glfwiFont.BytesPerPixel \!= 3 \)
\{

    glfwFreeImage\( &amp;glfwiFont \);

    printf\( &quot;\[Font system texture format error\!\]&quot; \);

    return 2;

\}

//Check the image's width.
if\( glfwiFont.Width \!= 512 \)
\{

    glfwFreeImage\( &amp;glfwiFont \);

    printf\( &quot;\[Font system texture size error\!\]&quot; \);

    return 3;

\}

//Check the image's height.
if\( glfwiFont.Height \!= 512 \)
\{

    glfwFreeImage\( &amp;glfwiFont \);

    printf\( &quot;\[Font system texture size error\!\]&quot; \);

    return 4;

\}

//Make space for the font texture.
glGenTextures\( 1, &amp;gluiFont \);
glBindTexture\( GL\_TEXTURE\_2D, gluiFont \);

glPixelStorei\( GL\_UNPACK\_ALIGNMENT, 1 \);

glTexParameteri\( GL\_TEXTURE\_2D, GL\_TEXTURE\_WRAP\_S, GL\_REPEAT \);
glTexParameteri\( GL\_TEXTURE\_2D, GL\_TEXTURE\_WRAP\_T, GL\_REPEAT \);
glTexParameteri\( GL\_TEXTURE\_2D, GL\_TEXTURE\_MAG\_FILTER, GL\_LINEAR \);
glTexParameteri\( GL\_TEXTURE\_2D, GL\_TEXTURE\_MIN\_FILTER, GL\_LINEAR \);

glTexEnvf\( GL\_TEXTURE\_ENV, GL\_TEXTURE\_ENV\_MODE, GL\_MODULATE \);

glTexImage2D\( GL\_TEXTURE\_2D, 0, GL\_RGB, 512, 512, 0, GL\_RGB, GL\_UNSIGNED\_BYTE, glfwiFont.Data \);

//Work out how wide each character is.
uint8\_t ui8Y = 0;

while\( ui8Y &lt; 16 \)
\{

    uint8\_t ui8X = 0;

    while\( ui8X &lt; 16 \)
    \{

        //This is the &quot;base&quot; of the character. The upper left corner. This actually targets the blue component.
        uint8\_t \* ui8CharacterBase = glfwiFont.Data + \( \( \( \( 15 - ui8Y \) \* 16384 \) + \( ui8X \* 32 \) \) \* 3 \);

        //Ensure we know which pixel we're actually working on...
        uint8\_t ui8XPixel = 31;
        uint8\_t ui8YPixel = 0;

        //This is our &quot;tracking pixel&quot; which we are going to check.
        uint8\_t \* ui8RoamingPixel = ui8CharacterBase + \( 31 \* 3 \);

        //Move right to left looking for the closest non-black pixel to the right edge.
        while\( \( ui8XPixel &lt; UINT8\_MAX \) &amp;&amp; \( ui8YPixel &lt; 32 \) \)
        \{

            //If the pixel is active:
            if\( \* ui8RoamingPixel &gt; 0 \)
            \{

                //Quit the loop
                ui8YPixel = 32;

            \}
            else
            \{

                //Move the roaming pixel down one line.
                ui8RoamingPixel += 1536;
                ui8YPixel++;

                //If the moving pixel falls off the bottom:
                if\( ui8YPixel &gt; 31 \)
                \{

                    //Move it back up to the top and left one.
                    ui8YPixel = 0;
                    ui8XPixel--;
                    ui8RoamingPixel = ui8CharacterBase + \( ui8XPixel \* 3 \);

                \}

            \}

        \}

        ui8XPixel = 31 - ui8XPixel;

        //Ensure we know which pixel we're actually working on...
        uint8\_t ui8XPixel2 = 0;
        ui8YPixel = 0;

        //This is our &quot;tracking pixel&quot; which we are going to check.
        ui8RoamingPixel = ui8CharacterBase;

        //Move right to left looking for the closest non-black pixel to the right edge.
        while\( \( ui8XPixel2 &lt; 32 \) &amp;&amp; \( ui8YPixel &lt; 32 \) \)
        \{

            //If the pixel is active:
            if\( \* ui8RoamingPixel &gt; 0 \)
            \{

                //Quit the loop
                ui8YPixel = 32;

            \}
            else
            \{

                //Move the roaming pixel down one line.
                ui8RoamingPixel += 1536;
                ui8YPixel++;

                //If the moving pixel falls off the bottom:
                if\( ui8YPixel &gt; 31 \)
                \{

                    //Move it back up to the top and left one.
                    ui8YPixel = 0;
                    ui8XPixel2++;
                    ui8RoamingPixel = ui8CharacterBase + \( ui8XPixel2 \* 3 \);

                \}

            \}

        \}

        if\( \( ui8XPixel + ui8XPixel2 \) &gt; 31 \)
        \{

            ui8XPixel = 15;
            ui8XPixel2 = 15;

        \}

        //Generate a display list for our character.
        gluiCharacter\[\( ui8Y \* 16 \) + ui8X \] = glGenLists\( 1 \);

        //Did it fail?
        if\( gluiCharacter\[\( ui8Y \* 16 \) + ui8X \] == 0 \)
        \{

            //Delete all display lists.
            while\( ui8Y &lt; UINT8\_MAX \)
            \{

                while\( ui8X &lt; UINT8\_MAX \)
                \{

                    glDeleteLists\( gluiCharacter\[\( ui8Y \* 16 \) + ui8X \], 1 \);

                    ui8X--;

                \}

                ui8X = 15;

                ui8Y--;

            \}

            glDeleteTextures\( 1, &amp;gluiFont \);

            glfwFreeImage\( &amp;glfwiFont \);

            printf\( &quot;\[Font couldn't generate display list\!\]&quot; \);

            return 5;

        \}

        glNewList\( gluiCharacter\[\( ui8Y \* 16 \) + ui8X \], GL\_COMPILE \);

            glTranslatef\( -ui8XPixel2, 0, 0 \);

            glBegin\( GL\_QUADS \);

                glTexCoord2f\( ui8X / 16.0, \( 16 - ui8Y \) / 16.0 \);
                glVertex2f\( 0, 8 \);
                glTexCoord2f\( \( ui8X + 1 \) / 16.0, \( 16 - ui8Y \) / 16.0 \);
                glVertex2f\( 32, 8 \);
                glTexCoord2f\( \( ui8X + 1 \) / 16.0, \( 15 - ui8Y \) / 16.0 \);
                glVertex2f\( 32, 40 \);
                glTexCoord2f\( ui8X / 16.0, \( 15 - ui8Y \) / 16.0 \);
                glVertex2f\( 0, 40 \);

            glEnd\(\);

            glTranslatef\( \( 32 - ui8XPixel \) + 2, 0, 0 \);

        glEndList\(\);

        ui8CharacterOffsetA\[\( ui8Y \* 16 \) + ui8X \] = ui8XPixel;
        ui8CharacterOffsetB\[\( ui8Y \* 16 \) + ui8X \] = ui8XPixel2;
        ui8CharacterWidth\[\( ui8Y \* 16 \) + ui8X \] = \( 32 - ui8XPixel \) - ui8XPixel2;

        ui8X++;

    \}

    ui8Y++;

\}

//Free the image struct.
glfwFreeImage\( &amp;glfwiFont \);

return 0;

```

}

void TerminateFont( void )  
{

```
uint8\_t ui8Y = 0;

while\( ui8Y &lt; 16 \)
\{

    uint8\_t ui8X = 0;

    while\( ui8X &lt; 16 \)
    \{

        glDeleteLists\( gluiCharacter\[ui8X + \( ui8Y \* 16 \) \], 1 \);

        ui8X++;

    \}

    ui8Y++;

\}

glDeleteTextures\( 1, &amp;gluiFont \);

return;

```

}  
[/code]
