Cromon

GdiFontProvider.cs

Oct 18th, 2012
134
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 10.06 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using SlimDX.Direct3D9;
  7. using System.Drawing;
  8. using SlimDX;
  9.  
  10. namespace Gype.UI.D3D9
  11. {
  12.     [Flags]
  13.     internal enum FontFlags : uint
  14.     {
  15.         NoClip       = 1,
  16.         WordWrap     = 2,
  17.         LetterWrap   = 4
  18.     }
  19.  
  20.     internal class GdiFontProvider
  21.     {
  22.         public GdiFontProvider(Rendertarget target, string family, int fontSize)
  23.         {
  24.             mTarget = target as Rendertarget9;
  25.             mGdiFont = new System.Drawing.Font(family, fontSize, FontStyle.Bold, GraphicsUnit.Pixel);
  26.             mFontHeight = mGdiFont.Height;
  27.             mVertexShader = new ShaderCompiler<VertexShader>(mTarget.GraphicsDevice, Shaders.Text, "VertexMain", "vs_3_0");
  28.             mPixelShader = new ShaderCompiler<PixelShader>(mTarget.GraphicsDevice, Shaders.Text, "PixelMain", "ps_3_0");
  29.  
  30.             mMatrixParam = mVertexShader.ConstantTable["orthoProjMatrix"];
  31.  
  32.             var maxTextureSize = target.GetMaximumTextureSize();
  33.             mTextureSize = Math.Min(Math.Min(maxTextureSize.Height, maxTextureSize.Width), 1024);
  34.  
  35.             var curChars = GetCodepageChars(System.Globalization.CultureInfo.CurrentCulture.TextInfo.ANSICodePage);
  36.             var usChars = GetCodepageChars(437);
  37.             var arabChars = GetCodepageChars(1256);
  38.             var str = curChars.Union(usChars).Union(arabChars);
  39.             AllocateNewTexture();
  40.  
  41.             LoadCharRange(str.Except(new char[] { '\0' }).ToArray());
  42.             LoadWhiteSpaces();
  43.         }
  44.  
  45.         public void DrawString(string str, SlimDX.Vector2 position, SlimDX.Vector2 size, FontFlags flags, Color4 clr, float scale = 0.8f)
  46.         {
  47.             LoadCharRange(str);
  48.  
  49.             Vector2 curPos = position;
  50.             List<UIVertex> triangleList = new List<UIVertex>();
  51.             foreach (var c in str)
  52.             {
  53.                 if (char.IsWhiteSpace(c) && c != ' ')
  54.                     continue;
  55.  
  56.                 if (c == ' ')
  57.                 {
  58.                     curPos.X += mGlyphs[' '].CharWidth * scale;
  59.                     continue;
  60.                 }
  61.  
  62.                 var glyph = mGlyphs[c];
  63.  
  64.                 var vertices = mTarget.CreateTriangleList(curPos, new Vector2(glyph.CharWidth * scale, mFontHeight * scale), clr);
  65.                 vertices[0].TexCoord = glyph.TexCoordTop;
  66.                 vertices[1].TexCoord = new Vector2(glyph.TexCoordBottom.X, glyph.TexCoordTop.Y);
  67.                 vertices[2].TexCoord = new Vector2(glyph.TexCoordTop.X, glyph.TexCoordBottom.Y);
  68.                 vertices[3].TexCoord = vertices[1].TexCoord;
  69.                 vertices[4].TexCoord = glyph.TexCoordBottom;
  70.                 vertices[5].TexCoord = vertices[2].TexCoord;
  71.  
  72.                 triangleList.AddRange(vertices);
  73.                 curPos.X += (glyph.CharWidth + 1.5f) * scale;
  74.             }
  75.  
  76.             var dev = mTarget.GraphicsDevice;
  77.             dev.VertexShader = mVertexShader.Shader;
  78.             dev.PixelShader = mPixelShader.Shader;
  79.  
  80.             mVertexShader.SetValue(mMatrixParam, mTarget.OrthoMatrix);
  81.             dev.SetTexture(0, mFontTextures[0]);
  82.  
  83.             dev.VertexDeclaration = mTarget.UIVertexDeclaration;
  84.             dev.DrawUserPrimitives(PrimitiveType.TriangleList, triangleList.Count / 3, triangleList.ToArray());
  85.  
  86.             dev.VertexShader = null;
  87.             dev.PixelShader = null;
  88.         }
  89.  
  90.         private char[] GetCodepageChars(int codepage)
  91.         {
  92.             byte[] letters = new byte[223];
  93.             for (int i = 33; i < 256; ++i)
  94.             {
  95.                 letters[i - 33] = (byte)i;
  96.             }
  97.  
  98.             var encoding = Encoding.GetEncoding(codepage);
  99.             var str = encoding.GetChars(letters);
  100.             return str;
  101.         }
  102.  
  103.         private void LoadWhiteSpaces()
  104.         {
  105.             var size = mBitmapGraphics.MeasureString(" ", mGdiFont);
  106.             mGlyphs.Add(' ',
  107.                 new CharGlyphEntry()
  108.                 {
  109.                     IgnoreDraw = true,
  110.                     CharWidth = (int)size.Width,
  111.                     TexCoordBottom = Vector2.Zero,
  112.                     TexCoordTop = Vector2.Zero,
  113.                     TextureIndex = -1
  114.                 }
  115.                 );
  116.         }
  117.  
  118.         private void LoadCharRange(string range)
  119.         {
  120.             LoadCharRange(range.Distinct().ToArray());
  121.         }
  122.  
  123.         private void LoadCharRange(char[] chars)
  124.         {
  125.             List<char> newChars = new List<char>();
  126.  
  127.             foreach (char c in chars)
  128.             {
  129.                 if (mGlyphs.ContainsKey(c))
  130.                     continue;
  131.  
  132.                 newChars.Add(c);
  133.             }
  134.  
  135.             if (newChars.Count == 0)
  136.                 return;
  137.  
  138.             Bitmap bmp = new Bitmap(mFontHeight * 2, mFontHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
  139.             Graphics g = Graphics.FromImage(bmp);
  140.  
  141.             SolidBrush brush = new SolidBrush(Color.White);
  142.  
  143.             foreach (char c in newChars)
  144.             {
  145.                 g.Clear(Color.Transparent);
  146.                 g.DrawString(c.ToString(), mGdiFont, brush, PointF.Empty);
  147.  
  148.                 int charStart = mFontHeight * 2;
  149.                 int charEnd = 0;
  150.                 bool startFound = false;
  151.                 bool endFound = false;
  152.  
  153.                 for (int x = 0; x < mFontHeight * 2; ++x)
  154.                 {
  155.                     for (int y = 0; y < mFontHeight; ++y)
  156.                     {
  157.                         var clr = bmp.GetPixel(x, y);
  158.                         if (clr.A == 0)
  159.                             continue;
  160.  
  161.                         charStart = x;
  162.                         startFound = true;
  163.                         break;
  164.                     }
  165.  
  166.                     if (startFound)
  167.                         break;
  168.                 }
  169.                 for (int x = mFontHeight * 2 - 1; x >= 0; --x)
  170.                 {
  171.                     for (int y = 0; y < mFontHeight; ++y)
  172.                     {
  173.                         var clr = bmp.GetPixel(x, y);
  174.                         if (clr.A == 0)
  175.                             continue;
  176.  
  177.                         charEnd = x;
  178.                         endFound = true;
  179.                         break;
  180.                     }
  181.  
  182.                     if (endFound)
  183.                         break;
  184.                 }
  185.  
  186.                 CharGlyphEntry entry = new CharGlyphEntry();
  187.  
  188.                 if (charEnd < charStart)
  189.                 {
  190.                     entry.IgnoreDraw = true;
  191.                     continue;
  192.                 }
  193.  
  194.                 entry.CharWidth = (charEnd - charStart) + 1;
  195.                 entry.TextureIndex = mFontTextures.Count - 1;
  196.  
  197.                 if ((mCurOfsX + (charEnd - charStart) + 1) > mTextureSize)
  198.                 {
  199.                     mCurOfsX = 0;
  200.                     mCurOfsY += mFontHeight;
  201.                     if (mCurOfsY + mFontHeight >= mTextureSize)
  202.                     {
  203.                         UpdateTexture();
  204.                         AllocateNewTexture();
  205.                         mCurOfsY = 0;
  206.                     }
  207.                 }
  208.  
  209.                 entry.TexCoordTop = new SlimDX.Vector2((float)mCurOfsX / mTextureSize, (float)mCurOfsY / mTextureSize);
  210.                 entry.TexCoordBottom = new SlimDX.Vector2((float)(mCurOfsX + (charEnd - charStart) + 1) / mTextureSize, (float)(mCurOfsY + mFontHeight) / mTextureSize);
  211.                 entry.IgnoreDraw = false;
  212.  
  213.                 mGlyphs.Add(c, entry);
  214.                
  215.                 mBitmapGraphics.DrawImage(bmp, new RectangleF(mCurOfsX, mCurOfsY, (charEnd - charStart) + 1, mFontHeight), new RectangleF(charStart, 0, (charEnd - charStart) + 1, mFontHeight), GraphicsUnit.Pixel);
  216.                 mCurOfsX += (charEnd - charStart) + 1;
  217.             }
  218.  
  219.             UpdateTexture();
  220.         }
  221.  
  222.         private void UpdateTexture()
  223.         {
  224.             var lockData = mCurrentBitmap.LockBits(new Rectangle(0, 0, mTextureSize, mTextureSize), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
  225.             var surf = mCurrentTexture.GetSurfaceLevel(0);
  226.             Surface.FromStream(surf, new SlimDX.DataStream(lockData.Scan0, mTextureSize * mTextureSize * 4, true, true), Filter.Default, 0, Format.A8R8G8B8, 4 * mTextureSize, new Rectangle(0, 0, mTextureSize, mTextureSize));
  227.             surf.Dispose();
  228.             mCurrentBitmap.UnlockBits(lockData);
  229.         }
  230.  
  231.         private void AllocateNewTexture()
  232.         {
  233.             if (mCurrentBitmap != null)
  234.                 mBitmapGraphics.Clear(Color.Transparent);
  235.             else
  236.             {
  237.                 mCurrentBitmap = new Bitmap(mTextureSize, mTextureSize, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
  238.                 mBitmapGraphics = Graphics.FromImage(mCurrentBitmap);
  239.             }
  240.  
  241.             mCurrentTexture = new Texture(mTarget.GraphicsDevice, mTextureSize, mTextureSize, 1, Usage.None, Format.A8R8G8B8, Pool.Managed);
  242.             mFontTextures.Add(mCurrentTexture);
  243.         }
  244.  
  245.         private class CharGlyphEntry
  246.         {
  247.             public SlimDX.Vector2 TexCoordTop { get; set; }
  248.             public SlimDX.Vector2 TexCoordBottom { get; set; }
  249.             public int CharWidth { get; set; }
  250.             public int TextureIndex { get; set; }
  251.             public bool IgnoreDraw { get; set; }
  252.         }
  253.  
  254.         private int mFontHeight = 0;
  255.         private int mCurOfsX = 0;
  256.         private int mCurOfsY = 0;
  257.         private Graphics mBitmapGraphics;
  258.         private Bitmap mCurrentBitmap;
  259.         private Texture mCurrentTexture;
  260.         private Dictionary<char, CharGlyphEntry> mGlyphs = new Dictionary<char, CharGlyphEntry>();
  261.         private List<Texture> mFontTextures = new List<Texture>();
  262.         private int mTextureSize;
  263.         private System.Drawing.Font mGdiFont;
  264.         private Rendertarget9 mTarget;
  265.         private ShaderCompiler<VertexShader> mVertexShader;
  266.         private ShaderCompiler<PixelShader> mPixelShader;
  267.         private ConstantDescription mMatrixParam;
  268.     }
  269. }
Advertisement
Add Comment
Please, Sign In to add comment