Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
SpriteFontWriter.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 //
4 // Copyright (c) 2010-2013 SharpDX - Alexandre Mutel
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to deal
8 // in the Software without restriction, including without limitation the rights
9 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 // copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 // THE SOFTWARE.
23 // -----------------------------------------------------------------------------
24 // The following code is a port of MakeSpriteFont from DirectXTk
25 // http://go.microsoft.com/fwlink/?LinkId=248929
26 // -----------------------------------------------------------------------------
27 // Microsoft Public License (Ms-PL)
28 //
29 // This license governs use of the accompanying software. If you use the
30 // software, you accept this license. If you do not accept the license, do not
31 // use the software.
32 //
33 // 1. Definitions
34 // The terms "reproduce," "reproduction," "derivative works," and
35 // "distribution" have the same meaning here as under U.S. copyright law.
36 // A "contribution" is the original software, or any additions or changes to
37 // the software.
38 // A "contributor" is any person that distributes its contribution under this
39 // license.
40 // "Licensed patents" are a contributor's patent claims that read directly on
41 // its contribution.
42 //
43 // 2. Grant of Rights
44 // (A) Copyright Grant- Subject to the terms of this license, including the
45 // license conditions and limitations in section 3, each contributor grants
46 // you a non-exclusive, worldwide, royalty-free copyright license to reproduce
47 // its contribution, prepare derivative works of its contribution, and
48 // distribute its contribution or any derivative works that you create.
49 // (B) Patent Grant- Subject to the terms of this license, including the license
50 // conditions and limitations in section 3, each contributor grants you a
51 // non-exclusive, worldwide, royalty-free license under its licensed patents to
52 // make, have made, use, sell, offer for sale, import, and/or otherwise dispose
53 // of its contribution in the software or derivative works of the contribution
54 // in the software.
55 //
56 // 3. Conditions and Limitations
57 // (A) No Trademark License- This license does not grant you rights to use any
58 // contributors' name, logo, or trademarks.
59 // (B) If you bring a patent claim against any contributor over patents that
60 // you claim are infringed by the software, your patent license from such
61 // contributor to the software ends automatically.
62 // (C) If you distribute any portion of the software, you must retain all
63 // copyright, patent, trademark, and attribution notices that are present in the
64 // software.
65 // (D) If you distribute any portion of the software in source code form, you
66 // may do so only under this license by including a complete copy of this
67 // license with your distribution. If you distribute any portion of the software
68 // in compiled or object code form, you may only do so under a license that
69 // complies with this license.
70 // (E) The software is licensed "as-is." You bear the risk of using it. The
71 // contributors give no express warranties, guarantees or conditions. You may
72 // have additional consumer rights under your local laws which this license
73 // cannot change. To the extent permitted under your local laws, the
74 // contributors exclude the implied warranties of merchantability, fitness for a
75 // particular purpose and non-infringement.
76 //--------------------------------------------------------------------
77 
78 using System;
79 using System.Drawing;
80 using System.Drawing.Imaging;
81 using System.Runtime.InteropServices;
82 using SiliconStudio.Core.Mathematics;
83 using SiliconStudio.Core.Serialization;
84 using SiliconStudio.Paradox.Graphics;
86 
87 namespace SiliconStudio.Paradox.Assets.SpriteFont.Compiler
88 {
89  // Writes the output sprite font binary file.
90  internal static class SpriteFontWriter
91  {
92  public static StaticSpriteFontData CreateSpriteFontData(SpriteFontAsset options, Glyph[] glyphs, float lineSpacing, float baseLine, Bitmap bitmap)
93  {
94  var spriteFontData = new StaticSpriteFontData
95  {
96  Size = FontHelper.PointsToPixels(options.Size),
97  BaseOffset = baseLine,
98  FontDefaultLineSpacing = lineSpacing,
99  ExtraLineSpacing = options.LineSpacing,
100  ExtraSpacing = options.Spacing,
101  DefaultCharacter = options.DefaultCharacter
102  };
103 
104  WriteGlyphs(spriteFontData, glyphs);
105 
106  spriteFontData.Bitmaps = new ContentReference<Graphics.Image>[1];
107  var image = GetImage(options, bitmap);
108  spriteFontData.Bitmaps[0] = new ContentReference<Graphics.Image> { Value = image };
109 
110  return spriteFontData;
111  }
112 
113  static void WriteGlyphs(StaticSpriteFontData spriteFont, Glyph[] glyphs)
114  {
115  spriteFont.Glyphs = new Graphics.Font.Glyph[glyphs.Length];
116  for (int i = 0; i < glyphs.Length; i++)
117  {
118  var glyph = glyphs[i];
119  spriteFont.Glyphs[i] = new Graphics.Font.Glyph
120  {
121  Character = glyph.Character,
122  Subrect = new Core.Mathematics.Rectangle(glyph.Subrect.X, glyph.Subrect.Y, glyph.Subrect.Width, glyph.Subrect.Height),
123  Offset = new Vector2(glyph.XOffset, glyph.YOffset),
124  XAdvance = glyph.XAdvance,
125  };
126  }
127  }
128 
129  static Graphics.Image GetImage(SpriteFontAsset options, Bitmap bitmap)
130  {
131  switch (options.Format)
132  {
133  //case FontTextureFormat.Auto:
134  case FontTextureFormat.Rgba32:
135  return GetImageRgba32(bitmap);
136 
137  //case FontTextureFormat.CompressedMono:
138  // return GetCompressedMono(bitmap, options);
139 
140  default:
141  throw new NotSupportedException();
142  }
143  }
144 
145 
146  // Writes an uncompressed 32 bit font texture.
147  static Graphics.Image GetImageRgba32(Bitmap bitmap)
148  {
149  var image = Graphics.Image.New2D(bitmap.Width, bitmap.Height, 1, Graphics.PixelFormat.R8G8B8A8_UNorm);
150  var pixelBuffer = image.PixelBuffer[0];
151  using (var bitmapData = new BitmapUtils.PixelAccessor(bitmap, ImageLockMode.ReadOnly))
152  {
153  for (int y = 0; y < bitmap.Height; y++)
154  {
155  for (int x = 0; x < bitmap.Width; x++)
156  {
157  var color = bitmapData[x, y];
158  pixelBuffer.SetPixel(x, y, new Core.Mathematics.Color(color.R, color.G, color.B, color.A));
159  }
160  }
161  }
162  return image;
163  }
164 
165  // Writes a block compressed monochromatic font texture.
166  static unsafe Graphics.Image GetCompressedMono(Bitmap bitmap, SpriteFontAsset options)
167  {
168  if ((bitmap.Width & 3) != 0 ||
169  (bitmap.Height & 3) != 0)
170  {
171  throw new ArgumentException("Block compression requires texture size to be a multiple of 4.");
172  }
173 
174  var image = Graphics.Image.New2D(bitmap.Width, bitmap.Height, 1, Graphics.PixelFormat.BC2_UNorm);
175  var pixelBuffer = (BC2Pixel*)image.PixelBuffer[0].DataPointer;
176  using (var bitmapData = new BitmapUtils.PixelAccessor(bitmap, ImageLockMode.ReadOnly))
177  {
178  for (int y = 0; y < bitmap.Height; y += 4)
179  {
180  for (int x = 0; x < bitmap.Width; x += 4)
181  {
182  BC2Pixel bc2Pixel;
183  CompressBlock( bitmapData, x, y, options, out bc2Pixel);
184  *pixelBuffer = bc2Pixel;
185  pixelBuffer++;
186  }
187  }
188  }
189  return image;
190  }
191 
192  [StructLayout(LayoutKind.Sequential, Pack = 4)]
193  struct BC2Pixel
194  {
195  public long AlphaBits;
196  public uint EndPoint;
197  public int RgbBits;
198  }
199 
200 
201  // We want to compress our font textures, because, like, smaller is better,
202  // right? But a standard DXT compressor doesn't do a great job with fonts that
203  // are in premultiplied alpha format. Our font data is greyscale, so all of the
204  // RGBA channels have the same value. If one channel is compressed differently
205  // to another, this causes an ugly variation in brightness of the rendered text.
206  // Also, fonts are mostly either black or white, with grey values only used for
207  // antialiasing along their edges. It is very important that the black and white
208  // areas be accurately represented, while the precise value of grey is less
209  // important.
210  //
211  // Trouble is, your average DXT compressor knows nothing about these
212  // requirements. It will optimize to minimize a generic error metric such as
213  // RMS, but this will often sacrifice crisp black and white in exchange for
214  // needless accuracy of the antialiasing pixels, or encode RGB differently to
215  // alpha. UGLY!
216  //
217  // Fortunately, encoding monochrome fonts turns out to be trivial. Using DXT3,
218  // we can fix the end colors as black and white, which gives guaranteed exact
219  // encoding of the font inside and outside, plus two fractional values for edge
220  // antialiasing. Also, these RGB values (0, 1/3, 2/3, 1) map exactly to four of
221  // the possible 16 alpha values available in DXT3, so we can ensure the RGB and
222  // alpha channels always exactly match.
223 
224  static void CompressBlock(BitmapUtils.PixelAccessor bitmapData, int blockX, int blockY, SpriteFontAsset options, out BC2Pixel bc2Pixel)
225  {
226  long alphaBits = 0;
227  int rgbBits = 0;
228 
229  int pixelCount = 0;
230 
231  for (int y = 0; y < 4; y++)
232  {
233  for (int x = 0; x < 4; x++)
234  {
235  long alpha;
236  int rgb;
237 
238  int value = bitmapData[blockX + x, blockY + y].A;
239 
240  if (options.NoPremultiply)
241  {
242  // If we are not premultiplied, RGB is always white and we have 4 bit alpha.
243  alpha = value >> 4;
244  rgb = 0;
245  }
246  else
247  {
248  // For premultiplied encoding, quantize the source value to 2 bit precision.
249  if (value < 256 / 6)
250  {
251  alpha = 0;
252  rgb = 1;
253  }
254  else if (value < 256 / 2)
255  {
256  alpha = 5;
257  rgb = 3;
258  }
259  else if (value < 256 * 5 / 6)
260  {
261  alpha = 10;
262  rgb = 2;
263  }
264  else
265  {
266  alpha = 15;
267  rgb = 0;
268  }
269  }
270 
271  // Add this pixel to the alpha and RGB bit masks.
272  alphaBits |= alpha << (pixelCount * 4);
273  rgbBits |= rgb << (pixelCount * 2);
274 
275  pixelCount++;
276  }
277  }
278 
279  // Output the alpha bit mask.
280  bc2Pixel.AlphaBits = alphaBits;
281 
282  // Output the two endpoint colors (black and white in 5.6.5 format).
283  bc2Pixel.EndPoint = 0x0000FFFF;
284 
285  // Output the RGB bit mask.
286  bc2Pixel.RgbBits = rgbBits;
287  }
288  }
289 }
SiliconStudio.Paradox.Games.Mathematics.Vector2 Vector2
char DefaultCharacter
The default character fall-back.
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ float size_t y
Definition: DirectXTexP.h:191
SharpDX.DirectWrite.Font Font
SpriteFont to use with SpriteBatch. See SpriteFont to learn how to use it.
Definition: SpriteFont.cs:26
Description of a glyph (a single character)
Definition: Glyph.cs:12
Data for a static SpriteFont object that supports kerning.