All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scaffold.libs_as.starling.text.BitmapFont.as Maven / Gradle / Ivy

// =================================================================================================
//
//	Starling Framework
//	Copyright 2011-2015 Gamua. All Rights Reserved.
//
//	This program is free software. You can redistribute and/or modify it
//	in accordance with the terms of the accompanying license agreement.
//
// =================================================================================================

package starling.text
{
    import flash.geom.Rectangle;
    import flash.utils.Dictionary;

    import starling.display.Image;
    import starling.display.MeshBatch;
    import starling.display.Sprite;
    import starling.textures.Texture;
    import starling.textures.TextureSmoothing;
    import starling.utils.Align;
    import starling.utils.StringUtil;

    /** The BitmapFont class parses bitmap font files and arranges the glyphs
     *  in the form of a text.
     *
     *  The class parses the XML format as it is used in the 
     *  AngelCode Bitmap Font Generator or
     *  the Glyph Designer. 
     *  This is what the file format looks like:
     *
     *  
 
     *  <font>
     *    <info face="BranchingMouse" size="40" />
     *    <common lineHeight="40" />
     *    <pages>  <!-- currently, only one page is supported -->
     *      <page id="0" file="texture.png" />
     *    </pages>
     *    <chars>
     *      <char id="32" x="60" y="29" width="1" height="1" xoffset="0" yoffset="27" xadvance="8" />
     *      <char id="33" x="155" y="144" width="9" height="21" xoffset="0" yoffset="6" xadvance="9" />
     *    </chars>
     *    <kernings> <!-- Kerning is optional -->
     *      <kerning first="83" second="83" amount="-4"/>
     *    </kernings>
     *  </font>
     *  
* * Pass an instance of this class to the method registerBitmapFont of the * TextField class. Then, set the fontName property of the text field to the * name value of the bitmap font. This will make the text field use the bitmap * font. */ public class BitmapFont implements ITextCompositor { /** Use this constant for the fontSize property of the TextField class to * render the bitmap font in exactly the size it was created. */ public static const NATIVE_SIZE:int = -1; /** The font name of the embedded minimal bitmap font. Use this e.g. for debug output. */ public static const MINI:String = "mini"; private static const CHAR_SPACE:int = 32; private static const CHAR_TAB:int = 9; private static const CHAR_NEWLINE:int = 10; private static const CHAR_CARRIAGE_RETURN:int = 13; private var _texture:Texture; private var _chars:Dictionary; private var _name:String; private var _size:Number; private var _lineHeight:Number; private var _baseline:Number; private var _offsetX:Number; private var _offsetY:Number; private var _helperImage:Image; // helper objects private static var sLines:Array = []; private static var sDefaultOptions:TextOptions = new TextOptions(); /** Creates a bitmap font by parsing an XML file and uses the specified texture. * If you don't pass any data, the "mini" font will be created. */ public function BitmapFont(texture:Texture=null, fontXml:XML=null) { // if no texture is passed in, we create the minimal, embedded font if (texture == null && fontXml == null) { texture = MiniBitmapFont.texture; fontXml = MiniBitmapFont.xml; } else if (texture != null && fontXml == null) { throw new ArgumentError("fontXml cannot be null!"); } _name = "unknown"; _lineHeight = _size = _baseline = 14; _offsetX = _offsetY = 0.0; _texture = texture; _chars = new Dictionary(); _helperImage = new Image(texture); parseFontXml(fontXml); } /** Disposes the texture of the bitmap font! */ public function dispose():void { if (_texture) _texture.dispose(); } private function parseFontXml(fontXml:XML):void { var scale:Number = _texture.scale; var frame:Rectangle = _texture.frame; var frameX:Number = frame ? frame.x : 0; var frameY:Number = frame ? frame.y : 0; _name = StringUtil.clean(fontXml.info.@face); _size = parseFloat(fontXml.info.@size) / scale; _lineHeight = parseFloat(fontXml.common.@lineHeight) / scale; _baseline = parseFloat(fontXml.common.@base) / scale; if ([email protected]() == "0") smoothing = TextureSmoothing.NONE; if (_size <= 0) { trace("[Starling] Warning: invalid font size in '" + _name + "' font."); _size = (_size == 0.0 ? 16.0 : _size * -1.0); } for each (var charElement:XML in fontXml.chars.char) { var id:int = parseInt(charElement.@id); var xOffset:Number = parseFloat(charElement.@xoffset) / scale; var yOffset:Number = parseFloat(charElement.@yoffset) / scale; var xAdvance:Number = parseFloat(charElement.@xadvance) / scale; var region:Rectangle = new Rectangle(); region.x = parseFloat(charElement.@x) / scale + frameX; region.y = parseFloat(charElement.@y) / scale + frameY; region.width = parseFloat(charElement.@width) / scale; region.height = parseFloat(charElement.@height) / scale; var texture:Texture = Texture.fromTexture(_texture, region); var bitmapChar:BitmapChar = new BitmapChar(id, texture, xOffset, yOffset, xAdvance); addChar(id, bitmapChar); } for each (var kerningElement:XML in fontXml.kernings.kerning) { var first:int = parseInt(kerningElement.@first); var second:int = parseInt(kerningElement.@second); var amount:Number = parseFloat(kerningElement.@amount) / scale; if (second in _chars) getChar(second).addKerning(first, amount); } } /** Returns a single bitmap char with a certain character ID. */ public function getChar(charID:int):BitmapChar { return _chars[charID]; } /** Adds a bitmap char with a certain character ID. */ public function addChar(charID:int, bitmapChar:BitmapChar):void { _chars[charID] = bitmapChar; } /** Returns a vector containing all the character IDs that are contained in this font. */ public function getCharIDs(out:Vector.=null):Vector. { if (out == null) out = new []; for(var key:* in _chars) out[out.length] = int(key); return out; } /** Checks whether a provided string can be displayed with the font. */ public function hasChars(text:String):Boolean { if (text == null) return true; var charID:int; var numChars:int = text.length; for (var i:int=0; i = arrangeChars(width, height, text, format, options); var numChars:int = charLocations.length; var sprite:Sprite = new Sprite(); for (var i:int=0; i = arrangeChars( width, height, text, format, options); var numChars:int = charLocations.length; _helperImage.color = format.color; for (var i:int=0; i { if (text == null || text.length == 0) return CharLocation.vectorFromPool(); if (options == null) options = sDefaultOptions; var kerning:Boolean = format.kerning; var leading:Number = format.leading; var hAlign:String = format.horizontalAlign; var vAlign:String = format.verticalAlign; var fontSize:Number = format.size; var autoScale:Boolean = options.autoScale; var wordWrap:Boolean = options.wordWrap; var finished:Boolean = false; var charLocation:CharLocation; var numChars:int; var containerWidth:Number; var containerHeight:Number; var scale:Number; var i:int, j:int; if (fontSize < 0) fontSize *= -_size; while (!finished) { sLines.length = 0; scale = fontSize / _size; containerWidth = width / scale; containerHeight = height / scale; if (_lineHeight <= containerHeight) { var lastWhiteSpace:int = -1; var lastCharID:int = -1; var currentX:Number = 0; var currentY:Number = 0; var currentLine:Vector. = CharLocation.vectorFromPool(); numChars = text.length; for (i=0; i containerWidth) { if (wordWrap) { // when autoscaling, we must not split a word in half -> restart if (autoScale && lastWhiteSpace == -1) break; // remove characters and add them again to next line var numCharsToRemove:int = lastWhiteSpace == -1 ? 1 : i - lastWhiteSpace; for (j=0; j 3) fontSize -= 1; else finished = true; } // while (!finished) var finalLocations:Vector. = CharLocation.vectorFromPool(); var numLines:int = sLines.length; var bottom:Number = currentY + _lineHeight; var yOffset:int = 0; if (vAlign == Align.BOTTOM) yOffset = containerHeight - bottom; else if (vAlign == Align.CENTER) yOffset = (containerHeight - bottom) / 2; for (var lineID:int=0; lineID = sLines[lineID]; numChars = line.length; if (numChars == 0) continue; var xOffset:int = 0; var lastLocation:CharLocation = line[line.length-1]; var right:Number = lastLocation.x - lastLocation.char.xOffset + lastLocation.char.xAdvance; if (hAlign == Align.RIGHT) xOffset = containerWidth - right; else if (hAlign == Align.CENTER) xOffset = (containerWidth - right) / 2; for (var c:int=0; c 0 && charLocation.char.height > 0) finalLocations[finalLocations.length] = charLocation; } } return finalLocations; } /** The name of the font as it was parsed from the font file. */ public function get name():String { return _name; } /** The native size of the font. */ public function get size():Number { return _size; } /** The height of one line in points. */ public function get lineHeight():Number { return _lineHeight; } public function set lineHeight(value:Number):void { _lineHeight = value; } /** The smoothing filter that is used for the texture. */ public function get smoothing():String { return _helperImage.textureSmoothing; } public function set smoothing(value:String):void { _helperImage.textureSmoothing = value; } /** The baseline of the font. This property does not affect text rendering; * it's just an information that may be useful for exact text placement. */ public function get baseline():Number { return _baseline; } public function set baseline(value:Number):void { _baseline = value; } /** An offset that moves any generated text along the x-axis (in points). * Useful to make up for incorrect font data. @default 0. */ public function get offsetX():Number { return _offsetX; } public function set offsetX(value:Number):void { _offsetX = value; } /** An offset that moves any generated text along the y-axis (in points). * Useful to make up for incorrect font data. @default 0. */ public function get offsetY():Number { return _offsetY; } public function set offsetY(value:Number):void { _offsetY = value; } /** The underlying texture that contains all the chars. */ public function get texture():Texture { return _texture; } } } import starling.text.BitmapChar; class CharLocation { public var char:BitmapChar; public var scale:Number; public var x:Number; public var y:Number; public function CharLocation(char:BitmapChar) { reset(char); } private function reset(char:BitmapChar):CharLocation { this.char = char; return this; } // pooling private static var sInstancePool:Vector. = new []; private static var sVectorPool:Array = []; private static var sInstanceLoan:Vector. = new []; private static var sVectorLoan:Array = []; public static function instanceFromPool(char:BitmapChar):CharLocation { var instance:CharLocation = sInstancePool.length > 0 ? sInstancePool.pop() : new CharLocation(char); instance.reset(char); sInstanceLoan[sInstanceLoan.length] = instance; return instance; } public static function vectorFromPool():Vector. { var vector:Vector. = sVectorPool.length > 0 ? sVectorPool.pop() : new []; vector.length = 0; sVectorLoan[sVectorLoan.length] = vector; return vector; } public static function rechargePool():void { var instance:CharLocation; var vector:Vector.; while (sInstanceLoan.length > 0) { instance = sInstanceLoan.pop(); instance.char = null; sInstancePool[sInstancePool.length] = instance; } while (sVectorLoan.length > 0) { vector = sVectorLoan.pop(); vector.length = 0; sVectorPool[sVectorPool.length] = vector; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy