Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
GlyphPacker.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.Collections.Generic;
80 using System.Drawing;
81 using System.Drawing.Imaging;
82 
83 namespace SiliconStudio.Paradox.Assets.SpriteFont.Compiler
84 {
85  // Helper for arranging many small bitmaps onto a single larger surface.
86  internal static class GlyphPacker
87  {
88  public static Bitmap ArrangeGlyphs(Glyph[] sourceGlyphs)
89  {
90  // Build up a list of all the glyphs needing to be arranged.
91  List<ArrangedGlyph> glyphs = new List<ArrangedGlyph>();
92 
93  for (int i = 0; i < sourceGlyphs.Length; i++)
94  {
95  ArrangedGlyph glyph = new ArrangedGlyph();
96 
97  glyph.Source = sourceGlyphs[i];
98 
99  // Leave a one pixel border around every glyph in the output bitmap.
100  glyph.Width = sourceGlyphs[i].Subrect.Width + 2;
101  glyph.Height = sourceGlyphs[i].Subrect.Height + 2;
102 
103  glyphs.Add(glyph);
104  }
105 
106  // Sort so the largest glyphs get arranged first.
107  glyphs.Sort(CompareGlyphSizes);
108 
109  // Work out how big the output bitmap should be.
110  int outputWidth = GuessOutputWidth(sourceGlyphs);
111  int outputHeight = 0;
112 
113  // Choose positions for each glyph, one at a time.
114  for (int i = 0; i < glyphs.Count; i++)
115  {
116  PositionGlyph(glyphs, i, outputWidth);
117 
118  outputHeight = Math.Max(outputHeight, glyphs[i].Y + glyphs[i].Height);
119  }
120 
121  // Create the merged output bitmap.
122  outputHeight = MakeValidTextureSize(outputHeight, false);
123 
124  return CopyGlyphsToOutput(glyphs, outputWidth, outputHeight);
125  }
126 
127 
128  // Once arranging is complete, copies each glyph to its chosen position in the single larger output bitmap.
129  static Bitmap CopyGlyphsToOutput(List<ArrangedGlyph> glyphs, int width, int height)
130  {
131  Bitmap output = new Bitmap(width, height, PixelFormat.Format32bppArgb);
132 
133  foreach (ArrangedGlyph glyph in glyphs)
134  {
135  Glyph sourceGlyph = glyph.Source;
136  Rectangle sourceRegion = sourceGlyph.Subrect;
137  Rectangle destinationRegion = new Rectangle(glyph.X + 1, glyph.Y + 1, sourceRegion.Width, sourceRegion.Height);
138 
139  BitmapUtils.CopyRect(sourceGlyph.Bitmap, sourceRegion, output, destinationRegion);
140 
141  BitmapUtils.PadBorderPixels(output, destinationRegion);
142 
143  sourceGlyph.Bitmap = output;
144  sourceGlyph.Subrect = destinationRegion;
145  }
146 
147  return output;
148  }
149 
150 
151  // Internal helper class keeps track of a glyph while it is being arranged.
152  class ArrangedGlyph
153  {
154  public Glyph Source;
155 
156  public int X;
157  public int Y;
158 
159  public int Width;
160  public int Height;
161  }
162 
163 
164  // Works out where to position a single glyph.
165  static void PositionGlyph(List<ArrangedGlyph> glyphs, int index, int outputWidth)
166  {
167  int x = 0;
168  int y = 0;
169 
170  while (true)
171  {
172  // Is this position free for us to use?
173  int intersects = FindIntersectingGlyph(glyphs, index, x, y);
174 
175  if (intersects < 0)
176  {
177  glyphs[index].X = x;
178  glyphs[index].Y = y;
179 
180  return;
181  }
182 
183  // Skip past the existing glyph that we collided with.
184  x = glyphs[intersects].X + glyphs[intersects].Width;
185 
186  // If we ran out of room to move to the right, try the next line down instead.
187  if (x + glyphs[index].Width > outputWidth)
188  {
189  x = 0;
190  y++;
191  }
192  }
193  }
194 
195 
196  // Checks if a proposed glyph position collides with anything that we already arranged.
197  static int FindIntersectingGlyph(List<ArrangedGlyph> glyphs, int index, int x, int y)
198  {
199  int w = glyphs[index].Width;
200  int h = glyphs[index].Height;
201 
202  for (int i = 0; i < index; i++)
203  {
204  if (glyphs[i].X >= x + w)
205  continue;
206 
207  if (glyphs[i].X + glyphs[i].Width <= x)
208  continue;
209 
210  if (glyphs[i].Y >= y + h)
211  continue;
212 
213  if (glyphs[i].Y + glyphs[i].Height <= y)
214  continue;
215 
216  return i;
217  }
218 
219  return -1;
220  }
221 
222 
223  // Comparison function for sorting glyphs by size.
224  static int CompareGlyphSizes(ArrangedGlyph a, ArrangedGlyph b)
225  {
226  const int heightWeight = 1024;
227 
228  int aSize = a.Height * heightWeight + a.Width;
229  int bSize = b.Height * heightWeight + b.Width;
230 
231  if (aSize != bSize)
232  return bSize.CompareTo(aSize);
233  else
234  return a.Source.Character.CompareTo(b.Source.Character);
235  }
236 
237 
238  // Heuristic guesses what might be a good output width for a list of glyphs.
239  static int GuessOutputWidth(Glyph[] sourceGlyphs)
240  {
241  int maxWidth = 0;
242  int totalSize = 0;
243 
244  foreach (Glyph glyph in sourceGlyphs)
245  {
246  maxWidth = Math.Max(maxWidth, glyph.Subrect.Width);
247  totalSize += glyph.Subrect.Width * glyph.Subrect.Height;
248  }
249 
250  int width = Math.Max((int)Math.Sqrt(totalSize), maxWidth);
251 
252  return MakeValidTextureSize(width, true);
253  }
254 
255 
256  // Rounds a value up to the next larger valid texture size.
257  static int MakeValidTextureSize(int value, bool requirePowerOfTwo)
258  {
259  // In case we want to DXT compress, make sure the size is a multiple of 4.
260  const int blockSize = 4;
261 
262  if (requirePowerOfTwo)
263  {
264  // Round up to a power of two.
265  int powerOfTwo = blockSize;
266 
267  while (powerOfTwo < value)
268  powerOfTwo <<= 1;
269 
270  return powerOfTwo;
271  }
272  else
273  {
274  // Round up to the specified block size.
275  return (value + blockSize - 1) & ~(blockSize - 1);
276  }
277  }
278  }
279 }
function b
function a
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ float size_t y
Definition: DirectXTexP.h:191
System.Windows.Shapes.Rectangle Rectangle
Definition: ColorPicker.cs:16
PixelFormat
Defines various types of pixel formats.
Definition: PixelFormat.cs:32