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





5.00/5 (3投票s)
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_AltNETType
和 ANT_Done_AltNETType
代替 FT_Init_FreeType
和 FT_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 工具)