Click here to Skip to main content
Click here to Skip to main content

Rendering AltNETType (= .NET FreeType port) with OpenGL

, 14 Oct 2013 CPOL
Rate this:
Please Sign up or sign in to vote.
Example of AltNETType use in OpenGL

Introduction

This tip will explain how to render true type text to a OpenGL surface by using the AltSketch.AltNETType library; using open source tools and technology; these include the Mono, SDL, TAO and free for non commercial AltSketch package.

Background

This tip just explains the modified example of jve7gm Rendering FreeType/2 with OpenGL. Recently, I found AltSketch library implemented in pure C# for MS .NET / Mono (Silverlight / Moonlight), that includes AltNETType subsystem. AltNETType is a pure C# CLS compliant 100% managed, without unsafe blocks port of wonderful font rendering library Freetype. I modified jve7gm example to play with this library. And it is working.

Using the Code

Unlike the use of Freetype, in AltNETType uses "ANT_" prefixes at code elements instead of native Freetype "FT_" prefixes; the core class named "ANT". Instead of FT_Init_FreeType and FT_Done_FreeType, we need to use ANT_Init_AltNETType and ANT_Done_AltNETType.

So code of Rendering FreeType/2 with OpenGL example modified according to these differences.

In the code example, you can see all operations with AltNETType.

public Font3D(string font, int size)
{
    //  Save the size we need it later on when printing

    font_size = size;
 
    //  We begin by creating a library pointer
    ANT_Library library;
    ANT_Error ret = ANT.ANT_Init_AltNETType(out library);
    if (ret != ANT_Error.ANT_Err_Ok)
    {
        return;
    } 
 
    //  Once we have the library we create and load the font face
    ANT_Face face;
    ret = ANT.ANT_New_Face(library, font, 0, out face);
    if (ret != ANT_Error.ANT_Err_Ok)
    {
        return;
    }
 
    //  AltNETType (as Freetype) measures the font size in 1/64th of pixels for accuracy 
    //  so we need to request characters in size*64
    ANT.ANT_Set_Char_Size(face, size << 6, size << 6, 96, 96);
 
    //  Provide a reasonably accurate estimate for expected pixel sizes
    //  when we later on create the bitmaps for the font
    ANT.ANT_Set_Pixel_Sizes(face, size, size);
 
    //  Once we have the face loaded and sized we generate opengl textures 
    //  from the glyphs  for each printable character
    textures = new int[128];
    extent_x = new int[128];
    list_base = Gl.glGenLists(128);
    Gl.glGenTextures(128, textures);
    for (int c = 0; c < 128; c++)
    {
        Compile_Character(face, c);
    }
 
    //  Dispose of these as we don't need
    ANT.ANT_Done_Face(ref face);
    ANT.ANT_Done_AltNETType(ref library);
} 
 
public void Compile_Character(ANT_Face face, int c)
{
    //  We first convert the number index to a character index
    int index = ANT.ANT_Get_Char_Index(face, Convert.ToChar(c));
 
    //  Here we load the actual glyph for the character
    ANT_Error ret = ANT.ANT_Load_Glyph(face, index, ANT_LOAD.ANT_LOAD_DEFAULT);
    if (ret != 0) return;
 
    //  Convert the glyph to a bitmap
    ANT_Glyph glyph;
    ret = ANT.ANT_Get_Glyph(face.glyph, out glyph);
    if (ret != ANT_Error.ANT_Err_Ok)
    {
        return;
    }
 
    ANT.ANT_Glyph_To_Bitmap(ref glyph, ANT_Render_Mode.ANT_RENDER_MODE_NORMAL, null, true);
    ANT_BitmapGlyph glyph_bmp = (ANT_BitmapGlyph) glyph;
    int size = (glyph_bmp.bitmap.width * glyph_bmp.bitmap.rows);
    if (size <= 0)
    {
        //  space is a special `blank` character
        extent_x[c] = 0;
        if (c == 32)
        {
            Gl.glNewList((uint)(list_base + c), Gl.GL_COMPILE);
            Gl.glTranslatef(font_size >> 1, 0, 0);
            extent_x[c] = font_size >> 1;
            Gl.glEndList();
        }
 
        return;
    }
 
    byte[] bmp = new byte[size];
    Array.Copy(glyph_bmp.bitmap.buffer, bmp, bmp.Length);
 
    //  Next we expand the bitmap into an opengl texture             
    int width = next_po2(glyph_bmp.bitmap.width);
    int height = next_po2(glyph_bmp.bitmap.rows);
    byte[] expanded = new byte[2 * width * height];
    for (int j = 0; j < height; j++)
    {
        for (int i = 0; i < width; i++)
        {
            expanded[2 * (i + j * width)] = expanded[2 * (i + j * width) + 1] =
                (i >= glyph_bmp.bitmap.width || j >= glyph_bmp.bitmap.rows) ?
                    (byte)0 : bmp[i + glyph_bmp.bitmap.width * j];
        }
    }
 
    //  Set up some texture parameters for opengl
    Gl.glBindTexture(Gl.GL_TEXTURE_2D, textures[c]);
    Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR);
    Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR);
 
    //  Create the texture
    Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA, width, height,
        0, Gl.GL_LUMINANCE_ALPHA, Gl.GL_UNSIGNED_BYTE, expanded);
    expanded = null;
    bmp = null;
 
    //  Create a display list and bind a texture to it
    Gl.glNewList((uint)(list_base + c), Gl.GL_COMPILE);
    Gl.glBindTexture(Gl.GL_TEXTURE_2D, textures[c]);
 
    //  Account for freetype spacing rules
    Gl.glTranslatef(glyph_bmp.left, 0, 0);
    Gl.glPushMatrix();
    Gl.glTranslatef(0, glyph_bmp.top - glyph_bmp.bitmap.rows, 0);
    float x = (float)glyph_bmp.bitmap.width / (float)width;
    float y = (float)glyph_bmp.bitmap.rows / (float)height;
 
    //  Draw the quad
    Gl.glBegin(Gl.GL_QUADS);
    Gl.glTexCoord2d(0, 0); Gl.glVertex2f(0, glyph_bmp.bitmap.rows);
    Gl.glTexCoord2d(0, y); Gl.glVertex2f(0, 0);
    Gl.glTexCoord2d(x, y); Gl.glVertex2f(glyph_bmp.bitmap.width, 0);
    Gl.glTexCoord2d(x, 0); Gl.glVertex2f(glyph_bmp.bitmap.width, glyph_bmp.bitmap.rows);
    Gl.glEnd();
    Gl.glPopMatrix();
 
    //  Advance for the next character            
    Gl.glTranslatef(glyph_bmp.bitmap.width, 0, 0);
    extent_x[c] = glyph_bmp.left + glyph_bmp.bitmap.width;
    Gl.glEndList();
}  

Points of Interest

As AltSketch is implemented in pure C#, so you do not need to use any unsafe blocks of code or managed/unmanaged conversations. Also as AltNETType is fully managed code, so you don't need to have different FreeType versions of OS-dependent DLLs.

History

  • 13th October, 2013: First release
  • 22nd June, 2014: Executable zip archive removed (it's better to get platform dependent SDL & OpenGL tools by yourself)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Demid Korneev

United States United States
No Biography provided

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.1411019.1 | Last Updated 14 Oct 2013
Article Copyright 2013 by Demid Korneev
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid