/// <summary> /// Sets up a single character as a OpenGL texture for rendering. /// </summary> /// <param name="face"></param> /// <param name="faceptr"></param> /// <param name="c"></param> private void CompileCharacter(Face face, IntPtr faceptr, int c) { //We first convert the number index to a character index int index = Face.FT_Get_Char_Index(faceptr, Convert.ToChar(c)); //Here we load the actual glyph for the character int ret = Face.FT_Load_Glyph(faceptr, index, FT_LOAD_TYPES.FT_LOAD_DEFAULT); if (ret != 0) { return; } //Convert the glyph to a bitmap IntPtr glyph; int retb = Glyph.FT_Get_Glyph(face.glyphrec, out glyph); if (retb != 0) { return; } // Render the glphy to a bitmap Glyph.FT_Glyph_To_Bitmap(out glyph, FT_RENDER_MODES.FT_RENDER_MODE_NORMAL, 0, 1); BitmapGlyph glyph_bmp = (BitmapGlyph)Marshal.PtrToStructure(glyph, typeof(BitmapGlyph)); 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((int)(list_base + c), Gl.GL_COMPILE); Gl.glTranslatef(fontSize >> 1, 0, 0); extent_x[c] = fontSize >> 1; Gl.glEndList(); } return; } // Allocate space and grab the bitmap byte[] bmp = new byte[size]; Marshal.Copy(glyph_bmp.bitmap.buffer, bmp, 0, bmp.Length); // Save the size of the bitmap and create a power of 2 version // for OpenGL. glyphSizes[c] = new SizeF(glyph_bmp.bitmap.width, glyph_bmp.bitmap.rows); baselines[c] = glyph_bmp.top - glyph_bmp.bitmap.rows; 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((int)(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.glRotatef(180, 1f, 0, 0); Gl.glScalef(1, -1, 1); 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(); }