public void generateAtlases(string outputPath, int maxWidth, int maxHeight, bool genJSON, bool genRBXLua)
{
int atlas = 0;
int posX = 0, posY = 0;
List<Bitmap> bitmaps = new List<Bitmap>();
Dictionary<string, List<FontInfo>> infos = new Dictionary<string, List<FontInfo>>();
Bitmap bitmap = new Bitmap(maxWidth, maxHeight, PixelFormat.Format32bppArgb);
Graphics graphics = Graphics.FromImage(bitmap);
graphics.Clear(Color.Transparent);
foreach (Face face in faces)
{
infos[face.StyleName] = new List<FontInfo>();
for (int i = 0; i < sizes.Length; i++)
{
int size = sizes[i];
FontInfo info = new FontInfo(face.StyleName, size);
int width = 0;
int height = 0;
int lineHeight = 0;
int firstAdjust = 0;
face.SetPixelSizes((uint)size + extraSize, (uint)size + extraSize);
face.SetUnpatentedHinting(true);
getKernWidthHeight(face, info, out width, out lineHeight, out firstAdjust);
if (width > maxWidth)
{
int overlaps = (int)Math.Truncate((float)(width / maxWidth));
width = maxWidth;
height = (overlaps + 1) * (lineHeight + padY);
}
else
{
width = maxWidth;
height = lineHeight + padY;
}
for (int j = 0; j < characters.Length; j++)
{
char character = characters[j];
uint index = face.GetCharIndex(character);
face.LoadGlyph(index, LoadFlags.Default, LoadTarget.Normal);
face.Glyph.RenderGlyph(RenderMode.Normal);
// case where the glyph won't fit horizontally
if (posX + face.Glyph.Metrics.Width + face.Glyph.BitmapLeft + padX > width)
{
posX = 0;
posY += lineHeight + padY;
}
// case where the glyph won't fit vertically
if (posY > maxHeight - (lineHeight + padY))
{
bitmaps.Add(bitmap);
bitmap = new Bitmap(maxWidth, maxHeight, PixelFormat.Format32bppArgb);
graphics = Graphics.FromImage(bitmap);
graphics.Clear(Color.Transparent);
posX = 0;
posY = 0;
atlas++;
}
// draw the character
posX += renderCharacter(face, characters[j], posX, posY, atlas, info, graphics) + padX;
}
// new font size means resetting some stuff
posX = 0;
posY += lineHeight + padY;
// set the info line height and first adjust
info.lineHeight = lineHeight;
info.firstAdjust = firstAdjust;
// add the info to the list
infos[face.StyleName].Add(info);
}
}
// add the current bitmap
bitmaps.Add(bitmap);
graphics.Dispose();
// export
int count = 0;
foreach (Bitmap bmp in bitmaps)
{
count++;
bmp.Save(outputPath + "\\" + family + "_" + count + ".png");
}
// export data
if (genJSON)
{
int c = 0;
string output = prepOutputDataJSON();
foreach (Face face in faces)
{
c++;
output += "\t\t\"" + face.StyleName + "\" : {\n";
int c2 = 0;
foreach (FontInfo info in infos[face.StyleName])
{
c2++;
output += info.makeJSON("\t\t\t") + (c2 < infos[face.StyleName].Count ? "," : "") + "\n";
}
output += "\t\t}" + (c < faces.Length ? "," : "") + "\n";
}
output += "\t}\n}";
// write json file
File.WriteAllText(outputPath + "\\" + family + ".json", output);
}
if (genRBXLua)
{
int c = 0;
string output = prepOutputDataLua();
foreach (Face face in faces)
{
c++;
output += "\t\t[\"" + face.StyleName + "\"] = {\n";
int c2 = 0;
foreach (FontInfo info in infos[face.StyleName])
{
c2++;
output += info.makeLua("\t\t\t") + (c2 < infos[face.StyleName].Count ? "," : "") + "\n";
}
output += "\t\t}" + (c < faces.Length ? "," : "") + "\n";
}
output += "\t}\n}";
// Setup module
string header = "--[[\n\t@Font " + family + "\n";
header += "\t@Sizes {" + string.Join(", ", sizes) + "}\n";
header += "\t@Author N/A\n";
header += "\t@Link N/A\n--]]\n\n";
header += "local module = {}\n\n";
header += "module.atlases = {\n";
for (int i = 1; i <= count; i++)
{
header += "\t[" + i + "] = \"rbxassetid://\";\n";
}
header += "};\n\nmodule.font = " + output;
header += "\n\nreturn module";
// write Lua file
File.WriteAllText(outputPath + "\\" + family + ".lua", header);
}
}