/// <summary> /// Retrieve the list of faces from the specified font. For example: regular, bold, italic. /// </summary> static public string[] GetFaces(Font font) { if (font == null || !isPresent) { return(null); } string[] names = null; IntPtr lib = IntPtr.Zero; IntPtr face = IntPtr.Zero; if (FT_Init_FreeType(out lib) != 0) { Debug.LogError("Failed to initialize FreeType"); return(null); } string fileName = Application.dataPath.Substring(0, Application.dataPath.Length - "Assets".Length) + UnityEditor.AssetDatabase.GetAssetPath(font); if (File.Exists(fileName)) { if (FT_New_Face(lib, fileName, 0, out face) != 0) { Debug.LogError("Unable to use the chosen font (FT_New_Face)."); } else { FT_FaceRec record = (FT_FaceRec)Marshal.PtrToStructure(face, typeof(FT_FaceRec)); names = new string[record.num_faces]; for (int i = 0; i < record.num_faces; i++) { IntPtr ptr = IntPtr.Zero; if (FT_New_Face(lib, fileName, i, out ptr) == 0) { string family = Marshal.PtrToStringAnsi(record.family_name); string style = Marshal.PtrToStringAnsi(record.style_name); names[i] = family + " - " + style; FT_Done_Face(ptr); } } } } if (face != IntPtr.Zero) { FT_Done_Face(face); } #if !UNITY_3_5 if (lib != IntPtr.Zero) { FT_Done_FreeType(lib); } #endif return(names); }
public override int GetCharWidth(PDFFont pdfFont, TTFontData data, char charCode) { InitLibrary(); int aint = (int)charCode; if (data.Widths.IndexOfKey(charCode) >= 0) { return(data.Widths[charCode]); } LogFontFt cfont = data.LogFont; cfont.OpenFont(); int awidth = 0; Monitor.Enter(flag); try { if (data.Widths.IndexOfKey(charCode) >= 0) { awidth = data.Widths[charCode]; } else { if (0 == FT.FT_Load_Char(cfont.iface, (uint)charCode, (int)FT.FT_LOAD_NO_SCALE)) { FT_FaceRec aface = (FT_FaceRec)Marshal.PtrToStructure(cfont.iface, typeof(FT_FaceRec)); FT_GlyphSlotRec aglyph = (FT_GlyphSlotRec)Marshal.PtrToStructure(aface.glyph, typeof(FT_GlyphSlotRec)); ushort width1 = (ushort)(aglyph.linearHoriAdvance >> 16); ushort width2 = (ushort)(aglyph.linearHoriAdvance & 0x0000FFFF); double dwidth = width1 + width2 / (double)65535; awidth = System.Convert.ToInt32(Math.Round(cfont.widthmult * dwidth)); } data.Widths[charCode] = awidth; data.Glyphs[charCode] = System.Convert.ToInt32(FT.FT_Get_Char_Index(cfont.iface, charCode)); if (data.FirstLoaded > aint) { data.FirstLoaded = aint; } if (data.LastLoaded < aint) { data.LastLoaded = aint; } } } finally { Monitor.Exit(flag); } return(awidth); }
/// <summary> /// Creates a new font set. /// </summary> /// <param name="family">The font family.</param> /// <param name="size">Size in pixels.</param> /// <param name="resolution">Resolution in dpi.</param> public FontAssetCore(FontFamily family, int size, uint resolution) { _family = family; _resolution = resolution; FT_FaceRec face = (FT_FaceRec)Marshal.PtrToStructure(_family.Face, typeof(FT_FaceRec)); _charSet = new BitmapCharacterSet(face.num_glyphs) { RenderedSize = size, Width = MAX_WIDTH, Height = MAX_HEIGHT }; _charSet.Ascender = _charSet.RenderedSize * face.ascender / face.height; }
/// <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); }
public void OpenFont() { if (faceinit) { return; } Monitor.Enter(FontInfoFt.flag); try { if (FontFaces.IndexOfKey(keyname) >= 0) { iface = FontFaces[keyname]; faceinit = true; } else { FontInfoFt.CheckFreeType(FT.FT_New_Face(ftlibrary, filename, 0, out iface)); FT_FaceRec aface = new FT_FaceRec(); FontInfoFt.CheckFreeType(FT.FT_New_Face(ftlibrary, filename, 0, out iface)); aface = (FT_FaceRec)Marshal.PtrToStructure(iface, typeof(FT_FaceRec)); faceinit = true; if (type1) { kerningfile = System.IO.Path.ChangeExtension(filename, ".afm"); if (File.Exists(kerningfile)) { FontInfoFt.CheckFreeType(FT.FT_Attach_File(iface, kerningfile)); } } // Don't need scale, but this is a scale that returns // exact widht for pdf if you divide the result // of Get_Char_Width by 64 FontInfoFt.CheckFreeType(FT.FT_Set_Char_Size(iface, 0, 64 * 100, 720, 720)); FontFaces.Add(keyname, iface); } } finally { Monitor.Exit(FontInfoFt.flag); } }
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 bool AddGlyphInternal(uint glyphIndex) { // FreeType measures font size in terms Of 1/64ths of a point. // 1 point = 1/72th of an inch. Resolution is in dots (pixels) per inch. // Locking is also required here to avoid accessing to texture when handling glyphs (can lead to AccessViolationException) lock (_syncObj) { float pointSize = 64.0f * _charSet.RenderedSize * 72.0f / _resolution; FT.FT_Set_Char_Size(_family.Face, (int)pointSize, 0, _resolution, 0); // Font does not contain that glyph, the 'missing' glyph will be shown instead if (glyphIndex == 0 && _charSet.GetCharacter(0) != null) { return(false); } // Load the glyph for the current character. if (FT.FT_Load_Glyph(_family.Face, glyphIndex, FT.FT_LOAD_DEFAULT) != 0) { return(false); } FT_FaceRec face = (FT_FaceRec)Marshal.PtrToStructure(_family.Face, typeof(FT_FaceRec)); IntPtr glyphPtr; // Load the glyph data into our local array. if (FT.FT_Get_Glyph(face.glyph, out glyphPtr) != 0) { return(false); } // Convert the glyph to bitmap form. if (FT.FT_Glyph_To_Bitmap(ref glyphPtr, FT_Render_Mode.FT_RENDER_MODE_NORMAL, IntPtr.Zero, 1) != 0) { return(false); } // Get the structure fron the intPtr FT_BitmapGlyph glyph = (FT_BitmapGlyph)Marshal.PtrToStructure(glyphPtr, typeof(FT_BitmapGlyph)); // Width/height of char int cwidth = glyph.bitmap.width; int cheight = glyph.bitmap.rows; // Width/height of char including padding int pwidth = cwidth + 3 * PAD; int pheight = cheight + 3 * PAD; // Check glyph index is in the character set range. if (!_charSet.IsInRange(glyphIndex)) { return(false); } // Check glyph fits in our texture if (_currentX + pwidth > MAX_WIDTH) { _currentX = 0; _currentY += _rowHeight; _rowHeight = 0; } if (_currentY + pheight > MAX_HEIGHT) { return(false); } // Create and store a BitmapCharacter for this glyph _charSet.SetCharacter(glyphIndex, CreateCharacter(glyph)); // Copy the glyph bitmap to our local array Byte[] bitmapBuffer = new Byte[cwidth * cheight]; if (glyph.bitmap.buffer != IntPtr.Zero) { Marshal.Copy(glyph.bitmap.buffer, bitmapBuffer, 0, cwidth * cheight); } // Write glyph bitmap to our texture WriteGlyphToTexture(glyph, pwidth, pheight, bitmapBuffer); _currentX += pwidth; _rowHeight = Math.Max(_rowHeight, pheight); // Free the glyph FT.FT_Done_Glyph(glyphPtr); } return(true); }
/// <summary> /// Create a bitmap font from the specified dynamic font. /// </summary> static public bool CreateFont(Font ttf, int size, int faceIndex, bool kerning, string characters, int padding, out BMFont font, out Texture2D tex) { font = null; tex = null; if (ttf == null || !isPresent) { return(false); } IntPtr lib = IntPtr.Zero; IntPtr face = IntPtr.Zero; if (FT_Init_FreeType(out lib) != 0) { Debug.LogError("Failed to initialize FreeType"); return(false); } string fileName = Application.dataPath.Substring(0, Application.dataPath.Length - "Assets".Length) + UnityEditor.AssetDatabase.GetAssetPath(ttf); if (!File.Exists(fileName)) { Debug.LogError("Unable to use the chosen font."); } else if (FT_New_Face(lib, fileName, faceIndex, out face) != 0) { Debug.LogError("Unable to use the chosen font (FT_New_Face)."); } else { font = new BMFont(); font.charSize = size; Color32 white = Color.white; List <int> entries = new List <int>(); List <Texture2D> textures = new List <Texture2D>(); FT_FaceRec faceRec = (FT_FaceRec)Marshal.PtrToStructure(face, typeof(FT_FaceRec)); FT_Set_Pixel_Sizes(face, 0, (uint)size); // Calculate the baseline value that would let the printed font be centered vertically //int ascender = (faceRec.met.ascender >> 6); //int descender = (faceRec.descender >> 6); //int baseline = ((ascender - descender) >> 1); //if ((baseline & 1) == 1) --baseline; //Debug.Log(ascender + " " + descender + " " + baseline); // Space character is not renderable FT_Load_Glyph(face, FT_Get_Char_Index(face, 32), FT_LOAD_DEFAULT); FT_GlyphSlotRec space = (FT_GlyphSlotRec)Marshal.PtrToStructure(faceRec.glyph, typeof(FT_GlyphSlotRec)); // Space is not visible and doesn't have a texture BMGlyph spaceGlyph = font.GetGlyph(32, true); spaceGlyph.offsetX = 0; spaceGlyph.offsetY = 0; spaceGlyph.advance = (space.metrics.horiAdvance >> 6); spaceGlyph.channel = 15; spaceGlyph.x = 0; spaceGlyph.y = 0; spaceGlyph.width = 0; spaceGlyph.height = 0; // Save kerning information if (kerning) { for (int b = 0; b < characters.Length; ++b) { uint ch2 = characters[b]; if (ch2 == 32) { continue; } FT_Vector vec; if (FT_Get_Kerning(face, ch2, 32, 0, out vec) != 0) { continue; } int offset = (vec.x >> 6); if (offset != 0) { spaceGlyph.SetKerning((int)ch2, offset); } } } // Run through all requested characters foreach (char ch in characters) { uint charIndex = FT_Get_Char_Index(face, (uint)ch); FT_Load_Glyph(face, charIndex, FT_LOAD_DEFAULT); FT_GlyphSlotRec glyph = (FT_GlyphSlotRec)Marshal.PtrToStructure(faceRec.glyph, typeof(FT_GlyphSlotRec)); FT_Render_Glyph(ref glyph, FT_Render_Mode.FT_RENDER_MODE_NORMAL); if (glyph.bitmap.width > 0 && glyph.bitmap.rows > 0) { byte[] buffer = new byte[glyph.bitmap.width * glyph.bitmap.rows]; Marshal.Copy(glyph.bitmap.buffer, buffer, 0, buffer.Length); Texture2D texture = new Texture2D(glyph.bitmap.width, glyph.bitmap.rows, UnityEngine.TextureFormat.ARGB32, false); Color32[] colors = new Color32[buffer.Length]; for (int i = 0, y = 0; y < glyph.bitmap.rows; ++y) { for (int x = 0; x < glyph.bitmap.width; ++x) { white.a = buffer[i++]; colors[x + glyph.bitmap.width * (glyph.bitmap.rows - y - 1)] = white; } } // Save the texture texture.SetPixels32(colors); texture.Apply(); textures.Add(texture); entries.Add(ch); // Record the metrics BMGlyph bmg = font.GetGlyph(ch, true); bmg.offsetX = (glyph.metrics.horiBearingX >> 6); bmg.offsetY = -(glyph.metrics.horiBearingY >> 6); bmg.advance = (glyph.metrics.horiAdvance >> 6); bmg.channel = 15; // Save kerning information if (kerning) { for (int b = 0; b < characters.Length; ++b) { uint ch2 = characters[b]; if (ch2 == ch) { continue; } FT_Vector vec; if (FT_Get_Kerning(face, ch2, ch, 0, out vec) != 0) { continue; } int offset = (vec.x >> 6); if (offset != 0) { bmg.SetKerning((int)ch2, offset); } } } } } // Create a packed texture with all the characters tex = new Texture2D(32, 32, TextureFormat.ARGB32, false); Rect[] rects = tex.PackTextures(textures.ToArray(), padding); // Make the RGB channel pure white Color32[] cols = tex.GetPixels32(); for (int i = 0, imax = cols.Length; i < imax; ++i) { Color32 c = cols[i]; c.r = 255; c.g = 255; c.b = 255; cols[i] = c; } tex.SetPixels32(cols); tex.Apply(); font.texWidth = tex.width; font.texHeight = tex.height; int min = int.MaxValue; int max = int.MinValue; // Other glyphs are visible and need to be added for (int i = 0, imax = entries.Count; i < imax; ++i) { // Destroy the texture now that it's a part of an atlas UnityEngine.Object.DestroyImmediate(textures[i]); textures[i] = null; Rect rect = rects[i]; // Set the texture coordinates BMGlyph glyph = font.GetGlyph(entries[i], true); glyph.x = Mathf.RoundToInt(rect.x * font.texWidth); glyph.y = Mathf.RoundToInt(rect.y * font.texHeight); glyph.width = Mathf.RoundToInt(rect.width * font.texWidth); glyph.height = Mathf.RoundToInt(rect.height * font.texHeight); // Flip the Y since the UV coordinate system is different glyph.y = font.texHeight - glyph.y - glyph.height; max = Mathf.Max(max, -glyph.offsetY); min = Mathf.Min(min, -glyph.offsetY - glyph.height); } int baseline = size + min; baseline += ((max - min - size) >> 1); // Offset all glyphs so that they are not using the baseline for (int i = 0, imax = entries.Count; i < imax; ++i) { BMGlyph glyph = font.GetGlyph(entries[i], true); glyph.offsetY += baseline; } } if (face != IntPtr.Zero) { FT_Done_Face(face); } #if !UNITY_3_5 if (lib != IntPtr.Zero) { FT_Done_FreeType(lib); } #endif return(tex != null); }
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); }
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; }
private static void InitLibrary() { Monitor.Enter(flag); try { if (libraryinitialized) { return; } CheckFreeType(FT.FT_Init_FreeType(out FreeTypeLib)); libraryinitialized = true; Strings npaths = GetFontDirectories(); foreach (string ndir in npaths) { if (Directory.Exists(ndir)) { string[] nfiles = StreamUtil.GetFiles(ndir, "*.TTF|*.ttf|*.pf*", SearchOption.TopDirectoryOnly); foreach (string nfile in nfiles) { IntPtr iface = (IntPtr)0; FT_FaceRec aface = new FT_FaceRec(); CheckFreeType(FT.FT_New_Face(FreeTypeLib, nfile, 0, out iface)); try { aface = (FT_FaceRec)Marshal.PtrToStructure(iface, typeof(FT_FaceRec)); if ((aface.face_flags & (int)FT_Face_Flags.FT_FACE_FLAG_SCALABLE) != 0) { LogFontFt aobj = new LogFontFt(); aobj.ftlibrary = FreeTypeLib; aobj.fullinfo = false; // Fill font properties aobj.type1 = ((int)FT_Face_Flags.FT_FACE_FLAG_SFNT & aface.face_flags) == 0; if (aobj.type1) { aobj.convfactor = 1; // aobj.convfactor:=1000/aface.units_per_EM; aobj.widthmult = aobj.convfactor; } else { aobj.convfactor = 1; // aobj.convfactor:=1000/aface.units_per_EM; aobj.widthmult = aobj.convfactor; } aobj.filename = nfile; string family_name = Marshal.PtrToStringAnsi(aface.family_name); aobj.postcriptname = family_name.Replace(" ", ""); aobj.familyname = family_name; aobj.keyname = family_name + "____"; aobj.fixedpitch = (aface.face_flags & (int)FT_Face_Flags.FT_FACE_FLAG_FIXED_WIDTH) != 0; aobj.havekerning = (aface.face_flags & (int)FT_Face_Flags.FT_FACE_FLAG_KERNING) != 0; int nleft = System.Convert.ToInt32(Math.Round(aobj.convfactor * aface.bbox.xMin)); int nright = System.Convert.ToInt32(Math.Round(aobj.convfactor * aface.bbox.xMax)); int ntop = System.Convert.ToInt32(Math.Round(aobj.convfactor * aface.bbox.yMax)); int nbottom = System.Convert.ToInt32(Math.Round(aobj.convfactor * aface.bbox.yMin)); aobj.BBox = new Rectangle(nleft, ntop, nright - nleft, nbottom - ntop); aobj.ascent = System.Convert.ToInt32(Math.Round(aobj.convfactor * aface.ascender)); aobj.descent = System.Convert.ToInt32(Math.Round(aobj.convfactor * aface.descender)); aobj.leading = System.Convert.ToInt32(Math.Round(aobj.convfactor * aface.height) - (aobj.ascent - aobj.descent)); aobj.MaxWidth = System.Convert.ToInt32(Math.Round(aobj.convfactor * aface.max_advance_width)); aobj.Capheight = System.Convert.ToInt32(Math.Round(aobj.convfactor * aface.ascender)); string style_name = Marshal.PtrToStringAnsi(aface.style_name); aobj.stylename = style_name; aobj.bold = (aface.style_flags & (int)FT_Style_Flags.FT_STYLE_FLAG_BOLD) != 0; aobj.italic = (aface.style_flags & (int)FT_Style_Flags.FT_STYLE_FLAG_ITALIC) != 0; if (aobj.bold) { aobj.keyname = aobj.keyname + "B1"; } else { aobj.keyname = aobj.keyname + "B0"; } if (aobj.italic) { aobj.keyname = aobj.keyname + "I1"; } else { aobj.keyname = aobj.keyname + "I0"; } // Default font configuration, LUXI SANS is default if ((!aobj.italic) && (!aobj.bold)) { if (defaultfont == null) { defaultfont = aobj; } else { if (aobj.familyname.ToUpper() == "LUXI SANS") { defaultfont = aobj; } } } else if ((!aobj.italic) && (aobj.bold)) { if (defaultfontb == null) { defaultfontb = aobj; } else { if (aobj.familyname.ToUpper() == "LUXI SANS") { defaultfontb = aobj; } } } else if ((aobj.italic) && (!aobj.bold)) { if (defaultfontit == null) { defaultfontit = aobj; } else { if (aobj.familyname.ToUpper() == "LUXI SANS") { defaultfontit = aobj; } } } else if ((aobj.italic) && (aobj.bold)) { if (defaultfontbit == null) { defaultfontbit = aobj; } else { if (aobj.familyname.ToUpper() == "LUXI SANS") { defaultfontbit = aobj; } } } aobj.keyname = aobj.keyname.ToUpper(); if (fontlist.IndexOfKey(aobj.keyname) < 0) { fontlist.Add(aobj.keyname.ToUpper(), aobj); } } int nindex = fontfiles.IndexOfKey(nfile); if (nindex < 0) { fontfiles.Add(nfile, nfile); } } finally { CheckFreeType(FT.FT_Done_Face(iface)); } } } } } finally { Monitor.Exit(flag); } }