private BitmapCharacter CreateCharacter(FT_BitmapGlyph glyph) { lock (_syncObj) return new BitmapCharacter { Width = glyph.bitmap.width + PAD * 2, Height = glyph.bitmap.rows + PAD * 2, X = _currentX, Y = _currentY, XOffset = glyph.left, YOffset = _charSet.Ascender - glyph.top, // Convert fixed point 16.16 to float by divison with 2^16 XAdvance = (int)(glyph.root.advance.x / 65536.0f) }; }
private void WriteGlyphToTexture(FT_BitmapGlyph glyph, int pwidth, int pheight, Byte[] bitmapBuffer) { lock (_syncObj) { if (_texture == null) { return; } // Lock the the area we intend to update Rectangle charArea = new Rectangle(_currentX, _currentY, pwidth, pheight); DataStream dataStream; _texture.LockRectangle(0, charArea, LockFlags.None, out dataStream); using (dataStream) { // Copy FreeType glyph bitmap into our font texture. Byte[] fontPixels = new Byte[pwidth]; Byte[] padPixels = new Byte[pwidth]; int pitch = Math.Abs(glyph.bitmap.pitch); // Write the first padding row dataStream.Write(padPixels, 0, pwidth); dataStream.Seek(MAX_WIDTH - pwidth, SeekOrigin.Current); // Write the glyph for (int y = 0; y < glyph.bitmap.rows; y++) { for (int x = 0; x < glyph.bitmap.width; x++) { fontPixels[x + PAD] = bitmapBuffer[y * pitch + x]; } dataStream.Write(fontPixels, 0, pwidth); dataStream.Seek(MAX_WIDTH - pwidth, SeekOrigin.Current); } // Write the last padding row dataStream.Write(padPixels, 0, pwidth); dataStream.Seek(MAX_WIDTH - pwidth, SeekOrigin.Current); _texture.UnlockRectangle(0); } } }
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); }
private void WriteGlyphToTexture(FT_BitmapGlyph glyph, int pwidth, int pheight, Byte[] bitmapBuffer) { lock (_syncObj) { // Lock the the area we intend to update Rectangle charArea = new Rectangle(_currentX, _currentY, pwidth, pheight); DataRectangle rect = _texture.LockRectangle(0, charArea, LockFlags.None); using (rect.Data) { // Copy FreeType glyph bitmap into our font texture. Byte[] fontPixels = new Byte[pwidth]; Byte[] padPixels = new Byte[pwidth]; int pitch = Math.Abs(glyph.bitmap.pitch); // Write the first padding row rect.Data.Write(padPixels, 0, pwidth); rect.Data.Seek(MAX_WIDTH - pwidth, SeekOrigin.Current); // Write the glyph for (int y = 0; y < glyph.bitmap.rows; y++) { for (int x = 0; x < glyph.bitmap.width; x++) fontPixels[x + PAD] = bitmapBuffer[y * pitch + x]; rect.Data.Write(fontPixels, 0, pwidth); rect.Data.Seek(MAX_WIDTH - pwidth, SeekOrigin.Current); } // Write the last padding row rect.Data.Write(padPixels, 0, pwidth); rect.Data.Seek(MAX_WIDTH - pwidth, SeekOrigin.Current); _texture.UnlockRectangle(0); } } }
private BitmapCharacter CreateCharacter(FT_BitmapGlyph glyph) { lock (_syncObj) return new BitmapCharacter { Width = glyph.bitmap.width + PAD * 2, Height = glyph.bitmap.rows + PAD * 2, X = _currentX, Y = _currentY, XOffset = glyph.left, YOffset = _charSet.Base - glyph.top, // Convert fixed point 16.16 to float by divison with 2^16 XAdvance = (int) (glyph.root.advance.x / 65536.0f) }; }