public TextGenerator(string path, string fontName, uint fontSize = 12) { if (_textPs == null) { LoadProgramShader(); } FontName = fontName; FontSize = fontSize; SharpFont.Library fontLib = new SharpFont.Library(); SharpFont.Face fontFace = new SharpFont.Face(fontLib, path); fontFace.SetPixelSizes(0, FontSize); GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1); for (char c = (char)0x20; c <= (char)0x7E; c++) { fontFace.LoadChar(c, LoadFlags.Render, LoadTarget.Normal); Texture texture = Texture.CreateTexture( fontFace.Glyph.Bitmap.Width, fontFace.Glyph.Bitmap.Rows, PixelInternalFormat.R8, PixelFormat.Red, fontFace.Glyph.Bitmap.Buffer); Character character = new Character( texture.ID, new Vector2(fontFace.Glyph.Bitmap.Width, fontFace.Glyph.Bitmap.Rows), new Vector2(fontFace.Glyph.BitmapLeft, fontFace.Glyph.BitmapTop), (int)fontFace.Glyph.Advance.X); _characters.Add(c, character); } fontFace.Dispose(); fontLib.Dispose(); vao = VAO.Create(); vao.LinkPS(_textPs); vbo = VBO.Create <float>(vertices.Length, 4, "vertex"); indices = new IndicesCollection(); indices.Add(4, vertices.Length); vao.AddVBuff(vbo); vao.AddIndicesCollection(indices); }
/// <summary> /// Releases all resources used by the <see cref="Text"/>. /// </summary> public void Dispose() { if (_stroker != null && !_stroker.IsDisposed) { _stroker.Dispose(); } if (_face != null && !_face.IsDisposed) { _face.Dispose(); } if (_library != null && !_library.IsDisposed) { _library.Dispose(); } _pages = null; _fontData = null; }
private void Clear() { try { if (Font != null) { Font.Dispose(); Font = null; } GL.BindTexture(TextureTarget.Texture2D, 0); if (GlyphCount > 0) { if (m_ListBase > 0) { GL.DeleteLists(m_ListBase, GlyphCount); } else if (!CharMap.IsNullOrEmpty()) { CharMap.Values.Select(val => val.ListID).ForEach(lid => GL.DeleteLists(lid, 1)); CharMap.Clear(); } } if (!m_Textures.IsNullOrEmpty()) { GL.DeleteTextures(m_Textures.Length, m_Textures); } } catch (Exception ex) { ex.LogError(); } finally { GlyphCount = 0; m_ListBase = 0; m_Textures = null; Height = 0; Count = 0; m_EllipsisGlyphIndex = GlyphInfo.Empty; } }
private void InitFont(float scaleFactor) { try { System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew(); ScaleFactor = scaleFactor; YOffsetScaled = YOffset * scaleFactor; // Reset everything Clear(); Font = new Face(FontManager.Library, FilePath); // Go on float size = Size.Scale(ScaleFactor); Fixed26Dot6 sz = new Fixed26Dot6(size / 64); Font.SetCharSize(sz, sz, 72, 72); int pixelSize = (size * 1.3334).Ceil(); Font.SetPixelSizes((uint)pixelSize, (uint)pixelSize); GlyphCount = Font.GlyphCount; int glyphCount = GlyphCount; Monospace = Font.FaceFlags.HasFlag(FaceFlags.FixedWidth); string tmpName = Font.GetPostscriptName(); if (!String.IsNullOrEmpty(tmpName)) { Name = tmpName; } // We support 4 different glyph loading strategies: // // (1) All: all glyphs loaded at once on start // (2) Filtered: all filtered glyphs loaded at once on start // (3) OnDemand: no glyphs loaded at start, all glyphs on demand if (OnDemand) { // Startegy (3) GlyphCount = 0; } else if (Filter > GlyphFilterFlags.OnDemand) { // Startegy (2) // If we have a Filter set, let's count the number of valid glyphs // to minimize graphics memory. uint glyphindex; uint cc = Font.GetFirstChar(out glyphindex); int count = 0; while (glyphindex > 0) { char c = (char)cc; if (Filter.IsValid(c)) { count++; } cc = Font.GetNextChar(cc, out glyphindex); } GlyphCount = count; } else { // Strategy (1), loading the entire font } m_Textures = new int[Math.Max(32, GlyphCount)]; CharMap = new ThreadSafeDictionary <char, GlyphInfo>(Math.Max(31, GlyphCount)); if (!OnDemand) { // Strategy (1) + (2): Load all or filtered glyphs m_ListBase = GL.GenLists(GlyphCount); GL.GenTextures(GlyphCount, m_Textures); uint glyphindex; uint cc = Font.GetFirstChar(out glyphindex); while (glyphindex > 0) { char c = (char)cc; if (!CharMap.ContainsKey(c) && Filter.IsValid(c)) { try { CharMap.Add(c, CompileCharacter(Font, glyphindex, c)); } catch (Exception ex) { ex.LogWarning(); } } cc = Font.GetNextChar(cc, out glyphindex); } CharMap.TryGetValue(SpecialCharacters.Ellipsis, out m_EllipsisGlyphIndex); } else { try { GetGlyphIndex(SpecialCharacters.Ellipsis, out m_EllipsisGlyphIndex); } catch (Exception ex) { ex.LogError(); } } //if (Height <= 1) //Height = pixelSize.NextPowerOf2(); //Height = pixelSize * 1.33335f; Height = pixelSize; float fscale = Height / Font.Height * 1.33334f; //float fscale = Height / Font.Height * 0.776f; Ascender = Font.Ascender * fscale; Descender = Font.Descender * fscale; //HalfHeight = Height / 2; Height = (Ascender).Ceil(); HalfHeight = (int)(Height / 2); //LineHeight = Height * 1.42f * LineSpacing; LineHeight = (int)((Height * 1.42f * LineSpacing) + 0.5f); //TextBoxHeight = ((Height * 2f) + (ScaleFactor * 2f)).Ceil(); //TextBoxHeight = (int)(Height * 1.85f + 0.5f); TextBoxHeight = (int)(Height * 1.85f + 2); CaptionHeight = (int)(Height * 1.55 + 2); YOffsetScaled = (YOffset * ScaleFactor) - HalfHeight; if (OnDemand) { Count.LogInformation("Font {0} ({1}), {2}/{3} glyphs pre-loaded in {4} ms, more glyphs are loaded on demand.", Name, Size, Count, glyphCount, sw.ElapsedMilliseconds); } else { Count.LogInformation("Font {0} ({1}), {2}/{3} glyphs loaded in {4} ms.", Name, Size, Count, glyphCount, sw.ElapsedMilliseconds); } } catch (Exception ex) { ex.LogError(); } finally { if (!OnDemand && Font != null) { Font.Dispose(); Font = null; } } }