private static Surface RenderGlyph(FT_Bitmap bitmap, byte alpha) { if (bitmap.rows == 0 || bitmap.pitch == 0) { return(new Surface(0, 0)); } var bytes = new byte[bitmap.rows * bitmap.pitch]; Marshal.Copy(bitmap.buffer, bytes, 0, bytes.Length); return(new Surface((int)bitmap.width, (int)bitmap.rows, TransformGlyphBytes(bytes, alpha))); Pixel[] TransformGlyphBytes(byte[] input, byte a) { var output = new Pixel[input.Length]; for (int i = 0; i < input.Length; i++) { output[i].R = input[i]; output[i].G = input[i]; output[i].B = input[i]; output[i].A = input[i] != 0 ? (byte)255 : alpha; } return(output); } }
public CharacterInfo RequestCharacterInfo(int charactorCode) { var glyphIndex = FT.FT_Get_Char_Index(face.Face, (uint)charactorCode); if (glyphIndex == 0) { return(null); } FT_Error error; error = FT.FT_Load_Glyph(face.Face, glyphIndex, FT.FT_LOAD_DEFAULT); if (error != FT_Error.FT_Err_Ok) { throw new FreeTypeException(error); } FT_Render_Mode renderMode = antialias ? FT_Render_Mode.FT_RENDER_MODE_NORMAL : FT_Render_Mode.FT_RENDER_MODE_MONO; IntPtr pGlyphSlot; unsafe { pGlyphSlot = (IntPtr)face.GlyphSlot; } error = FT.FT_Render_Glyph(pGlyphSlot, renderMode); if (error != FT_Error.FT_Err_Ok) { throw new FreeTypeException(error); } FT_GlyphSlotRec glyphSlot = (FT_GlyphSlotRec)Marshal.PtrToStructure(pGlyphSlot, typeof(FT_GlyphSlotRec)); FT_Bitmap bitmap = glyphSlot.bitmap; if (bitmap.buffer == IntPtr.Zero) { return(new CharacterInfo(this, charactorCode, new Vector2((int)glyphSlot.advance.x >> 6, (int)glyphSlot.advance.y >> 6))); } Texture texture = Font.atlas.Allocate(bitmap.width, bitmap.rows); switch ((FT_Pixel_Mode)bitmap.pixel_mode) { case FT_Pixel_Mode.FT_PIXEL_MODE_GRAY: { uint length = bitmap.width * bitmap.rows; byte[] buffer = new Byte[length]; Marshal.Copy(bitmap.buffer, buffer, 0, (int)length); Color[] pixels = new Color[length]; int count = 0; for (int y = (int)bitmap.rows - 1; y >= 0; y--) { for (int x = 0; x < bitmap.width; x++) { int index = y * (int)bitmap.width + x; pixels[count] = new Color { r = 1, g = 1, b = 1, a = (float)buffer[index] / 255.0f }; count++; } } texture.SetPixels(pixels); } break; case FT_Pixel_Mode.FT_PIXEL_MODE_MONO: { uint length = bitmap.width * bitmap.rows; byte[] buffer = new Byte[bitmap.pitch * bitmap.rows]; Marshal.Copy(bitmap.buffer, buffer, 0, (int)buffer.Length); Color[] pixels = new Color[length]; int count = 0; for (int y = (int)bitmap.rows - 1; y >= 0; y--) { for (int x = 0; x < bitmap.width; x++) { int index = y * bitmap.pitch + (int)(x / 8); byte group = buffer[index]; float pixel = (group & (1 << (7 - x % 8))) > 0 ? 255.0f : 0; pixels[count] = new Color { r = 1, g = 1, b = 1, a = pixel / 255.0f }; count++; } } texture.SetPixels(pixels); } break; default: throw new NotImplementedException(string.Format("Pixel mode ({0})", bitmap.pixel_mode.ToString())); } return(new CharacterInfo( this, charactorCode, new Vector2((float)glyphSlot.advance.x / (float)(1 << 6), (float)glyphSlot.advance.y / (float)(1 << 6)), texture, new Vector2(glyphSlot.bitmap_left, glyphSlot.bitmap_top) )); }