Last active
March 14, 2016 01:49
-
-
Save 7interactivestudio/7987260 to your computer and use it in GitHub Desktop.
Bitmap Chars for Genome2D
Font created with Littera ( http://kvazars.com/littera/ ) GBitmapFont Topic and Demo: http://forum.genome2d.com/viewtopic.php?f=6&t=111
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Created by rodrigo on 12/14/13. | |
*/ | |
package rodrigolopezpeker.genome2d.text { | |
import com.genome2d.textures.GTexture; | |
import flash.utils.Dictionary; | |
public class BitmapChar { | |
public var texture:GTexture; | |
private var _charId:int; | |
private var _xOffset:int; | |
private var _yOffset:int; | |
private var _xAdvance:int; | |
private var _kernings:Dictionary; | |
public function BitmapChar(pId:int, pTexture:GTexture, pxOffset:Number, pyOffset:Number, pxAdvance:Number) { | |
_charId = pId; | |
texture = pTexture ; | |
_xOffset = pxOffset; | |
_yOffset = pyOffset; | |
_xAdvance = pxAdvance; | |
} | |
public function addKerning(pCharId:int, pKerning:Number):void { | |
if (_kernings == null) _kernings = new Dictionary(true); | |
_kernings[pCharId] = pKerning; | |
} | |
public function getKerning(pCharId:int):Number { | |
if (!_kernings || !_kernings[pCharId]) return 0; | |
return _kernings[pCharId]; | |
} | |
public function get xOffset():int { | |
return _xOffset; | |
} | |
public function get yOffset():int { | |
return _yOffset; | |
} | |
public function get xAdvance():int { | |
return _xAdvance; | |
} | |
public function get charId():int { | |
return _charId; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Created by rodrigo on 12/14/13. | |
*/ | |
package rodrigolopezpeker.genome2d.text { | |
import com.genome2d.textures.GTexture; | |
import com.genome2d.textures.GTextureAtlas; | |
import com.genome2d.textures.GTextureSourceType; | |
import com.genome2d.textures.GTextureUtils; | |
import flash.display.BitmapData; | |
import flash.geom.Rectangle; | |
import flash.utils.Dictionary; | |
public class BitmapFont { | |
public static const NATIVE_SIZE:int = -1; | |
public static const CHAR_SPACE:int = 32; | |
public static const CHAR_TAB:int = 9; | |
public static const CHAR_NEWLINE:int = 10; | |
public static const CHAR_RETURN:int = 13; | |
public static const UKNOWN_NAME:String = 'uknown'; | |
private var _atlas:GTextureAtlas; | |
private var _bitmap:BitmapData; | |
private var _fontData:XML; | |
private var _chars:Dictionary; | |
private var _name:String; | |
private var _size:Number; | |
private var _lineHeight:Number; | |
/** | |
* Constructor. | |
* @param pAtlas | |
* @param pFontData | |
*/ | |
public function BitmapFont(pBitmap:BitmapData, pFontData:XML) { | |
_bitmap = pBitmap; | |
_fontData = pFontData; | |
_name = UKNOWN_NAME; | |
_lineHeight = _size = 14; | |
_chars = new Dictionary(true); | |
parseFontXML(pFontData); | |
} | |
private function parseFontXML(pFontData:XML):void { | |
_name = pFontData.info.@face; | |
_size = parseFloat(pFontData.info.@size); | |
_lineHeight = parseFloat(pFontData.info.@lineHeight); | |
if (isNaN(_lineHeight)) { | |
_lineHeight = parseFloat(pFontData.common.@lineHeight); | |
} | |
if (_size <= 0) { | |
trace('[Genome2D] Warning: invalid font size in "' + _name + '" font.'); | |
_size = _size == 0 ? 16 : _size *= -1; | |
} | |
var region:Rectangle; | |
var atlasId:String = _name.toLowerCase().split(' ').join('-') + '-' + size; | |
_atlas = new GTextureAtlas(atlasId, GTextureSourceType.BITMAPDATA, _bitmap.width, _bitmap.height, _bitmap, GTextureUtils.isBitmapDataTransparent(_bitmap), null); | |
for each(var node:XML in pFontData.chars.char) { | |
var id:int = node.@id; | |
var xOffset:Number = node.@xoffset; | |
var yOffset:Number = node.@yoffset; | |
var xAdvance:Number = node.@xadvance; | |
region = new Rectangle(int(node.@x), int(node.@y), int(node.@width), int(node.@height)); | |
var pivotX:Number = -region.width / 2; | |
var pivotY:Number = -region.height / 2; | |
var charTexture:GTexture = _atlas.addSubTexture(String(id), region, pivotX, pivotY); | |
addChar(id, new BitmapChar(id, charTexture, xOffset, yOffset, xAdvance)); | |
} | |
// add kernings. | |
for each(node in pFontData.kernings.kerning) { | |
var first:int = int(node.@first); | |
var second:int = int(node.@second); | |
var amount:int = int(node.@amount); | |
if (second in _chars) getChar(second).addKerning(first, amount); | |
} | |
_atlas.invalidate(); | |
} | |
public function getChar(pCharId:int):BitmapChar { | |
return _chars[pCharId]; | |
} | |
public function addChar(pId:int, pBitmapChar:BitmapChar):void { | |
_chars[pId] = pBitmapChar; | |
} | |
public function get atlas():GTextureAtlas { | |
return _atlas; | |
} | |
public function get fontData():XML { | |
return _fontData; | |
} | |
public function get name():String { | |
return _name; | |
} | |
public function get size():Number { | |
return _size; | |
} | |
public function get lineHeight():Number { | |
return _lineHeight; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Created by rodrigo on 12/14/13. | |
*/ | |
package rodrigolopezpeker.genome2d.text { | |
import com.genome2d.components.GComponent; | |
import com.genome2d.components.renderables.GSprite; | |
import com.genome2d.context.GBlendMode; | |
import com.genome2d.core.GNode; | |
import com.genome2d.core.GNodeFactory; | |
import com.genome2d.textures.GTexture; | |
import com.genome2d.textures.GTextureAlignType; | |
import com.genome2d.textures.factories.GTextureFactory; | |
import org.osflash.signals.Signal; | |
public class GBitmapText extends GComponent { | |
private var _font:BitmapFont; | |
private var _w:int; | |
private var _h:int; | |
private static var _boxBorderTexture:GTexture; | |
private var _borderContainer:GNode ; | |
private var _backgroundSprite:GSprite; | |
private var _borders:Vector.<GSprite>; | |
private var _background:Boolean = false ; | |
private var _border:Boolean = false ; | |
private var _borderThickness:int = 1 ; | |
private var _borderColor:uint = 0xFFFFFF ; | |
private var _backgroundColor: uint = 0x0 ; | |
private var _invalidateBorder:Boolean; | |
private var _invalidateBackground:Boolean; | |
private var _invalidateText:Boolean; | |
private var _textNode:GNode; | |
private var _text:String; | |
private var _fontSize:Number; | |
private var _fontColor:uint; | |
private var _hAlign:String = 'center'; | |
private var _vAlign:String = 'center'; | |
private var _autoScale:Boolean; | |
private var _kerning:Boolean; | |
private var _letterSpacing:Number = 0 ; | |
private var _leading:Number = 0; | |
private var _invalidateAlign:Boolean; | |
public var onTextDrawn:Signal; | |
public function GBitmapText(pNode:GNode) { | |
super(pNode); | |
onTextDrawn = new Signal(); | |
_textNode = GNodeFactory.createNode(); | |
node.addChild(_textNode); | |
} | |
public function setBitmapFont(pBitmapFont:BitmapFont):void { | |
_font = pBitmapFont; | |
// invalidate. | |
} | |
public function setup(pWidth:int, pHeight:int, pText:String, fontSize:int=-1, | |
color:uint=0xFFFFFF, hAlign:String='center', vAlign:String='center', | |
autoScale:Boolean=true, kerning:Boolean=true):void { | |
_w = pWidth ; | |
_h = pHeight; | |
_text = pText ; | |
_fontColor = color ; | |
_fontSize = fontSize ; | |
_hAlign = hAlign ; | |
_vAlign = vAlign ; | |
_autoScale = autoScale; | |
_kerning = kerning; | |
// redraw text. | |
if(_font){ | |
drawText() ; | |
} | |
if(_border)_invalidateBorder=true; | |
if(_background)_invalidateBackground=true; | |
} | |
private function drawText():void { | |
if( _fontSize == BitmapFont.NATIVE_SIZE ) _fontSize = _font.size ; | |
var finished:Boolean = false ; | |
var lineNode:GNode; | |
var lastCharNode:GNode; | |
var lineHeight:int = _leading + _font.lineHeight ; | |
_textNode.disposeChildren(); | |
if(_text=='') return ; | |
while(!finished){ | |
var scale:Number = _fontSize/_font.size; | |
var containerLineNode:GNode = GNodeFactory.createNode(); | |
if( lineHeight * scale <=_h){ | |
var containerWidth:Number = _w/scale; | |
var containerHeight:Number = _h/scale; | |
containerLineNode.transform.setScale(scale,scale); | |
var lastWhitespace:int = -1; | |
var lastCharId:int = -1; | |
var currentX:Number = 0 ; | |
var currentLineNode:GNode = GNodeFactory.createNode(); | |
var numChars:int = _text.length ; | |
for (var i:int = 0; i < numChars; i++) { | |
var lineFull:Boolean = false ; | |
var charId:int = _text.charCodeAt(i); | |
var charSprite:GSprite = GNodeFactory.createNodeWithComponent(GSprite) as GSprite ; | |
if(charId==10||charId==13){ | |
lineFull = true ; | |
} else { | |
var bitmapChar:BitmapChar = _font.getChar(charId); | |
if(!bitmapChar){ | |
trace('[Genome2D] Missing character:' + charId); | |
continue; | |
} | |
if(charId==BitmapFont.CHAR_SPACE || charId == BitmapFont.CHAR_TAB) lastWhitespace = i ; | |
charSprite.setTexture(bitmapChar.texture); | |
if(_kerning) currentX += bitmapChar.getKerning(lastCharId); | |
currentX += _letterSpacing ; | |
charSprite.node.transform.setPosition(currentX+bitmapChar.xOffset, bitmapChar.yOffset); | |
charSprite.node.transform.color = _fontColor ; | |
currentLineNode.addChild(charSprite.node); | |
currentX += bitmapChar.xAdvance; | |
lastCharId = charId; | |
if(currentX>containerWidth){ | |
// remove characters and add them to the next line. | |
var numCharsToRemove:int = lastWhitespace == -1 ? 1 : i-lastWhitespace; | |
for (var r:int=0; r<numCharsToRemove; ++r) | |
currentLineNode.removeChild(currentLineNode.lastChild); | |
if(currentLineNode.numChildren==0) break ; | |
lastCharNode = currentLineNode.lastChild; | |
currentX = lastCharNode.transform.x + (lastCharNode.getComponent(GSprite) as GSprite).getTexture().width; | |
i -= numCharsToRemove; | |
lineFull = true ; | |
} | |
} | |
if( i ==numChars-1){ | |
containerLineNode.addChild(currentLineNode); | |
finished = true ; | |
} else if( lineFull ){ | |
containerLineNode.addChild(currentLineNode); | |
var nextLineY:Number = currentLineNode.transform.y + lineHeight ; | |
if( nextLineY + lineHeight <= containerHeight ){ | |
currentLineNode = GNodeFactory.createNode(); | |
currentLineNode.transform.y = nextLineY; | |
currentX = 0 ; | |
lastWhitespace = -1; | |
lastCharId = -1 ; | |
} else { | |
break ; | |
} | |
} | |
} // for each char | |
} | |
if(_autoScale && !finished){ | |
_fontSize -= 1; | |
containerLineNode.disposeChildren(); | |
//dispose! | |
} else { | |
finished = true ; | |
} | |
_textNode.addChild(containerLineNode); | |
}// while finished | |
drawAlign() ; | |
onTextDrawn.dispatch(); | |
} | |
private function drawAlign():void { | |
var containerLineNode:GNode = _textNode.lastChild ; | |
var lineNode:GNode ; | |
var lineHeight: Number = _leading + _font.lineHeight ; | |
var scale:Number = _fontSize/_font.size; | |
// h align | |
var containerWidth:Number = _w / scale; | |
for (lineNode = containerLineNode.firstChild; lineNode != null; lineNode = lineNode.next) { | |
var lastCharNode:GNode = lineNode.lastChild; | |
var lineWidth:Number = lastCharNode.transform.x + (lastCharNode.getComponent(GSprite) as GSprite).getTexture().width; | |
var widthDiff:Number = containerWidth - lineWidth; | |
lineNode.transform.x = int(_hAlign == 'right' ? widthDiff : _hAlign == 'center' ? widthDiff / 2 : 0); | |
} | |
// v align | |
var contentHeight:Number = containerLineNode.numChildren * lineHeight * scale; | |
var heightDiff:Number = _h - contentHeight; | |
containerLineNode.transform.y = int(_vAlign == 'bottom' ? heightDiff : _vAlign == 'center' ? heightDiff / 2 : 0); | |
} | |
//// ---- STYLE THINGS ------ | |
private function drawBorder():void { | |
_borders[1].node.transform.scaleX = _borders[3].node.transform.scaleX = _borders[0].node.transform.scaleY = _borders[2].node.transform.scaleY = _borderThickness/2; | |
_borders[0].node.transform.scaleX = _borders[2].node.transform.scaleX = _w/2; | |
_borders[1].node.transform.scaleY = _borders[3].node.transform.scaleY = _h/2; | |
_borders[1].node.transform.x = _w - _borderThickness ; | |
_borders[2].node.transform.y = _h - _borderThickness ; | |
} | |
override public function update(p_deltaTime:Number):void { | |
super.update(p_deltaTime); | |
if( _invalidateBackground ) { | |
_invalidateBackground = false; | |
_backgroundSprite.node.transform.setScale(_w/2,_h/2); | |
} | |
if( _invalidateText && _font ) { | |
_invalidateText = false ; | |
drawText(); | |
} else if( _invalidateAlign ){ | |
_invalidateAlign = false ; | |
drawAlign(); | |
} | |
if( _invalidateBorder ){ | |
_invalidateBorder = false; | |
drawBorder(); | |
} | |
} | |
public function get borderThickness():int {return _borderThickness;} | |
public function set borderThickness(value:int):void { | |
if(_borderThickness== value) return ; | |
_borderThickness = value; | |
if(_borderContainer)_invalidateBorder = true ; | |
} | |
public function get borderColor():uint {return _borderColor;} | |
public function set borderColor(value:uint):void { | |
if(_borderColor == value) return ; | |
_borderColor = value; | |
if( _borderContainer ) _borderContainer.transform.color = value ; | |
} | |
public function get border():Boolean {return _border;} | |
public function set border(value:Boolean):void { | |
if( _border == value ) return ; | |
_border = value; | |
if(!_border && _borderContainer ){ | |
node.removeChild(_borderContainer); | |
_borderContainer.dispose(); | |
_borderContainer.disposeChildren(); | |
_borderContainer = null ; | |
} else { | |
initBorder() ; | |
if( _borderColor != 0xffffff ) _borderContainer.transform.color = _borderColor ; | |
_invalidateBorder = true ; | |
} | |
node.putChildToFront(_textNode); | |
} | |
private function initBorder():void { | |
if(!_boxBorderTexture){ | |
_boxBorderTexture = GTextureFactory.createFromColor('box_border_outline', 0xFFFFFF, 2, 2); | |
_boxBorderTexture.alignTexture(GTextureAlignType.TOP_LEFT); | |
} | |
_borderContainer = GNodeFactory.createNode(); | |
_borders = new Vector.<GSprite>() ; | |
for (var i:int = 0; i < 4; i++) { | |
var b:GSprite = GNodeFactory.createNodeWithComponent(GSprite) as GSprite ; | |
_borderContainer.addChild(b.node); | |
b.blendMode = GBlendMode.NONE ; | |
b.setTexture(_boxBorderTexture); | |
_borders[i] = b ; | |
} | |
node.addChild(_borderContainer); | |
} | |
public function get background():Boolean {return _background;} | |
public function set background(value:Boolean):void { | |
if( _background == value ) return ; | |
_background = value; | |
if(!_background && _backgroundSprite ){ | |
node.removeChild(_backgroundSprite.node); | |
_backgroundSprite = null ; | |
} else { | |
_backgroundSprite = GNodeFactory.createNodeWithComponent(GSprite) as GSprite ; | |
_backgroundSprite.setTexture(_boxBorderTexture); | |
_backgroundSprite.node.transform.color = _backgroundColor ; | |
_backgroundSprite.blendMode = GBlendMode.NONE ; | |
node.addChild(_backgroundSprite.node); | |
node.putChildToBack(_backgroundSprite.node); | |
_invalidateBackground = true ; | |
} | |
node.putChildToFront(_textNode); | |
} | |
public function get backgroundColor():uint {return _backgroundColor;} | |
public function set backgroundColor(value:uint):void { | |
if( _backgroundColor == value ) return ; | |
_backgroundColor = value; | |
if(_backgroundSprite) _backgroundSprite.node.transform.color = _backgroundColor ; | |
} | |
public function get fontSize():Number {return _fontSize;} | |
public function set fontSize(value:Number):void { | |
if( _fontSize == value ) return ; | |
_fontSize = value; | |
_invalidateText = true ; | |
} | |
public function get text():String {return _text;} | |
public function set text(value:String):void { | |
if( _text == value ) return ; | |
_text = value; | |
_invalidateText = true ; | |
} | |
public function get autoScale():Boolean {return _autoScale;} | |
public function set autoScale(value:Boolean):void { | |
if( _autoScale == value ) return ; | |
_autoScale = value; | |
_invalidateText = true ; | |
} | |
public function get kerning():Boolean {return _kerning;} | |
public function set kerning(value:Boolean):void { | |
if( _kerning == value ) return ; | |
_kerning = value; | |
_invalidateText = true ; | |
} | |
public function get letterSpacing():Number {return _letterSpacing;} | |
public function set letterSpacing(value:Number):void { | |
if( _letterSpacing == value ) return ; | |
_letterSpacing = value; | |
_invalidateText = true ; | |
} | |
public function get leading():Number {return _leading;} | |
public function set leading(value:Number):void { | |
if( _leading == value ) return ; | |
_leading = value; | |
_invalidateText = true ; | |
} | |
public function get hAlign():String {return _hAlign;} | |
public function set hAlign(value:String):void { | |
if( _hAlign == value ) return ; | |
_hAlign = value; | |
_invalidateAlign = true ; | |
} | |
public function get vAlign():String {return _vAlign;} | |
public function set vAlign(value:String):void { | |
if( _vAlign == value ) return ; | |
_vAlign = value; | |
_invalidateAlign = true ; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment