/// <summary> /// Add a character. /// </summary> /// <param name="codePoint">Codepoint.</param> unsafe void AddCharacter(uint codePoint) { // Handle Tab if (codePoint == (uint)'\t') { var spaceGlyph = GetGlyph((uint)' '); glyphs.Add(codePoint, new GlyphInfo(spaceGlyph.AdvanceX * 5, spaceGlyph.AdvanceY, spaceGlyph.CharIndex)); return; } // Check if Glyph exists uint index = FT.FT_Get_Char_Index(facePtr, codePoint); if (index == 0) { if (codePoint == (uint)'?') { throw new Exception("Font does not contain required character '?'"); } glyphs.Add(codePoint, GetGlyph((uint)'?')); return; } // Render the glyph FT.FT_Load_Glyph(facePtr, index, FT.FT_LOAD_DEFAULT | FT.FT_LOAD_TARGET_NORMAL); var faceRec = (FT.FaceRec)Marshal.PtrToStructure(facePtr, typeof(FT.FaceRec)); FT.FT_Render_Glyph(faceRec.glyph, FT.FT_RENDER_MODE_NORMAL); var glyphRec = (FT.GlyphSlotRec)Marshal.PtrToStructure(faceRec.glyph, typeof(FT.GlyphSlotRec)); //Check for glyph that is only spacing if (glyphRec.bitmap.width == 0 || glyphRec.bitmap.rows == 0) { glyphs.Add(codePoint, new GlyphInfo( (int)Math.Ceiling(FTMath.From26Dot6(glyphRec.advance.x)), (int)Math.Ceiling(FTMath.From26Dot6(glyphRec.advance.y)), index )); return; } var pixels = new RGBA[glyphRec.bitmap.width * glyphRec.bitmap.rows]; if (glyphRec.bitmap.pixel_mode == 2) { byte *data = (byte *)glyphRec.bitmap.buffer; for (int i = 0; i < glyphRec.bitmap.width * glyphRec.bitmap.rows; i++) { // TODO: 4 bytes used for 1 byte of alpha data? investigate compression with GL_RED and shader. pixels [i] = new RGBA(255, 255, 255, data [i]); } } else { throw new NotImplementedException(); } if (currentX + glyphRec.bitmap.width > TEXTURE_SIZE) { currentX = 0; currentY += lineMax; lineMax = 0; } if (currentY + glyphRec.bitmap.rows > TEXTURE_SIZE) { currentX = 0; currentY = 0; lineMax = 0; pages.Add(GetNewTexture()); } lineMax = Math.Max(lineMax, glyphRec.bitmap.rows); var rect = new Rectangle(currentX, currentY, glyphRec.bitmap.width, glyphRec.bitmap.rows); var tex = pages [pages.Count - 1]; tex.SetData(pixels, rect); currentX += glyphRec.bitmap.width; var glyphInfo = new GlyphInfo( t: tex, r: rect, advX: (int)Math.Ceiling(FTMath.From26Dot6(glyphRec.advance.x)), advY: (int)Math.Ceiling(FTMath.From26Dot6(glyphRec.advance.y)), horzAdv: (int)Math.Ceiling(FTMath.From26Dot6(glyphRec.metrics.horiAdvance)), xOff: glyphRec.bitmap_left, yOff: glyphRec.bitmap_top, idx: index ); glyphs.Add(codePoint, glyphInfo); }
/// <summary> /// Add a character. /// </summary> /// <param name="codePoint">Codepoint.</param> unsafe void AddCharacter(uint codePoint) { // Handle Tab if (codePoint == (uint) '\t') { var spaceGlyph = GetGlyph ((uint) ' '); glyphs.Add (codePoint, new GlyphInfo (spaceGlyph.AdvanceX * 5, spaceGlyph.AdvanceY, spaceGlyph.CharIndex)); return; } // Check if Glyph exists uint index = FT.FT_Get_Char_Index (facePtr, codePoint); if (index == 0) { if (codePoint == (uint) '?') throw new Exception ("Font does not contain required character '?'"); glyphs.Add (codePoint, GetGlyph ((uint) '?')); return; } // Render the glyph FT.FT_Load_Glyph (facePtr, index, FT.FT_LOAD_DEFAULT | FT.FT_LOAD_TARGET_NORMAL); var faceRec = (FT.FaceRec) Marshal.PtrToStructure (facePtr, typeof(FT.FaceRec)); FT.FT_Render_Glyph (faceRec.glyph, FT.FT_RENDER_MODE_NORMAL); var glyphRec = (FT.GlyphSlotRec) Marshal.PtrToStructure (faceRec.glyph, typeof(FT.GlyphSlotRec)); //Check for glyph that is only spacing if (glyphRec.bitmap.width == 0 || glyphRec.bitmap.rows == 0) { glyphs.Add (codePoint, new GlyphInfo ( (int) Math.Ceiling (FTMath.From26Dot6 (glyphRec.advance.x)), (int) Math.Ceiling (FTMath.From26Dot6 (glyphRec.advance.y)), index )); return; } var pixels = new RGBA[glyphRec.bitmap.width * glyphRec.bitmap.rows]; if (glyphRec.bitmap.pixel_mode == 2) { byte* data = (byte*) glyphRec.bitmap.buffer; for (int i = 0; i < glyphRec.bitmap.width * glyphRec.bitmap.rows; i++) { // TODO: 4 bytes used for 1 byte of alpha data? investigate compression with GL_RED and shader. pixels [i] = new RGBA (255, 255, 255, data [i]); } } else { throw new NotImplementedException (); } if (currentX + glyphRec.bitmap.width > TEXTURE_SIZE) { currentX = 0; currentY += lineMax; lineMax = 0; } if (currentY + glyphRec.bitmap.rows > TEXTURE_SIZE) { currentX = 0; currentY = 0; lineMax = 0; pages.Add (GetNewTexture ()); } lineMax = Math.Max (lineMax, glyphRec.bitmap.rows); var rect = new Rectangle (currentX, currentY, glyphRec.bitmap.width, glyphRec.bitmap.rows); var tex = pages [pages.Count - 1]; tex.SetData (pixels, rect); currentX += glyphRec.bitmap.width; var glyphInfo = new GlyphInfo ( t: tex, r: rect, advX: (int) Math.Ceiling (FTMath.From26Dot6 (glyphRec.advance.x)), advY: (int) Math.Ceiling (FTMath.From26Dot6 (glyphRec.advance.y)), horzAdv: (int) Math.Ceiling (FTMath.From26Dot6 (glyphRec.metrics.horiAdvance)), xOff: glyphRec.bitmap_left, yOff: glyphRec.bitmap_top, idx: index ); glyphs.Add (codePoint, glyphInfo); }