65.9K
CodeProject 正在变化。 阅读更多。
Home

使用OpenGL渲染AltNETType (= .NET FreeType 端口)

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2013年10月14日

CPOL

1分钟阅读

viewsIcon

35278

downloadIcon

711

AltNETType 在 OpenGL 中的使用示例

引言

本技巧将解释如何使用 AltSketch.AltNETType 库将 TrueType 文本渲染到 OpenGL 表面;使用开源工具和技术;这些包括 Mono、SDL、TAO 和免费(非商业用途)的 AltSketch 包。

背景

本技巧仅解释了 jve7gm 使用 OpenGL 渲染 FreeType/2 的修改示例。最近,我发现了一个纯 C# 实现的 MS .NET / Mono (Silverlight / Moonlight) 的 AltSketch 库,其中包含 AltNETType 子系统。AltNETType 是一个纯 C# CLS 兼容的 100% 托管代码,没有不安全代码块,是对优秀的字体渲染库 Freetype 的移植。 我修改了 jve7gm 示例来使用这个库。它正常工作。

Using the Code

与使用 Freetype 不同,AltNETType 在代码元素中使用 "ANT_" 前缀代替 native 的 Freetype 的 "FT_" 前缀;核心类命名为 "ANT"。我们需要使用 ANT_Init_AltNETTypeANT_Done_AltNETType 代替 FT_Init_FreeTypeFT_Done_FreeType

所以 使用 OpenGL 渲染 FreeType/2 示例的代码根据这些差异进行了修改。

在代码示例中,您可以查看与 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();
}  

关注点

由于 AltSketch 是用纯 C# 实现的,因此您不需要使用任何不安全的代码块或托管/非托管转换。 此外,由于 AltNETType 是完全托管的代码,因此您不需要具有操作系统相关的 DLL 的不同 FreeType 版本。

历史

  • 2013 年 10 月 13 日:首次发布
  • 2014 年 6 月 22 日:删除了可执行 zip 压缩包(最好自己获取平台相关的 SDL 和 OpenGL 工具)
© . All rights reserved.