public Font(string font, uint size) { if (!File.Exists(font)) throw new FileNotFoundException("Failed to load font file:" + font); Size = size; if (Graphics.Instance.GraphicsDevice == null) throw new NullReferenceException("Graphics Device is null."); gd = Graphics.Instance.GraphicsDevice; IntPtr libptr; int ret = FT.FT_Init_FreeType(out libptr); if (ret != 0) throw new Exception("Failed to load FreeType library."); int retb = FT.FT_New_Face(libptr, font, 0, out faceptr); if (retb != 0) throw new Exception("Failed to create font face."); face = (FT_FaceRec)Marshal.PtrToStructure(faceptr, typeof(FT_FaceRec)); FT.FT_Set_Char_Size(faceptr, (int)size << 6, (int)size << 6, 96, 96); FT.FT_Set_Pixel_Sizes(faceptr, size, size); ascender = face.ascender >> 6; descender = face.descender >> 6; fontheight = ((face.height >> 6) + descender + ascender) / 4; yoffset = (int)(Size - ascender); baseCharacter = CreateChar('i'); }
private void CompileCharacter(FT_FaceRec face, int c) { //We first convert the number index to a character index uint index = FT.FT_Get_Char_Index(faceptr, (uint)c); string sError = ""; if (index == 0) sError = "No Glyph"; //Here we load the actual glyph for the character int ret = FT.FT_Load_Glyph(faceptr, index, FT.FT_LOAD_RENDER); if (ret != 0) { Report("Load_Glyph failed for character " + c.ToString()); } FT_GlyphSlotRec glyphrec = (FT_GlyphSlotRec)Marshal.PtrToStructure(face.glyph, typeof(FT_GlyphSlotRec)); RenderAsTexture(glyphrec,c); //RenderAsOutline(glyphrec,c); }
/// <summary> /// Render the font to a series of OpenGL textures (one per letter) /// </summary> /// <param name="fontsize">size of the font</param> /// <param name="DPI">dots-per-inch setting</param> public void ftRenderToTexture(int fontsize, uint DPI) { if (!fontloaded) return; font_size = fontsize; if (faceptr == IntPtr.Zero) { Report("ERROR: No Face Pointer. Font was not created properly"); return; } face = (FT_FaceRec)Marshal.PtrToStructure(faceptr, typeof(FT_FaceRec)); Report("Num Faces:" + face.num_faces.ToString()); Report("Num Glyphs:" + face.num_glyphs.ToString()); Report("Num Char Maps:" + face.num_charmaps.ToString()); Report("Font Family:" + face.family_name); Report("Style Name:" + face.style_name); Report("Generic:" + face.generic); Report("Bbox:" + face.bbox); Report("Glyph:" + face.glyph); //kerning = FT.FT_HAS_KERNING(faceptr); font_max_chars = (int)face.num_glyphs; // IConsole.Write("Num Glyphs:", ); //Freetype measures the font size in 1/64th of pixels for accuracy //so we need to request characters in size*64 FT.FT_Set_Char_Size(faceptr, font_size << 6, font_size << 6, DPI, DPI); //Provide a reasonably accurate estimate for expected pixel sizes //when we later on create the bitmaps for the font FT.FT_Set_Pixel_Sizes(faceptr, (uint)font_size, (uint)font_size); // Once we have the face loaded and sized we generate opengl textures // from the glyphs for each printable character Report("Compiling Font Characters 0.." + max_chars.ToString()); textures = new int[max_chars]; extent_x = new int[max_chars]; offsets = new FTGlyphOffset[max_chars]; list_base = Gl.glGenLists(max_chars); //Console.WriteLine("Font Compiled:" + sChars); }
private void CompileCharacterToTexture(FT_FaceRec face, int c) { FTGlyphOffset offset = new FTGlyphOffset(); //We first convert the number index to a character index uint index = FT.FT_Get_Char_Index(faceptr, (uint)c); string sError = ""; if (index == 0) sError = "No Glyph"; //Here we load the actual glyph for the character int ret = FT.FT_Load_Glyph(faceptr, index, FT.FT_LOAD_DEFAULT); if (ret != 0) { Console.Write("Load_Glyph failed for character " + c.ToString()); } FT_GlyphSlotRec glyphrec = (FT_GlyphSlotRec)Marshal.PtrToStructure(face.glyph, typeof(FT_GlyphSlotRec)); ret = FT.FT_Render_Glyph(ref glyphrec, FT_Render_Mode.FT_RENDER_MODE_NORMAL); if (ret != 0) { Console.Write("Render failed for character " + c.ToString()); } int size = (glyphrec.bitmap.width * glyphrec.bitmap.rows); if (size <= 0) { //Console.Write("Blank Character: " + c.ToString()); //space is a special `blank` character extent_x[c] = 0; if (c == 32) { Gl.glNewList((list_base + c), Gl.GL_COMPILE); Gl.glTranslatef(font_size >> 1, 0, 0); extent_x[c] = font_size >> 1; Gl.glEndList(); offset.left = 0; offset.top = 0; offset.height = 0; offset.width = extent_x[c]; offsets[c] = offset; } return; } byte[] bmp = new byte[size]; Marshal.Copy(glyphrec.bitmap.buffer, bmp, 0, bmp.Length); //Next we expand the bitmap into an opengl texture int width = next_po2(glyphrec.bitmap.width); int height = next_po2(glyphrec.bitmap.rows); byte[] expanded = new byte[2 * width * height]; for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { //Luminance expanded[2 * (i + j * width)] = (byte)255; //expanded[4 * (i + j * width) + 1] = (byte)255; //expanded[4 * (i + j * width) + 2] = (byte)255; // Alpha expanded[2 * (i + j * width) + 1] = (i >= glyphrec.bitmap.width || j >= glyphrec.bitmap.rows) ? (byte)0 : (byte)(bmp[i + glyphrec.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_WRAP_S, Gl.GL_CLAMP_TO_EDGE); Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_CLAMP_TO_EDGE); 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((list_base + c), Gl.GL_COMPILE); Gl.glBindTexture(Gl.GL_TEXTURE_2D, textures[c]); //Account for freetype spacing rules Gl.glTranslatef(glyphrec.bitmap_left, 0, 0); Gl.glPushMatrix(); Gl.glTranslatef(0, glyphrec.bitmap_top - glyphrec.bitmap.rows, 0); float x = (float)glyphrec.bitmap.width / (float)width; float y = (float)glyphrec.bitmap.rows / (float)height; offset.left = glyphrec.bitmap_left; offset.top = glyphrec.bitmap_top; offset.height = glyphrec.bitmap.rows; offset.width = glyphrec.bitmap.width; offset.advance = glyphrec.advance; offset.lsb_delta = glyphrec.lsb_delta; offset.rsb_delta = glyphrec.rsb_delta; offset.linearHoriAdvance = glyphrec.linearHoriAdvance; offset.linearVertAdvance = glyphrec.linearVertAdvance; offsets[c] = offset; //Draw the quad Gl.glBegin(Gl.GL_QUADS); Gl.glTexCoord2d(0, 0); Gl.glVertex2f(0, glyphrec.bitmap.rows); Gl.glTexCoord2d(0, y); Gl.glVertex2f(0, 0); Gl.glTexCoord2d(x, y); Gl.glVertex2f(glyphrec.bitmap.width, 0); Gl.glTexCoord2d(x, 0); Gl.glVertex2f(glyphrec.bitmap.width, glyphrec.bitmap.rows); Gl.glEnd(); Gl.glPopMatrix(); //Advance for the next character Gl.glTranslatef(glyphrec.bitmap.width, 0, 0); extent_x[c] = glyphrec.bitmap_left + glyphrec.bitmap.width; Gl.glEndList(); sChars += "f:" + c.ToString() + "[w:" + glyphrec.bitmap.width.ToString() + "][h:" + glyphrec.bitmap.rows.ToString() + "]" + sError; }
/// <summary> /// Render the font to a series of OpenGL textures (one per letter) /// </summary> /// <param name="fontsize">size of the font</param> /// <param name="DPI">dots-per-inch setting</param> public void ftRenderToTexture(int fontsize, uint DPI) { font_size = fontsize; face = (FT_FaceRec)Marshal.PtrToStructure(faceptr, typeof(FT_FaceRec)); Console.WriteLine("Num Faces:" + face.num_faces.ToString()); Console.WriteLine("Num Glyphs:" + face.num_glyphs.ToString()); Console.WriteLine("Num Char Maps:" + face.num_charmaps.ToString()); Console.WriteLine("Font Family:" + face.family_name); Console.WriteLine("Style Name:" + face.style_name); Console.WriteLine("Generic:" + face.generic); Console.WriteLine("Bbox:" + face.bbox); Console.WriteLine("Glyph:" + face.glyph); // IConsole.Write("Num Glyphs:", ); //Freetype measures the font size in 1/64th of pixels for accuracy //so we need to request characters in size*64 FT.FT_Set_Char_Size(faceptr, font_size << 6, font_size << 6, DPI, DPI); //Provide a reasonably accurate estimate for expected pixel sizes //when we later on create the bitmaps for the font FT.FT_Set_Pixel_Sizes(faceptr, (uint)font_size, (uint)font_size); // Once we have the face loaded and sized we generate opengl textures // from the glyphs for each printable character Console.WriteLine("Compiling Font Characters 0..127"); textures = new int[128]; extent_x = new int[128]; offsets = new FTGlyphOffset[128]; list_base = Gl.glGenLists(128); Gl.glGenTextures(128, textures); for (int c = 0; c < 128; c++) { CompileCharacterToTexture(face, c); if (c < 127) sChars += ","; } //Console.WriteLine("Font Compiled:" + sChars); }