package Packer { import flash.text.TextField; import flash.text.TextFormat; import flash.text.TextFieldType; import flash.text.TextFieldAutoSize; import flash.text.TextFormatAlign; import flash.display.Bitmap; import flash.display.BitmapData; import flash.geom.*; import flash.display.MovieClip; import flash.text.AntiAliasType; import flash.display.Sprite; import flash.display.Graphics; import flash.text.TextLineMetrics; import djarts.core.*; public class BitmapFont { public var CodepointData:Array = new Array(); public var IndexByCodepoint = {}; public var Name = ""; public var Size; public var Bold; public var AsBackupOnly = false; private var backupFont:BitmapFont = null; private var useBackupCodepoints = {}; private var useDeviceFontIfNeccessary = true; private var fontFaceName; public function BitmapFont(font:String, size:int, bold, backupFont:BitmapFont = null, useBackupCodepoints:String = null, asBackupOnly = false, useDeviceFontIfNeccessary = true) { this.fontFaceName = font; this.Name = font + size + (bold ? "Bold" : ""); this.Size = size; this.Bold = bold; this.backupFont = backupFont; if (useBackupCodepoints != null) { for (var i = 0; i < useBackupCodepoints.length; i++) { this.useBackupCodepoints[useBackupCodepoints.charCodeAt(i)] = true; } } this.useDeviceFontIfNeccessary = useDeviceFontIfNeccessary; this.AsBackupOnly = asBackupOnly; var additionalChars = ""; /* for (var i = 1024; i < 1280; i++) { additionalChars += String.fromCharCode(i); } */ CreateFrames(font, size, bold, additionalChars /*"δΎ§"*/); } private function AddCodepoint(data:FontCodepointData) { IndexByCodepoint[data.Codepoint] = CodepointData.length; CodepointData.push(data); } private var lineHeight = 10; public function CreateFrames(font:String, size:int, bold, additionalCodepoints:String) { var base:String = ""; for (var i = 32; i < 256; i++) { base += String.fromCharCode(i); } var text:String = base + additionalCodepoints; var t:TextField = new TextField(); var f:TextFormat = new TextFormat(); f.font = font; f.color = 0xFFFFFF; f.size = size; f.bold = bold; t.type = TextFieldType.DYNAMIC; t.defaultTextFormat = f; t.selectable = false; t.autoSize = TextFieldAutoSize.LEFT; t.embedFonts = true; t.antiAliasType = AntiAliasType.ADVANCED; var tDevice:TextField = new TextField(); tDevice.type = TextFieldType.DYNAMIC; tDevice.defaultTextFormat = f; tDevice.selectable = false; tDevice.autoSize = TextFieldAutoSize.LEFT; tDevice.embedFonts = false; tDevice.antiAliasType = AntiAliasType.ADVANCED; t.text = "Test"; var testMetrics:TextLineMetrics = t.getLineMetrics(0); lineHeight = testMetrics.height; for (var i = 0; i < text.length; i++) { var codepointStr = text.charAt(i); var codepoint = text.charCodeAt(i); var field:TextField = t; field.text = codepointStr; var lm:TextLineMetrics = t.getLineMetrics(0); if ((lm.width == 0 && codepoint != 32) || this.useBackupCodepoints[codepoint]) { // not sure we need this recursive search, actually var searchFont = this; var found = false; while (searchFont != null) { if (searchFont.backupFont != null && searchFont.backupFont.IndexByCodepoint[codepoint] != undefined) { // use the backup font's frame var index = searchFont.backupFont.IndexByCodepoint[codepoint]; if (searchFont.backupFont.CodepointData[index] && searchFont.backupFont.CodepointData[index].CodepointWidth != 0) { var data:FontCodepointData = new FontCodepointData(codepoint); data.InitFromOtherFont(searchFont.backupFont, index); AddCodepoint(data); searchFont.backupFont.CodepointData[searchFont.backupFont.IndexByCodepoint[codepoint]].References++; found = true; break; } } break; //searchFont = searchFont.backupFont; } if (found) continue; if (this.useBackupCodepoints[codepoint]) { // back up font didn't have this character, so skip continue; } if (this.useDeviceFontIfNeccessary) { field = tDevice; tDevice.text = codepointStr; lm = tDevice.getLineMetrics(0); } } var bounds:Rectangle = CacheManager.Instance().GetAccurateBounds(field); bounds.left = Math.floor(bounds.left); bounds.right = Math.ceil(bounds.right); bounds.top = Math.floor(bounds.top); bounds.bottom = Math.ceil(bounds.bottom); if ((bounds.width == 0 || bounds.height == 0) && codepoint != 32) continue; var offsetX = 0; var offsetY = 0; if (fontFaceName == "Grobold" && codepointStr == ".") { var tf:TextFormat = field.defaultTextFormat; tf.size = size + 25; field.defaultTextFormat = tf; // is this neccessary to refresh the size??? field.text = field.text; var newBounds:Rectangle = CacheManager.Instance().GetAccurateBounds(field); newBounds.left = Math.floor(newBounds.left); newBounds.right = Math.ceil(newBounds.right); newBounds.top = Math.floor(newBounds.top); newBounds.bottom = Math.ceil(newBounds.bottom); offsetY -= (newBounds.bottom - bounds.bottom); bounds.left = newBounds.left; bounds.right = newBounds.right; bounds.top = Math.min(bounds.top, newBounds.top + offsetY); lm = t.getLineMetrics(0); } if (fontFaceName == "Grobold" && (codepointStr == "!" || codepointStr == "%")) { var adjust = Math.floor(bounds.left * 0.7); bounds.x -= adjust; offsetX -= adjust; } var bitmapData:BitmapData = new BitmapData(bounds.width + GraphicPacker.PAD * 2, bounds.height + GraphicPacker.PAD * 2, true, 0x00000000); bitmapData.draw(field, new Matrix(1, 0, 0, 1, -bounds.left + GraphicPacker.PAD + offsetX, -bounds.top + GraphicPacker.PAD + offsetY)); var data:FontCodepointData = new FontCodepointData(codepoint); var offset:Point = new Point(-bounds.left + GraphicPacker.PAD, -bounds.top + GraphicPacker.PAD); var codepointWidth = Math.ceil(lm.width); if (lm.width > bounds.width && bounds.width != 0) { codepointWidth = bounds.width; } data.Init(bitmapData, offset, codepointWidth); AddCodepoint(data); if (fontFaceName == "Grobold" && codepointStr == ".") { var tf:TextFormat = field.defaultTextFormat; tf.size = size; field.defaultTextFormat = tf; } } } public function GetAdditionalData() { var codepoints:Array = new Array(); var advances:Array = new Array(); // the width of the character (not the character graphic) is called advance in the client for (var i = 0; i < CodepointData.length; i++) { codepoints.push(CodepointData[i].Codepoint); advances.push(CodepointData[i].CodepointWidth); } return {"codepoints":codepoints,"advances":advances,"line_height":lineHeight}; } } }