Newer
Older
exporter / Packer / BitmapFont.as
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};
		}
		

	}
	
}