Fixed fontHeight detection for empty strings

Strict

Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_8_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_8_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_9_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_9_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_10_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_10_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_11_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_11_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_12_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_12_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_13_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_13_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_14_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_14_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_15_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_15_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_16_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_16_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_17_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_17_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_18_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_18_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_19_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_19_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_20_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_20_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_21_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_21_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_22_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_22_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_23_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_23_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_24_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_24_flx.fnt"

Import flxextern
Import flxsprite
Import flxcamera
Import flxg
Import system.flxcolor
Import system.flxassetsmanager

#If FLX_TEXT_DRIVER = "angelfont"
	Import vendor.angelfont
#End

Class FlxText Extends FlxSprite Implements FlxSpriteRenderer

	Global ClassObject:Object

	Const ALIGN_LEFT:Float = 0
	Const ALIGN_CENTER:Float = 0.5
	Const ALIGN_RIGHT:Float = 1

	Const SYSTEM_FONT:String = "system"

Private
	Global _FontLoader:FlxFontLoader = New FlxFontLoader()

	Global _FontsManager:FlxFontsManager = New FlxFontsManager()

	Field _shadow:FlxColor

	Field _value:String

	Field _lines:FlxTextLine[]

	Field _countLines:Int

	Field _alignment:Float

	Field _fontFamily:String

	Field _fontSize:Int

	Field _fontHeight:Int

#If FLX_TEXT_DRIVER = "angelfont"
	Field _fontObject:AngelFont
#End

Public
	Method New(x:Float, y:Float, width:Int = 0, text:String = "")
		Super.New(x, y)

		SetRenderer(Self)
		_shadow = New FlxColor(0)

		Self.width = width
		frameWidth = Self.width
		moves = False

		SetFormat(SYSTEM_FONT)
		Text = text
	End Method

	Method Destroy:Void()
		Local i:Int = 0, l:Int = _lines.Length()

		While (i < l)
			_lines[i] = Null
			i += 1
		Wend

		_fontObject = Null
		_shadow = Null

		Super.Destroy()
	End Method

	Method SetFormat:FlxText(font:String = "", size:Int = 0, color:Int = FlxG.WHITE, alignment:Float = ALIGN_LEFT, shadowColor:Int = 0)
		_alignment = alignment
		_fontFamily = font
		_fontSize = FlxAssetsManager.GetFont(font).GetValidSize(size)

		Self.Color = color
		Shadow = shadowColor

		_ResetFont()
		_ResetHelpers()

		Return Self
	End Method

	Method SetWidth:Void(width:Float)
		Self.width = width
		frameWidth = Self.width
		_ResetHelpers()
	End Method

	Method Text:String() Property
		Return _value
	End Method

	Method Text:Void(text:String) Property
		_value = text
		_ResetHelpers()
	End Method

	Method Size:Void(size:Int) Property
		_fontSize = FlxAssetsManager.GetFont(_fontFamily).GetValidSize(size)
		_ResetFont()
		_ResetHelpers()
	End Method

	Method Size:Int() Property
		Return _fontSize
	End Method

	Method Font:String() Property
		Return _fontFamily
	End Method

	Method Font:Void(font:String) Property
		_fontFamily = font
		_ResetFont()
		_ResetHelpers()
	End Method

	Method Alignment:Float() Property
		Return _alignment
	End Method

	Method Alignment:Void(alignment:Float) Property
		If (_alignment = alignment) Return
		_alignment = alignment
		_ResetAlignment()
	End Method

	Method Shadow:Int() Property
		Return _shadow.argb
	End Method

	Method Shadow:Void(color:Int) Property
		_shadow.SetARGB(color)
	End Method

	Method OnSpriteRender:Void(x:Float, y:Float)
		If (_shadow.argb <> 0) Then
			Local oldColor:Int = FlxG._LastDrawingColor
			Local oldAlpha:Int = FlxG._LastDrawingAlpha

			If (_camera.Color <> FlxG.WHITE) Then
				_mixedColor.MixRGB(_shadow, _camera._color)

				If (FlxG._LastDrawingColor <> _mixedColor.argb) Then
					SetColor(_mixedColor.r, _mixedColor.g, _mixedColor.b)
				End If
			Else
				If (FlxG._LastDrawingColor <> _shadow.argb) Then
					SetColor(_shadow.r, _shadow.g, _shadow.b)
				End If
			End If

			If (_camera.Alpha < 1) Then
				Local _mixedAlpha:Float = _camera.Alpha * _shadow.a

				If (FlxG._LastDrawingAlpha <> _mixedAlpha) Then
					SetAlpha(_mixedAlpha)
				End If
			Else
				If (FlxG._LastDrawingAlpha <> _shadow.a) Then
					SetAlpha(_shadow.a)
				End If
			End If

			_fontObject.DrawText(Self, x + 1, y + 1)

			_mixedColor.SetRGB(oldColor)
			SetColor(_mixedColor.r, _mixedColor.g, _mixedColor.b)
			SetAlpha(oldAlpha)
		End If

		_fontObject.DrawText(Self, x, y)
	End Method

Private
	Method _ResetHelpers:Void()
		If (_value.Length() > 0) Then
			If (width <> 0) Then
				_ParseText()
			Else
				_countLines = 0
				_AddLine(0, _value.Length(), _fontObject.GetTextWidth(Self, 0, _value.Length()))
				_ResetAlignment()
			End If

			Self.height = _GetHeight()
			frameHeight = Self.height
		Else
			Self.height = 0
			frameHeight = 0
		End If

		Super._ResetHelpers()
	End Method

	Method _ResetFont:Void()
		_FontLoader.fontFamily = _fontFamily
		_FontLoader.fontSize = _fontSize

		_fontObject = _FontsManager.GetResource(_fontFamily + _fontSize, _FontLoader)
		_fontHeight = _fontObject.GetTextHeight(Self)
	End Method

	Method _ResetAlignment:Void()
		If (_value.Length() = 0) Return

		For Local line:Int = 0 Until _countLines
			_lines[line].xOffset = (width - _lines[line].width) * _alignment
		Next
	End Method

	Method _GetHeight:Int()
		If (width = 0) Then
			Return _fontHeight
		Else
			Return _fontHeight + _fontObject.lineGap * (_countLines - 1)
		End If
	End Method

	Method _ParseText:Void()
		_countLines = 0

		Local prevOffset:Int = 0
		Local offsetN:Int = _value.Find("~n", 0)
		Local offsetR:Int = _value.Find("~r", 0)
		Local offset:Int = 0

		If (offsetN >= 0 And offsetR >= 0) Then
			offset = Min(offsetN, offsetR)
		Else
			offset = Max(offsetN, offsetR)
		End If

		If (offset >= 0) Then
			While (offset >= 0)
				_BuildLines(prevOffset, offset)

				prevOffset = offset + 1

				offsetN = _value.Find("~n", prevOffset)
				offsetR = _value.Find("~r", prevOffset)

				If (offsetN >= 0 And offsetR >= 0) Then
					offset = Min(offsetN, offsetR)
				Else
					offset = Max(offsetN, offsetR)
				End if
			Wend

			_BuildLines(prevOffset, _value.Length())
		Else
			_BuildLines(0, _value.Length())
		End If

		_ResetAlignment()
	End Method

	Method _BuildLines:Void(startPos:Int, endPos:Int)
		Local textWidth:Int = _fontObject.GetTextWidth(Self, startPos, endPos)

		If (width < textWidth) Then
			Local textLength:Int = endPos - startPos

			Local range:Int = Ceil(textLength / Float(Floor(textWidth / Float(width)) + 1))

			Repeat
				range += 1
				textWidth = _fontObject.GetTextWidth(Self, 0, range)
			Until (textWidth >= width)

			Local maxOffset:Int = range - 1
			Local minOffset:Int = 0
			Local offset:Int = maxOffset
			Local tmpOffset:Int = 0
			Local dirty:Bool = False
			Local finalTextWidth:Int = 0

			Repeat
				Repeat
					offset -= 1
					If (offset - minOffset <= 1) Then
						offset = minOffset + 1
						Exit
					End if

					tmpOffset = -1
					For Local i:Int = offset - 1 To minOffset Step - 1
						If (_value[i] = KEY_SPACE Or _value[i] = KEY_TAB) Then
							tmpOffset = i
							Exit
						End If
					Next

					If (tmpOffset < 0) Then
						tmpOffset = _GetMinOffset(minOffset, offset)
					Else
						If (offset - minOffset > 1 And (_value[minOffset] = KEY_SPACE Or _value[minOffset] = KEY_TAB)) Then
							minOffset += 1
							offset += Min(offset + 2, maxOffset)
							Continue
						EndIf
					End If

					offset = tmpOffset + minOffset
					textWidth = _fontObject.GetTextWidth(Self, minOffset, offset)
				Until (textWidth <= width)

				'Print _value[minOffset .. offset]
				'Print "..."

				dirty = False
				finalTextWidth = _fontObject.GetTextWidth(Self, minOffset)

				If (finalTextWidth > width And textLength - minOffset > 1) Then
					For Local i:Int = minOffset Until offset
						If (_value[i] = KEY_SPACE Or _value[i] = KEY_TAB) Then
							minOffset += 1
							dirty = True
						Else
							Exit
						End If
					Next

					For Local i:Int = offset - 1 To minOffset Step - 1
						If (_value[i] = KEY_SPACE Or _value[i] = KEY_TAB) Then
							offset -= 1
							dirty = True
						Else
							Exit
						End If
					Next

					If (offset - minOffset = 0) Continue

					If ( Not dirty) Then
						_AddLine(minOffset, offset, textWidth)
					Else
						_AddLine(minOffset, offset, _fontObject.GetTextWidth(Self, minOffset, offset))
					End If

					minOffset = offset
					maxOffset = minOffset + range
					offset = maxOffset
				Else
					Local l:Int = _value.Length()

					For Local i:Int = minOffset Until l
						If (_value[i] = KEY_SPACE Or _value[i] = KEY_TAB) Then
							minOffset += 1
							dirty = True
						Else
							Exit
						End If
					Next

					For Local i:Int = l - 1 To minOffset Step - 1
						If (_value[i] = KEY_SPACE Or _value[i] = KEY_TAB) Then
							l -= 1
							dirty = True
						Else
							Exit
						End If
					Next

					If (offset - l = 0) Continue

					If ( Not dirty) Then
						_AddLine(minOffset, l, finalTextWidth)
					Else
						_AddLine(minOffset, offset, _fontObject.GetTextWidth(Self, minOffset, l))
					End If

					Exit
				End If
			Forever
		Else
			_AddLine(startPos, endPos, textWidth)
		End If
	End Method

	Method _GetMinOffset:Int(startPos:Int, endPos:Int)
		Local offset:Int = endPos - startPos

		While (_fontObject.GetTextWidth(Self, 0, offset) > width)
			offset -= 1
			If (offset = 0) Return offset
		Wend

		Return offset
	End Method

	Method _AddLine:FlxTextLine(startPos:Int, endPos:Int, width:Int)
		Local line:FlxTextLine

		If (_countLines = _lines.Length()) Then
			_lines = _lines.Resize(_countLines * 2 + 10)
			line = New FlxTextLine(startPos, endPos, width)
			_lines[_countLines] = line
		Else
			line = _lines[_countLines]
			If (line = Null) Then
				line = New FlxTextLine(startPos, endPos, width)
				_lines[_countLines] = line
			Else
				line.Reset(startPos, endPos, width)
			End If
		End If

		_countLines += 1
		Return line
	End Method

End Class

Private
Class FlxTextLine

	Field xOffset:Float

	Field startPos:Int

	Field endPos:Int

	Field width:Int

	Method New(startPos:Int, endPos:Int, width:Int)
		Reset(startPos, endPos, width)
	End Method

	Method Reset:Void(startPos:Int, endPos:Int, width:Int)
		Self.startPos = startPos
		Self.endPos = endPos
		Self.width = width
	End Method

End Class

#If FLX_TEXT_DRIVER = "angelfont"
	Class FlxFontLoader Extends FlxResourceLoader<AngelFont>

		Field fontFamily:String = FlxText.SYSTEM_FONT
		Field fontSize:Int

		Method Load:AngelFont(name:String)
			Local font:AngelFont = New AngelFont()
			font.LoadFontXml(FlxAssetsManager.GetFont(fontFamily).GetPath(fontSize))

			Return font
		End Method

	End Class

	Class FlxFontsManager Extends FlxResourcesManager<AngelFont>
	End Class

	Class AngelFont
	Private
		Field image:Image[] = New Image[1]
		Field chars:Char[256]

		Field kernPairs:IntMap<IntMap<KernPair>> = New IntMap<IntMap<KernPair>>
		Global firstKp:IntMap<KernPair>
		Global secondKp:KernPair

		Field iniText:String

		Field xOffset:Int
		Field yOffset:Int

	Public
		Field useKerning:Bool = True

		Field height:Int = 0
		Field heightOffset:Int = 9999

		Field lineGap:Int = 5

		Method LoadFontXml:Void(url:String)
			iniText = LoadString(url+".fnt")
			Local lines:String[] = iniText.Split(String.FromChar(10))
			Local firstLine:String = lines[0]
			If firstLine.Contains("<?xml")
				Local lineList:List<String> = New List<String>(lines)
				lineList.RemoveFirst()
				lines = lineList.ToArray()
				iniText = "~n".Join(lines)
			End

			Local pageCount:Int = 0

			Local config:= LoadConfig(iniText)

			Local nodes:= config.FindNodesByPath("font/chars/char")

			For Local node:= EachIn nodes
				Local id:Int = Int(node.GetAttribute("id"))
				Local page:Int = Int(node.GetAttribute("page"))
				If pageCount < page pageCount = page
				chars[id] = New Char(Int(node.GetAttribute("x")), Int(node.GetAttribute("y")), Int(node.GetAttribute("width")), Int(node.GetAttribute("height")),  Int(node.GetAttribute("xoffset")),  Int(node.GetAttribute("yoffset")),  Int(node.GetAttribute("xadvance")), page)
				Local ch := chars[id]
				If ch.height > Self.height Self.height = ch.height
				If ch.yOffset < Self.heightOffset Self.heightOffset = ch.yOffset
			Next

			nodes = config.FindNodesByPath("font/kernings/kerning")

			If (nodes <> Null) Then
				For Local node:= EachIn nodes
					Local first:Int = Int(node.GetAttribute("first"))
					firstKp = kernPairs.Get(first)
					If firstKp = Null
						kernPairs.Add(first, New IntMap<KernPair>)
						firstKp = kernPairs.Get(first)
					End

					Local second:Int = Int(node.GetAttribute("second"))
					firstKp.Add(second, New KernPair(first, second, Int(node.GetAttribute("amount"))))
				End
			Else
				useKerning = False
			End If

			If pageCount = 0
				image[0] = LoadImage(url+".png")
				If image[0] = Null image[0] = LoadImage(url+"_0.png")
			Else
				For Local page:= 0 To pageCount
					If image.Length < page+1 image = image.Resize(page+1)
					image[page] = LoadImage(url+"_"+page+".png")
				End
			End
		End

		Method GetTextWidth:Int(txt:FlxText, startPos:Int = 0, endPos:Int = -1)
			Local prevChar:Int = 0
			Local width:Int = 0

			If (endPos < 0) endPos = txt._value.Length()
			Local asc:Int, ac:Char

			For Local i:= startPos Until endPos
				asc = txt._value[i]
				ac = chars[asc]

				If ac <> Null
					If useKerning
						Local firstKp:= kernPairs.Get(prevChar)
						If firstKp <> Null
							Local secondKp:= firstKp.Get(asc)
							If secondKp <> Null
								xOffset += secondKp.amount
							End
						Endif
					EndIf

					width += ac.xAdvance
					prevChar = asc
				EndIf
			Next

			Return width
		End Method

		Method GetTextHeight:Int(txt:FlxText, startPos:Int = 0, endPos:Int = -1)
			Local h:Int = 0

			If (endPos < 0) endPos = txt._value.Length()

			If (endPos <> 0) Then
				For Local i:= startPos Until endPos
					Local asc:Int = txt._value[i]
					Local ac:Char = chars[asc]
					If ac.height+ac.yOffset > h h = ac.height+ac.yOffset
				Next
			Else
				h = chars[KEY_SPACE].height + chars[KEY_SPACE].yOffset
			End If

			Return h
		End

		Method DrawText:Void(txt:FlxText, x:Int, y:Int)
			Local lineIndex:Int = 0, countLines:Int = txt._countLines, line:FlxTextLine

			Local prevChar:Int = 0, xOffset:Int = 0, yOffset:Int = 0
			Local i:Int = 0, l:Int
			Local asc:Int, ac:Char
			Local lineHeight:Int = txt._fontHeight + lineGap

			While (lineIndex < countLines)
				line = txt._lines[lineIndex]
				i = line.startPos
				l = line.endPos
				xOffset = 0

				While (i < l)
					asc = txt._value[i]
					ac = chars[asc]

					If ac <> Null
						If useKerning
							firstKp = kernPairs.Get(prevChar)
							If firstKp <> Null
								secondKp = firstKp.Get(asc)
								If secondKp <> Null
									xOffset += secondKp.amount
								End
							Endif
						Endif

						ac.Draw(image[ac.page], x + xOffset + line.xOffset, y + yOffset)
						xOffset += ac.xAdvance
						prevChar = asc
					Endif

					i += 1
				Wend

				lineIndex += 1
				yOffset += lineHeight
			Wend
		End Method

	End Class
#End

Strict

Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_8_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_8_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_9_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_9_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_10_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_10_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_11_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_11_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_12_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_12_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_13_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_13_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_14_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_14_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_15_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_15_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_16_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_16_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_17_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_17_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_18_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_18_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_19_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_19_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_20_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_20_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_21_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_21_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_22_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_22_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_23_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_23_flx.fnt"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_24_flx_0.png"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_24_flx.fnt"

Import flxextern
Import flxsprite
Import flxcamera
Import flxg
Import system.flxcolor
Import system.flxassetsmanager

#If FLX_TEXT_DRIVER = "angelfont"
	Import vendor.angelfont
#End

Class FlxText Extends FlxSprite Implements FlxSpriteRenderer

	Global ClassObject:Object

	Const ALIGN_LEFT:Float = 0
	Const ALIGN_CENTER:Float = 0.5
	Const ALIGN_RIGHT:Float = 1

	Const SYSTEM_FONT:String = "system"

Private
	Global _FontLoader:FlxFontLoader = New FlxFontLoader()

	Global _FontsManager:FlxFontsManager = New FlxFontsManager()

	Field _shadow:FlxColor

	Field _value:String

	Field _lines:FlxTextLine[]

	Field _countLines:Int

	Field _alignment:Float

	Field _fontFamily:String

	Field _fontSize:Int

	Field _fontHeight:Int

#If FLX_TEXT_DRIVER = "angelfont"
	Field _fontObject:AngelFont
#End

Public
	Method New(x:Float, y:Float, width:Int = 0, text:String = "")
		Super.New(x, y)

		SetRenderer(Self)
		_shadow = New FlxColor(0)

		Self.width = width
		frameWidth = Self.width
		moves = False

		SetFormat(SYSTEM_FONT)
		Text = text
	End Method

	Method Destroy:Void()
		Local i:Int = 0, l:Int = _lines.Length()

		While (i < l)
			_lines[i] = Null
			i += 1
		Wend

		_fontObject = Null
		_shadow = Null

		Super.Destroy()
	End Method

	Method SetFormat:FlxText(font:String = "", size:Int = 0, color:Int = FlxG.WHITE, alignment:Float = ALIGN_LEFT, shadowColor:Int = 0)
		_alignment = alignment
		_fontFamily = font
		_fontSize = FlxAssetsManager.GetFont(font).GetValidSize(size)

		Self.Color = color
		Shadow = shadowColor

		_ResetFont()
		_ResetHelpers()

		Return Self
	End Method

	Method SetWidth:Void(width:Float)
		Self.width = width
		frameWidth = Self.width
		_ResetHelpers()
	End Method

	Method Text:String() Property
		Return _value
	End Method

	Method Text:Void(text:String) Property
		_value = text
		_ResetHelpers()
	End Method

	Method Size:Void(size:Int) Property
		_fontSize = FlxAssetsManager.GetFont(_fontFamily).GetValidSize(size)
		_ResetFont()
		_ResetHelpers()
	End Method

	Method Size:Int() Property
		Return _fontSize
	End Method

	Method Font:String() Property
		Return _fontFamily
	End Method

	Method Font:Void(font:String) Property
		_fontFamily = font
		_ResetFont()
		_ResetHelpers()
	End Method

	Method Alignment:Float() Property
		Return _alignment
	End Method

	Method Alignment:Void(alignment:Float) Property
		If (_alignment = alignment) Return
		_alignment = alignment
		_ResetAlignment()
	End Method

	Method Shadow:Int() Property
		Return _shadow.argb
	End Method

	Method Shadow:Void(color:Int) Property
		_shadow.SetARGB(color)
	End Method

	Method OnSpriteRender:Void(x:Float, y:Float)
		If (_shadow.argb <> 0) Then
			Local oldColor:Int = FlxG._LastDrawingColor
			Local oldAlpha:Int = FlxG._LastDrawingAlpha

			If (_camera.Color <> FlxG.WHITE) Then
				_mixedColor.MixRGB(_shadow, _camera._color)

				If (FlxG._LastDrawingColor <> _mixedColor.argb) Then
					SetColor(_mixedColor.r, _mixedColor.g, _mixedColor.b)
				End If
			Else
				If (FlxG._LastDrawingColor <> _shadow.argb) Then
					SetColor(_shadow.r, _shadow.g, _shadow.b)
				End If
			End If

			If (_camera.Alpha < 1) Then
				Local _mixedAlpha:Float = _camera.Alpha * _shadow.a

				If (FlxG._LastDrawingAlpha <> _mixedAlpha) Then
					SetAlpha(_mixedAlpha)
				End If
			Else
				If (FlxG._LastDrawingAlpha <> _shadow.a) Then
					SetAlpha(_shadow.a)
				End If
			End If

			_fontObject.DrawText(Self, x + 1, y + 1)

			_mixedColor.SetRGB(oldColor)
			SetColor(_mixedColor.r, _mixedColor.g, _mixedColor.b)
			SetAlpha(oldAlpha)
		End If

		_fontObject.DrawText(Self, x, y)
	End Method

Private
	Method _ResetHelpers:Void()
		If (_value.Length() > 0) Then
			If (width <> 0) Then
				_ParseText()
			Else
				_countLines = 0
				_AddLine(0, _value.Length(), _fontObject.GetTextWidth(Self, 0, _value.Length()))
				_ResetAlignment()
			End If

			Self.height = _GetHeight()
			frameHeight = Self.height
		Else
			Self.height = 0
			frameHeight = 0
		End If

		Super._ResetHelpers()
	End Method

	Method _ResetFont:Void()
		_FontLoader.fontFamily = _fontFamily
		_FontLoader.fontSize = _fontSize

		_fontObject = _FontsManager.GetResource(_fontFamily + _fontSize, _FontLoader)
		_fontHeight = _fontObject.GetTextHeight(Self)
	End Method

	Method _ResetAlignment:Void()
		If (_value.Length() = 0) Return

		For Local line:Int = 0 Until _countLines
			_lines[line].xOffset = (width - _lines[line].width) * _alignment
		Next
	End Method

	Method _GetHeight:Int()
		If (width = 0) Then
			Return _fontHeight
		Else
			Return _fontHeight + _fontObject.lineGap * (_countLines - 1)
		End If
	End Method

	Method _ParseText:Void()
		_countLines = 0

		Local prevOffset:Int = 0
		Local offsetN:Int = _value.Find("~n", 0)
		Local offsetR:Int = _value.Find("~r", 0)
		Local offset:Int = 0

		If (offsetN >= 0 And offsetR >= 0) Then
			offset = Min(offsetN, offsetR)
		Else
			offset = Max(offsetN, offsetR)
		End If

		If (offset >= 0) Then
			While (offset >= 0)
				_BuildLines(prevOffset, offset)

				prevOffset = offset + 1

				offsetN = _value.Find("~n", prevOffset)
				offsetR = _value.Find("~r", prevOffset)

				If (offsetN >= 0 And offsetR >= 0) Then
					offset = Min(offsetN, offsetR)
				Else
					offset = Max(offsetN, offsetR)
				End if
			Wend

			_BuildLines(prevOffset, _value.Length())
		Else
			_BuildLines(0, _value.Length())
		End If

		_ResetAlignment()
	End Method

	Method _BuildLines:Void(startPos:Int, endPos:Int)
		Local textWidth:Int = _fontObject.GetTextWidth(Self, startPos, endPos)

		If (width < textWidth) Then
			Local textLength:Int = endPos - startPos

			Local range:Int = Ceil(textLength / Float(Floor(textWidth / Float(width)) + 1))

			Repeat
				range += 1
				textWidth = _fontObject.GetTextWidth(Self, 0, range)
			Until (textWidth >= width)

			Local maxOffset:Int = range - 1
			Local minOffset:Int = 0
			Local offset:Int = maxOffset
			Local tmpOffset:Int = 0
			Local dirty:Bool = False
			Local finalTextWidth:Int = 0

			Repeat
				Repeat
					offset -= 1
					If (offset - minOffset <= 1) Then
						offset = minOffset + 1
						Exit
					End if

					tmpOffset = -1
					For Local i:Int = offset - 1 To minOffset Step - 1
						If (_value[i] = KEY_SPACE Or _value[i] = KEY_TAB) Then
							tmpOffset = i
							Exit
						End If
					Next

					If (tmpOffset < 0) Then
						tmpOffset = _GetMinOffset(minOffset, offset)
					Else
						If (offset - minOffset > 1 And (_value[minOffset] = KEY_SPACE Or _value[minOffset] = KEY_TAB)) Then
							minOffset += 1
							offset += Min(offset + 2, maxOffset)
							Continue
						EndIf
					End If

					offset = tmpOffset + minOffset
					textWidth = _fontObject.GetTextWidth(Self, minOffset, offset)
				Until (textWidth <= width)

				dirty = False
				finalTextWidth = _fontObject.GetTextWidth(Self, minOffset)

				If (finalTextWidth > width And textLength - minOffset > 1) Then
					For Local i:Int = minOffset Until offset
						If (_value[i] = KEY_SPACE Or _value[i] = KEY_TAB) Then
							minOffset += 1
							dirty = True
						Else
							Exit
						End If
					Next

					For Local i:Int = offset - 1 To minOffset Step - 1
						If (_value[i] = KEY_SPACE Or _value[i] = KEY_TAB) Then
							offset -= 1
							dirty = True
						Else
							Exit
						End If
					Next

					If (offset - minOffset = 0) Continue

					If ( Not dirty) Then
						_AddLine(minOffset, offset, textWidth)
					Else
						_AddLine(minOffset, offset, _fontObject.GetTextWidth(Self, minOffset, offset))
					End If

					minOffset = offset
					maxOffset = minOffset + range
					offset = maxOffset
				Else
					Local l:Int = _value.Length()

					For Local i:Int = minOffset Until l
						If (_value[i] = KEY_SPACE Or _value[i] = KEY_TAB) Then
							minOffset += 1
							dirty = True
						Else
							Exit
						End If
					Next

					For Local i:Int = l - 1 To minOffset Step - 1
						If (_value[i] = KEY_SPACE Or _value[i] = KEY_TAB) Then
							l -= 1
							dirty = True
						Else
							Exit
						End If
					Next

					If (offset - l = 0) Continue

					If ( Not dirty) Then
						_AddLine(minOffset, l, finalTextWidth)
					Else
						_AddLine(minOffset, offset, _fontObject.GetTextWidth(Self, minOffset, l))
					End If

					Exit
				End If
			Forever
		Else
			_AddLine(startPos, endPos, textWidth)
		End If
	End Method

	Method _GetMinOffset:Int(startPos:Int, endPos:Int)
		Local offset:Int = endPos - startPos

		While (_fontObject.GetTextWidth(Self, 0, offset) > width)
			offset -= 1
			If (offset = 0) Return offset
		Wend

		Return offset
	End Method

	Method _AddLine:FlxTextLine(startPos:Int, endPos:Int, width:Int)
		Local line:FlxTextLine

		If (_countLines = _lines.Length()) Then
			_lines = _lines.Resize(_countLines * 2 + 10)
			line = New FlxTextLine(startPos, endPos, width)
			_lines[_countLines] = line
		Else
			line = _lines[_countLines]
			If (line = Null) Then
				line = New FlxTextLine(startPos, endPos, width)
				_lines[_countLines] = line
			Else
				line.Reset(startPos, endPos, width)
			End If
		End If

		_countLines += 1
		Return line
	End Method

End Class

Private
Class FlxTextLine

	Field xOffset:Float

	Field startPos:Int

	Field endPos:Int

	Field width:Int

	Method New(startPos:Int, endPos:Int, width:Int)
		Reset(startPos, endPos, width)
	End Method

	Method Reset:Void(startPos:Int, endPos:Int, width:Int)
		Self.startPos = startPos
		Self.endPos = endPos
		Self.width = width
	End Method

End Class

#If FLX_TEXT_DRIVER = "angelfont"
	Class FlxFontLoader Extends FlxResourceLoader<AngelFont>

		Field fontFamily:String = FlxText.SYSTEM_FONT
		Field fontSize:Int

		Method Load:AngelFont(name:String)
			Local font:AngelFont = New AngelFont()
			font.LoadFontXml(FlxAssetsManager.GetFont(fontFamily).GetPath(fontSize))

			Return font
		End Method

	End Class

	Class FlxFontsManager Extends FlxResourcesManager<AngelFont>
	End Class

	Class AngelFont
	Private
		Field image:Image[] = New Image[1]
		Field chars:Char[256]

		Field kernPairs:IntMap<IntMap<KernPair>> = New IntMap<IntMap<KernPair>>
		Global firstKp:IntMap<KernPair>
		Global secondKp:KernPair

		Field iniText:String

		Field xOffset:Int
		Field yOffset:Int

	Public
		Field useKerning:Bool = True

		Field height:Int = 0
		Field heightOffset:Int = 9999

		Field lineGap:Int = 5

		Method LoadFontXml:Void(url:String)
			iniText = LoadString(url+".fnt")
			Local lines:String[] = iniText.Split(String.FromChar(10))
			Local firstLine:String = lines[0]
			If firstLine.Contains("<?xml")
				Local lineList:List<String> = New List<String>(lines)
				lineList.RemoveFirst()
				lines = lineList.ToArray()
				iniText = "~n".Join(lines)
			End

			Local pageCount:Int = 0

			Local config:= LoadConfig(iniText)

			Local nodes:= config.FindNodesByPath("font/chars/char")

			For Local node:= EachIn nodes
				Local id:Int = Int(node.GetAttribute("id"))
				Local page:Int = Int(node.GetAttribute("page"))
				If pageCount < page pageCount = page
				chars[id] = New Char(Int(node.GetAttribute("x")), Int(node.GetAttribute("y")), Int(node.GetAttribute("width")), Int(node.GetAttribute("height")),  Int(node.GetAttribute("xoffset")),  Int(node.GetAttribute("yoffset")),  Int(node.GetAttribute("xadvance")), page)
				Local ch := chars[id]
				If ch.height > Self.height Self.height = ch.height
				If ch.yOffset < Self.heightOffset Self.heightOffset = ch.yOffset
			Next

			nodes = config.FindNodesByPath("font/kernings/kerning")

			If (nodes <> Null) Then
				For Local node:= EachIn nodes
					Local first:Int = Int(node.GetAttribute("first"))
					firstKp = kernPairs.Get(first)
					If firstKp = Null
						kernPairs.Add(first, New IntMap<KernPair>)
						firstKp = kernPairs.Get(first)
					End

					Local second:Int = Int(node.GetAttribute("second"))
					firstKp.Add(second, New KernPair(first, second, Int(node.GetAttribute("amount"))))
				End
			Else
				useKerning = False
			End If

			If pageCount = 0
				image[0] = LoadImage(url+".png")
				If image[0] = Null image[0] = LoadImage(url+"_0.png")
			Else
				For Local page:= 0 To pageCount
					If image.Length < page+1 image = image.Resize(page+1)
					image[page] = LoadImage(url+"_"+page+".png")
				End
			End
		End

		Method GetTextWidth:Int(txt:FlxText, startPos:Int = 0, endPos:Int = -1)
			Local prevChar:Int = 0
			Local width:Int = 0

			If (endPos < 0) endPos = txt._value.Length()
			Local asc:Int, ac:Char

			For Local i:= startPos Until endPos
				asc = txt._value[i]
				ac = chars[asc]

				If ac <> Null
					If useKerning
						Local firstKp:= kernPairs.Get(prevChar)
						If firstKp <> Null
							Local secondKp:= firstKp.Get(asc)
							If secondKp <> Null
								xOffset += secondKp.amount
							End
						Endif
					EndIf

					width += ac.xAdvance
					prevChar = asc
				EndIf
			Next

			Return width
		End Method

		Method GetTextHeight:Int(txt:FlxText, startPos:Int = 0, endPos:Int = -1)
			Local h:Int = 0

			If (endPos < 0) endPos = txt._value.Length()

			For Local i:= startPos Until endPos
				Local asc:Int = txt._value[i]
				Local ac:Char = chars[asc]
				If ac.height+ac.yOffset > h h = ac.height+ac.yOffset
			Next
			Return h
		End

		Method DrawText:Void(txt:FlxText, x:Int, y:Int)
			Local lineIndex:Int = 0, countLines:Int = txt._countLines, line:FlxTextLine

			Local prevChar:Int = 0, xOffset:Int = 0, yOffset:Int = 0
			Local i:Int = 0, l:Int
			Local asc:Int, ac:Char
			Local lineHeight:Int = txt._fontHeight + lineGap

			While (lineIndex < countLines)
				line = txt._lines[lineIndex]
				i = line.startPos
				l = line.endPos
				xOffset = 0

				While (i < l)
					asc = txt._value[i]
					ac = chars[asc]

					If ac <> Null
						If useKerning
							firstKp = kernPairs.Get(prevChar)
							If firstKp <> Null
								secondKp = firstKp.Get(asc)
								If secondKp <> Null
									xOffset += secondKp.amount
								End
							Endif
						Endif

						ac.Draw(image[ac.page], x + xOffset + line.xOffset, y + yOffset)
						xOffset += ac.xAdvance
						prevChar = asc
					Endif

					i += 1
				Wend

				lineIndex += 1
				yOffset += lineHeight
			Wend
		End Method

	End Class
#End


FlxReplay elapsed time override fixed

FlxReplay elapsed time override fixed

Strict

Import mojo

Import flixel.flxg
Import replay.keyrecord
Import replay.xyrecord
Import replay.xyzrecord
Import replay.framerecord

Class FlxReplay

	Field seed:Float

	Field frame:Int

	Field frameCount:Int

	Field elapsed:Float

	Field lastElapsed:Float

	Field finished:Bool

Private
	Field _frames:FrameRecord[]

	Field _capacity:Int

	Field _marker:Int

Public
	Method New()
		seed = 0
		frame = 0
		frameCount = 0
		elapsed = 0
		lastElapsed = 0
		finished = False
		_frames = []
		_capacity = 0
		_marker = 0
	End Method

	Method Destroy:Void()
		If (_frames.Length() = 0) Return

		Local i:Int = frameCount - 1

		While (i >= 0)
			_frames[i].Destroy()
			i -= 1
		Wend

		_frames = []
	End Method

	Method Create:Void(seed:Int)
		Destroy()
		_Init()
		Self.seed = seed
		Rewind()
	End Method

	Method Load:Void(fileContents:String)
		_Init()

		Local lines:String[] = fileContents.Split("~n")

		seed = Int(lines[0])

		Local line:String
		Local i:Int = 1
		Local l:Int = lines.Length()

		While (i < l)
			line = lines[i]

			If (line.Length() > 3) Then
				_frames[frameCount] = (New FrameRecord()).Load(line)
				frameCount += 1

				If (frameCount >= _capacity) Then
					_capacity *= 2
					_frames = _frames.Resize(_capacity)
				End If
			End If

			i += 1
		Wend

		Rewind()
	End Method

	Method Save:String()
		If (frameCount <= 0) Return ""

		Local output:StringStack = New StringStack()
		output.Push(FlxG.GlobalSeed + "~n")

		Local i:Int = 0
		While (i < frameCount)
			_frames[i].Save(output)
			output.Push("~n")
			i += 1
		Wend

		Return output.Join("")
	End Method

	Method RecordFrame:Void()
		Local accelRecord:XYZRecord
		Local joystickRecord:Stack<XYZRecord[]>
		Local touchRecord:Stack<XYRecord>
		Local keysRecord:Stack<KeyRecord>
		Local mouseRecord:XYRecord

		#If TARGET = "html5" Or TARGET = "ios" Or TARGET = "android"
			accelRecord = FlxG.Accel.RecordXYZ()
		#End

		#If TARGET = "xna" Or TARGET = "glfw"
			If (Not FlxG.Mobile) Then
				Local joyCount:Int = FlxG.JoystickCount()
				Local joyXYZRecord:XYZRecord[]

				For Local i:Int = 0 Until joyCount
					joyXYZRecord = FlxG.Joystick(i).RecordXYZ()

					If (joyXYZRecord.Length() > 0) Then
						If (joystickRecord = Null) joystickRecord = New Stack<XYZRecord[]>()
						joystickRecord.Insert(i, joyXYZRecord)
					End If

					keysRecord = FlxG.Joystick(i).RecordKeys(keysRecord)
				Next
			End If
		#End

		#If TARGET = "ios" Or TARGET = "android"
			Local touchCount:Int = FlxG.TouchCount()
			Local touchXYRecord:XYRecord

			For Local i:Int = 0 Until touchCount
				If (i > 0 And Not FlxG.Touch(i).Used) Exit

				touchXYRecord = FlxG.Touch(i).RecordXY()

				If (touchXYRecord <> Null) Then
					If (touchRecord = Null) touchRecord = New Stack<XYRecord>()
					touchRecord.Insert(i, touchXYRecord)
				End If

				keysRecord = FlxG.Touch(i).RecordKeys(keysRecord)
			Next

		#ElseIf TARGET = "html5" Or TARGET = "flash"
			If (Not FlxG.Mobile) Then
				keysRecord = FlxG.Keys.RecordKeys(keysRecord)
			End If

		#ElseIf TARGET = "xna"
			If (Not FlxG.Mobile) Then
				Local touchXYRecord:XYRecord = FlxG.Touch(0).RecordXY()

				If (touchXYRecord <> Null) Then
					If (touchRecord = Null) touchRecord = New Stack<XYRecord>()
					touchRecord.Insert(0, touchXYRecord)
				End If

				keysRecord = FlxG.Touch(0).RecordKeys(keysRecord)
				keysRecord = FlxG.Keys.RecordKeys(keysRecord)
			Else
				Local touchCount:Int = FlxG.TouchCount()
				Local touchXYRecord:XYRecord

				For Local i:Int = 0 Until touchCount
					If (i > 0 And Not FlxG.Touch(i).Used) Exit

					touchXYRecord = FlxG.Touch(i).RecordXY()

					If (touchXYRecord <> Null) Then
						If (touchRecord = Null) touchRecord = New Stack<XYRecord>()
						touchRecord.Insert(i, touchXYRecord)
					End If

					keysRecord = FlxG.Touch(i).RecordKeys(keysRecord)
				Next
			End If

		#Else
			keysRecord = FlxG.Keys.RecordKeys(keysRecord)
		#End

		#If TARGET = "android"
			keysRecord = FlxG.Keys.RecordKeys(keysRecord)
		#End

		#If TARGET = "html5" Or TARGET = "glfw"
			Local touchXYRecord:XYRecord = FlxG.Touch(0).RecordXY()

			If (touchXYRecord <> Null) Then
				If (touchRecord = Null) touchRecord = New Stack<XYRecord>()
				touchRecord.Insert(0, touchXYRecord)
			End If

			keysRecord = FlxG.Touch(0).RecordKeys(keysRecord)
		#End

		mouseRecord = FlxG.Mouse.RecordXY()
		keysRecord = FlxG.Mouse.RecordKeys(keysRecord)

		elapsed = FlxG.Elapsed

		If (keysRecord = Null And mouseRecord = Null And joystickRecord = Null And touchRecord = Null And accelRecord = Null And lastElapsed = elapsed) Then
			frame += 1
			Return
		End If

		_frames[frameCount] = (New FrameRecord()).Create(frame, elapsed, keysRecord, mouseRecord, joystickRecord, touchRecord, accelRecord)
		frame += 1
		frameCount += 1
		lastElapsed = elapsed

		If (frameCount >= _capacity) Then
			_capacity *= 2
			_frames = _frames.Resize(_capacity)
		End If
	End Method

	Method PlayNextFrame:Void()
		FlxG.ResetInput()

		If (_marker >= frameCount) Then
			finished = True
			Return
		End If

		FlxG.Elapsed = _frames[_marker].elapsed

		If (_frames[_marker].frame <> frame) Then
			frame += 1
			Return
		End If

		frame += 1

		Local fr:FrameRecord = _frames[_marker]
		_marker += 1

		If (fr.keys <> Null) FlxG.Keys.PlaybackKeys(fr.keys)
		If (fr.mouse <> Null) FlxG.Mouse.PlaybackXY(fr.mouse)

		If (fr.joystick <> Null) Then
			Local i:Int = 0
			Local l:Int = fr.joystick.Length()

			While (i < l)
				FlxG.Joystick(i).PlaybackXYZ(fr.joystick.Get(i))
				i += 1
			Wend
		End If

		If (fr.touch <> Null) Then
			Local i:Int = 0
			Local l:Int = FlxG.TouchCount()
			Local tr:XYRecord

			While (i < l)
				tr = fr.touch.Get(i)
				If (tr = Null) Exit

				FlxG.Touch(i).PlaybackXY(tr)

				i += 1
			Wend
		End If

		If (fr.accel <> Null) FlxG.Accel.PlaybackXYZ(fr.accel)
	End Method

	Method Rewind:Void()
		_marker = 0
		frame = 0
		finished = False
	End Method

Private
	Method _Init:Void()
		_capacity = 100
		_frames = _frames.Resize(_capacity)
		frameCount = 0
	End Method

End Class

Interface FlxReplayListener

	Method OnReplayComplete:Void()

End Interface

Strict

Import mojo

Import flixel.flxg
Import replay.keyrecord
Import replay.xyrecord
Import replay.xyzrecord
Import replay.framerecord

Class FlxReplay

	Field seed:Float

	Field frame:Int

	Field frameCount:Int

	Field elapsed:Float

	Field lastElapsed:Float

	Field finished:Bool

Private
	Field _frames:FrameRecord[]

	Field _capacity:Int

	Field _marker:Int

Public
	Method New()
		seed = 0
		frame = 0
		frameCount = 0
		elapsed = 0
		lastElapsed = 0
		finished = False
		_frames = []
		_capacity = 0
		_marker = 0
	End Method

	Method Destroy:Void()
		If (_frames.Length() = 0) Return

		Local i:Int = frameCount - 1

		While (i >= 0)
			_frames[i].Destroy()
			i -= 1
		Wend

		_frames = []
	End Method

	Method Create:Void(seed:Int)
		Destroy()
		_Init()
		Self.seed = seed
		Rewind()
	End Method

	Method Load:Void(fileContents:String)
		_Init()

		Local lines:String[] = fileContents.Split("~n")

		seed = Int(lines[0])

		Local line:String
		Local i:Int = 1
		Local l:Int = lines.Length()

		While (i < l)
			line = lines[i]

			If (line.Length() > 3) Then
				_frames[frameCount] = (New FrameRecord()).Load(line)
				frameCount += 1

				If (frameCount >= _capacity) Then
					_capacity *= 2
					_frames = _frames.Resize(_capacity)
				End If
			End If

			i += 1
		Wend

		Rewind()
	End Method

	Method Save:String()
		If (frameCount <= 0) Return ""

		Local output:StringStack = New StringStack()
		output.Push(FlxG.GlobalSeed + "~n")

		Local i:Int = 0
		While (i < frameCount)
			_frames[i].Save(output)
			output.Push("~n")
			i += 1
		Wend

		Return output.Join("")
	End Method

	Method RecordFrame:Void()
		Local accelRecord:XYZRecord
		Local joystickRecord:Stack<XYZRecord[]>
		Local touchRecord:Stack<XYRecord>
		Local keysRecord:Stack<KeyRecord>
		Local mouseRecord:XYRecord

		#If TARGET = "html5" Or TARGET = "ios" Or TARGET = "android"
			accelRecord = FlxG.Accel.RecordXYZ()
		#End

		#If TARGET = "xna" Or TARGET = "glfw"
			If (Not FlxG.Mobile) Then
				Local joyCount:Int = FlxG.JoystickCount()
				Local joyXYZRecord:XYZRecord[]

				For Local i:Int = 0 Until joyCount
					joyXYZRecord = FlxG.Joystick(i).RecordXYZ()

					If (joyXYZRecord.Length() > 0) Then
						If (joystickRecord = Null) joystickRecord = New Stack<XYZRecord[]>()
						joystickRecord.Insert(i, joyXYZRecord)
					End If

					keysRecord = FlxG.Joystick(i).RecordKeys(keysRecord)
				Next
			End If
		#End

		#If TARGET = "ios" Or TARGET = "android"
			Local touchCount:Int = FlxG.TouchCount()
			Local touchXYRecord:XYRecord

			For Local i:Int = 0 Until touchCount
				If (i > 0 And Not FlxG.Touch(i).Used) Exit

				touchXYRecord = FlxG.Touch(i).RecordXY()

				If (touchXYRecord <> Null) Then
					If (touchRecord = Null) touchRecord = New Stack<XYRecord>()
					touchRecord.Insert(i, touchXYRecord)
				End If

				keysRecord = FlxG.Touch(i).RecordKeys(keysRecord)
			Next

		#ElseIf TARGET = "html5" Or TARGET = "flash"
			If (Not FlxG.Mobile) Then
				keysRecord = FlxG.Keys.RecordKeys(keysRecord)
			End If

		#ElseIf TARGET = "xna"
			If (Not FlxG.Mobile) Then
				Local touchXYRecord:XYRecord = FlxG.Touch(0).RecordXY()

				If (touchXYRecord <> Null) Then
					If (touchRecord = Null) touchRecord = New Stack<XYRecord>()
					touchRecord.Insert(0, touchXYRecord)
				End If

				keysRecord = FlxG.Touch(0).RecordKeys(keysRecord)
				keysRecord = FlxG.Keys.RecordKeys(keysRecord)
			Else
				Local touchCount:Int = FlxG.TouchCount()
				Local touchXYRecord:XYRecord

				For Local i:Int = 0 Until touchCount
					If (i > 0 And Not FlxG.Touch(i).Used) Exit

					touchXYRecord = FlxG.Touch(i).RecordXY()

					If (touchXYRecord <> Null) Then
						If (touchRecord = Null) touchRecord = New Stack<XYRecord>()
						touchRecord.Insert(i, touchXYRecord)
					End If

					keysRecord = FlxG.Touch(i).RecordKeys(keysRecord)
				Next
			End If

		#Else
			keysRecord = FlxG.Keys.RecordKeys(keysRecord)
		#End

		#If TARGET = "android"
			keysRecord = FlxG.Keys.RecordKeys(keysRecord)
		#End

		#If TARGET = "html5" Or TARGET = "glfw"
			Local touchXYRecord:XYRecord = FlxG.Touch(0).RecordXY()

			If (touchXYRecord <> Null) Then
				If (touchRecord = Null) touchRecord = New Stack<XYRecord>()
				touchRecord.Insert(0, touchXYRecord)
			End If

			keysRecord = FlxG.Touch(0).RecordKeys(keysRecord)
		#End

		mouseRecord = FlxG.Mouse.RecordXY()
		keysRecord = FlxG.Mouse.RecordKeys(keysRecord)

		elapsed = FlxG.Elapsed

		If (keysRecord = Null And mouseRecord = Null And joystickRecord = Null And touchRecord = Null And accelRecord = Null And lastElapsed = elapsed) Then
			frame += 1
			Return
		End If

		_frames[frameCount] = (New FrameRecord()).Create(frame, elapsed, keysRecord, mouseRecord, joystickRecord, touchRecord, accelRecord)
		frame += 1
		frameCount += 1
		lastElapsed = elapsed

		If (frameCount >= _capacity) Then
			_capacity *= 2
			_frames = _frames.Resize(_capacity)
		End If
	End Method

	Method PlayNextFrame:Void()
		FlxG.ResetInput()

		If (_marker >= frameCount) Then
			finished = True
			Return
		End If

		If (_frames[_marker].frame <> frame) Then
			frame += 1
			Return
		End If

		frame += 1

		Local fr:FrameRecord = _frames[_marker]
		_marker += 1

		FlxG.Elapsed = fr.elapsed

		If (fr.keys <> Null) FlxG.Keys.PlaybackKeys(fr.keys)
		If (fr.mouse <> Null) FlxG.Mouse.PlaybackXY(fr.mouse)

		If (fr.joystick <> Null) Then
			Local i:Int = 0
			Local l:Int = fr.joystick.Length()

			While (i < l)
				FlxG.Joystick(i).PlaybackXYZ(fr.joystick.Get(i))
				i += 1
			Wend
		End If

		If (fr.touch <> Null) Then
			Local i:Int = 0
			Local l:Int = FlxG.TouchCount()
			Local tr:XYRecord

			While (i < l)
				tr = fr.touch.Get(i)
				If (tr = Null) Exit

				FlxG.Touch(i).PlaybackXY(tr)

				i += 1
			Wend
		End If

		If (fr.accel <> Null) FlxG.Accel.PlaybackXYZ(fr.accel)
	End Method

	Method Rewind:Void()
		_marker = 0
		frame = 0
		finished = False
	End Method

Private
	Method _Init:Void()
		_capacity = 100
		_frames = _frames.Resize(_capacity)
		frameCount = 0
	End Method

End Class

Interface FlxReplayListener

	Method OnReplayComplete:Void()

End Interface


AddAnimation now returns FlxAnim

AddAnimation now returns FlxAnim

Strict

Import mojo

Import flxextern
Import flxpoint
Import flxobject
Import flxcamera
Import flxg

Import system.flxanim
Import system.flxcolor

Import "data/default_flx.png"

Class FlxSprite Extends FlxObject

	Global ClassObject:Object

	Field origin:FlxPoint

	Field offset:FlxPoint

	Field scale:FlxPoint

	Field blend:Int

	Field finished:Bool

	Field frameWidth:Int

	Field frameHeight:Int

	Field frames:Int

	Field dirty:Bool

	Field _color:FlxColor

	Field _mixedColor:FlxColor

	Field _camera:FlxCamera

Private
	Global _GraphicLoader:FlxGraphicLoader = New FlxGraphicLoader()

	Global _Matrix:Float[6]

	Field _animations:StringMap<FlxAnim>

	Field _flipped:Bool

	Field _flipNeeded:Bool

	Field _curAnim:FlxAnim

	Field _curFrame:Int

	Field _curIndex:Int

	Field _frameTimer:Float

	Field _callback:FlxAnimationListener

	Field _facing:Int

	Field _alpha:Float

	Field _bakedRotation:Float

	Field _pixels:Image

	Field _halfWidth:Float

	Field _halfHeight:Float

	Field _renderer:FlxSpriteRenderer

Public
	Method New(x:Float = 0, y:Float = 0, simpleGraphic:String = "")
		Super.New(x, y)

		offset = New FlxPoint()
		origin = New FlxPoint()

		scale = New FlxPoint(1.0, 1.0)
		_alpha = 1
		_color = New FlxColor(FlxG.WHITE)
		blend = AlphaBlend
		_cameras = Null

		finished = False
		_facing = RIGHT
		_animations = New StringMap<FlxAnim>
		_flipped = False
		_curAnim = Null
		_curFrame = 0
		_curIndex = 0
		_frameTimer = 0

		_callback = Null

		_mixedColor = New FlxColor(FlxG.WHITE)

		If (simpleGraphic.Length() = 0)
			simpleGraphic = "default" + FlxG.DATA_SUFFIX
		End If

		LoadGraphic(simpleGraphic)
	End Method

	Method Destroy:Void()
		If (_animations <> Null) Then
			_animations.Clear()
			_animations = Null
		End If

		offset = Null
		origin = Null
		scale = Null
		_curAnim = Null
		_callback = Null
		_color = Null
		_mixedColor = Null
		_camera = Null
		_renderer = Null

		Super.Destroy()
	End Method

	Method LoadGraphic:FlxSprite(graphic:String, animated:Bool = False, reverse:Bool = False, width:Int = 0, height:Int = 0, unique:Bool = False)
		_bakedRotation = 0

		_GraphicLoader.name = graphic
		_GraphicLoader.animated = animated
		_GraphicLoader.width = width
		_GraphicLoader.height = height

		_pixels = FlxG.AddBitmap(graphic, _GraphicLoader, unique)

		_flipped = reverse

		Self.width = _pixels.Width()
		frameWidth = Self.width

		Self.height = _pixels.Height()
		frameHeight = Self.height

		_ResetHelpers()

		Return Self
	End Method

	Method LoadRotatedGraphic:FlxSprite(graphic:String, rotations:Int = 16, frame:Int = -1)
		Error "LoadRotatedGraphic not currenlty support in " + FlxG.LIBRARY_NAME
		'TODO
		Return Null
	End Method

	Method MakeGraphic:FlxSprite(width:Int, height:Int, color:Int = FlxG.WHITE, unique:Bool = False, key:String = "")
		_pixels = FlxG.CreateBitmap(width, height, color, unique, key)
		_bakedRotation = 0

		Self.width = width
		frameWidth = width
		Self.height = height
		frameHeight = height

		_ResetHelpers()

		Return Self
	End Method

	Method PostUpdate:Void()
		Super.PostUpdate()
		_UpdateAnimation()
	End Method

	Method Draw:Void()
		If (_flickerTimer <> 0) Then
			_flicker = Not _flicker
			If (_flicker) Return
		End If

		_camera = FlxG._CurrentCamera

		If (_cameras <> Null And Not _cameras.Contains(_camera.ID)) Return
		If (Not OnScreen(_camera)) Return

		If (dirty) _CalcFrame()

		If (FlxG._LastDrawingBlend <> blend) Then
			SetBlend(blend)
			FlxG._LastDrawingBlend = blend
		End If

		_point.x = x - int(_camera.scroll.x * scrollFactor.x) - offset.x
		_point.y = y - int(_camera.scroll.y * scrollFactor.y) - offset.y

		If (_point.x > 0) Then
			_point.x += 0.0000001
		Else
			_point.x -= 0.0000001
		End If

		If (_point.y > 0) Then
			_point.y += 0.0000001
		Else
			_point.y -= 0.0000001
		End If

		If (_camera.Color <> FlxG.WHITE) Then
			_mixedColor.MixRGB(_color, _camera._color)

			If (FlxG._LastDrawingColor <> _mixedColor.argb) Then
				SetColor(_mixedColor.r, _mixedColor.g, _mixedColor.b)
				FlxG._LastDrawingColor = _mixedColor.argb
			End If
		Else
			If (FlxG._LastDrawingColor <> _color.argb) Then
				SetColor(_color.r, _color.g, _color.b)
				FlxG._LastDrawingColor = _color.argb
			End If
		End If

		If (_camera.Alpha < 1) Then
			Local _mixedAlpha:Float = _camera.Alpha * _alpha

			If (FlxG._LastDrawingAlpha <> _mixedAlpha) Then
				SetAlpha(_mixedAlpha)
				FlxG._LastDrawingAlpha = _mixedAlpha
			End If
		Else
			If (FlxG._LastDrawingAlpha <> _alpha) Then
				SetAlpha(_alpha)
				FlxG._LastDrawingAlpha = _alpha
			End If
		End If

		If ((angle = 0 Or _bakedRotation > 0) And scale.x = 1 And scale.y = 1) Then
			If ( Not _flipNeeded) Then
				If (_renderer = Null) Then
					DrawImage(_pixels, _point.x, _point.y, _curIndex)
				Else
					_renderer.OnSpriteRender(_point.x, _point.y)
				End If
			Else
				PushMatrix()
					Transform(-1, 0, 0, 1, _point.x + _halfWidth, _point.y + _halfHeight)

					If (_renderer = Null) Then
						DrawImage(_pixels, -_halfWidth, -_halfHeight, _curIndex)
					Else
						_renderer.OnSpriteRender(-_halfWidth, -_halfHeight)
					End If
				PopMatrix()
			End If
		Else
			PushMatrix()
				'Translate
				_Matrix[4] = _point.x + origin.x
				_Matrix[5] = _point.y + origin.y

				'Scale
				_Matrix[0] = scale.x
				_Matrix[3] = scale.y

				'Rotate
				If (angle <> 0 And _bakedRotation = 0) Then
					Local sin:Float = Sin(angle)
					Local cos:Float = Cos(angle)

					_Matrix[1] = sin * _Matrix[0]
					_Matrix[2] = -sin * _Matrix[3]
					_Matrix[0] *= cos
					_Matrix[3] *= cos
				Else
					_Matrix[1] = 0
					_Matrix[2] = 0
				End If

				Transform(_Matrix[0], _Matrix[1], _Matrix[2], _Matrix[3], _Matrix[4], _Matrix[5])

				If (_flipNeeded) Then
					Transform(-1, 0, 0, 1, _halfWidth - origin.x, _halfHeight - origin.y)
				End If

				If (_renderer = Null) Then
					DrawImage(_pixels, -origin.x, -origin.y, _curIndex)
				Else
					_renderer.OnSpriteRender(-origin.x, -origin.y)
				End If
			PopMatrix()
		End If

	#If FLX_DEBUG_ENABLED = "1"
		_VisibleCount += 1;
		If (FlxG.VisualDebug And Not ignoreDrawDebug) DrawDebug(_camera);
	#End
	End Method

	Method DrawFrame:Void(force:Bool = False)
		If (force Or dirty) _CalcFrame()
	End Method

	Method AddAnimation:FlxAnim(name:String, frames:Int[], frameRate:Float = 0, looped:Bool = True)
		Local anim:FlxAnim = New FlxAnim(name, frames, frameRate, looped)
		_animations.Set(name, anim)

		Return anim
	End Method

	Method AddAnimation:FlxAnim(name:String, startFrame:Int, endFrame:Int, frameRate:Float = 0, looped:Bool = True)
		Local i:Int = 0
		Local l:Int = endFrame - startFrame + 1
		Local frames:Int[] = New Int[l]

		While (i < l)
			frames[i] = i
			i += 1
		Wend

		Return AddAnimation(name, frames, frameRate, looped)
	End Method

	Method AddAnimation:FlxAnim(name:String, frameRate:Float = 0, looped:Bool = True)
		Return AddAnimation(name, 0, _pixels.Frames(), frameRate, looped)
	End Method

	Method AddAnimationCallback:Void(animationCallback:FlxAnimationListener)
		_callback = animationCallback
	End Method

	Method Play:Void(animName:String, force:Bool = False)
		If (Not force And _curAnim <> Null And animName = _curAnim.name And( _curAnim.looped Or Not finished )) Return

		_curFrame = 0
		_curIndex = 0
		_frameTimer = 0

		Local anim:FlxAnim = _animations.Get(animName)

		If (anim <> Null) Then
			_curAnim = anim

			If (_curAnim.delay <= 0) Then
				finished = True
			Else
				finished = False
			End If

			_curIndex = _curAnim.frames[_curFrame]
			dirty = True
			Return
		End If

		FlxG.Log("WARNING: No animation called ~q" + animName + "~q")
	End Method

	Method GetAnimation:FlxAnim(animName:String)
		Return _animations.Get(animName)
	End Method

	Method GetAnimation:FlxAnim()
		Return _curAnim
	End Method

	Method RandomFrame:Void()
		_curAnim = Null

		If (_pixels <> Null) Then
			_curIndex = Int(FlxG.Random() * (_pixels.Frames() - 1))
		Else
			_curIndex = 0
		End If

		dirty = True
	End Method

	Method SetOriginToCorner:Void()
		origin.x = 0
		origin.y = 0
	End Method

	Method CenterOffsets:Void(adjustPosition:Bool = False)
		offset.x = (frameWidth - width) * .5
		offset.y = (frameHeight - height) * .5

		If (adjustPosition) Then
			x += offset.x
			y += offset.y
		End If
	End Method

	Method Pixels:Image() Property
		Return _pixels
	End Method

	Method Pixels:Void(pixels:Image) Property
		_pixels = pixels

		If (_pixels <> Null) Then
			width = pixels.Width()
			height = pixels.Height()
		Else
			width = 0
			height = 0
		End If

		frameWidth = width
		frameHeight = height
		_ResetHelpers()
	End Method

	Method Facing:Int() Property
		Return _facing
	End Method

	Method Facing:Void(direction:Int) Property
		If (_facing <> direction) dirty = True
		_facing = direction

		_flipNeeded = (_flipped And _facing = LEFT)
	End Method

	Method Alpha:Float() Property
		Return _alpha
	End Method

	Method Alpha:Void(alpha:Float) Property
		If (alpha < 0) alpha = 0
		_alpha = alpha
	End Method

	Method Color:Int() Property
		Return _color.argb
	End Method

	Method Color:Void(color:Int) Property
		_color.SetRGB(color)
	End Method

	Method Frame:Int() Property
		Return _curIndex
	End Method

	Method Frame:Void(frame:Int) Property
		_curAnim = Null
		_curIndex = frame
		dirty = True
	End Method

	Method OnScreen:Bool(camera:FlxCamera = Null)
		If (camera = Null) camera = FlxG.Camera
		GetScreenXY(_point, camera)

		_point.x = _point.x - offset.x
		_point.y = _point.y - offset.y

		If ((angle = 0 Or _bakedRotation > 0) And scale.x = 1 And scale.y = 1) Then
			Return _point.x + frameWidth > 0 And _point.x < camera.Width And _point.y + frameHeight > 0 And _point.y < camera.Height
		End If

		Local radius:Float = Sqrt(_halfWidth * _halfWidth + _halfHeight * _halfHeight) * Max(Abs(scale.x), Abs(scale.y))
		_point.x += _halfWidth
		_point.y += _halfHeight

		Return _point.x + radius > 0 And _point.x - radius < camera.Width And _point.y + radius > 0 And _point.y - radius < camera.Height
	End Method

	Method SetRenderer:Void(render:FlxSpriteRenderer)
		_renderer = render
	End Method

	Method ClearRenderer:Void()
		_renderer = Null
	End Method

	Method _ResetHelpers:Void()
		_halfWidth = frameWidth * .5
		_halfHeight = frameHeight * .5
		origin.Make(_halfWidth, _halfHeight)

		If (_pixels <> Null) Then
			frames = _pixels.Frames()
		Else
			frames = 1
		End If

		_curIndex = 0
		_mixedColor.SetARGB(FlxG.WHITE)
	End Method

Private
	Method _UpdateAnimation:Void()
		If (_bakedRotation > 0) Then
			Local oldIndex:Int = _curIndex
			Local angleHelper:Int = angle Mod 360

			If (angleHelper < 0) angleHelper += 360
			_curIndex = angleHelper / _bakedRotation + 0.5

			If (oldIndex <> _curIndex) dirty = True

		ElseIf (_curAnim <> Null And _curAnim.delay > 0 And (_curAnim.looped Or Not finished))
			_frameTimer += FlxG.Elapsed
			While (_frameTimer > _curAnim.delay)
				_frameTimer -= _curAnim.delay

				If (_curFrame = _curAnim.frames.Length() - 1) Then
					If (_curAnim.looped) _curFrame = 0
					finished = True
				Else
					_curFrame += 1
				End If

				_curIndex = _curAnim.frames[_curFrame]
				dirty = True
			Wend
		End If

		If (dirty) _CalcFrame()
	End Method

	Method _CalcFrame:Void()
		If (_callback <> Null) Then
			If (_curAnim <> Null) Then
				_callback.OnAnimationFrame(_curAnim.name, _curFrame, _curIndex)
			Else
				_callback.OnAnimationFrame("", _curFrame, _curIndex)
			End If
		End If
		dirty = False
	End Method

End Class

Interface FlxSpriteRenderer

	Method OnSpriteRender:Void(x:Float, y:Float)

End Interface

Private
Class FlxGraphicLoader Extends FlxResourceLoader<Image>

	Field name:String
	Field animated:Bool
	Field width:Float
	Field height:Float

	Method Load:Image(name:String)
		Local image:Image = LoadImage(FlxAssetsManager.GetImagePath(Self.name))

		If (Not animated) Then
			Return image
		Else
			Local frames:Int

			If (width = 0 And height = 0) Then
				width = image.Height()
			ElseIf (width = 0) Then
				width = height
			ElseIf (height = 0) Then
				height = width
			End If

			If (height = 0) Then
				frames = Ceil(image.Width() / width)
				height = width
			Else
				frames = Ceil((image.Width() * image.Height()) / (width * height))
			End If

			Return image.GrabImage(0, 0, width, height, frames)
		End If
	End Method

End Class

Strict

Import mojo

Import flxextern
Import flxpoint
Import flxobject
Import flxcamera
Import flxg

Import system.flxanim
Import system.flxcolor

Import "data/default_flx.png"

Class FlxSprite Extends FlxObject

	Global ClassObject:Object

	Field origin:FlxPoint

	Field offset:FlxPoint

	Field scale:FlxPoint

	Field blend:Int

	Field finished:Bool

	Field frameWidth:Int

	Field frameHeight:Int

	Field frames:Int

	Field dirty:Bool

	Field _color:FlxColor

	Field _mixedColor:FlxColor

	Field _camera:FlxCamera

Private
	Global _GraphicLoader:FlxGraphicLoader = New FlxGraphicLoader()

	Global _Matrix:Float[6]

	Field _animations:StringMap<FlxAnim>

	Field _flipped:Bool

	Field _flipNeeded:Bool

	Field _curAnim:FlxAnim

	Field _curFrame:Int

	Field _curIndex:Int

	Field _frameTimer:Float

	Field _callback:FlxAnimationListener

	Field _facing:Int

	Field _alpha:Float

	Field _bakedRotation:Float

	Field _pixels:Image

	Field _halfWidth:Float

	Field _halfHeight:Float

	Field _renderer:FlxSpriteRenderer

Public
	Method New(x:Float = 0, y:Float = 0, simpleGraphic:String = "")
		Super.New(x, y)

		offset = New FlxPoint()
		origin = New FlxPoint()

		scale = New FlxPoint(1.0, 1.0)
		_alpha = 1
		_color = New FlxColor(FlxG.WHITE)
		blend = AlphaBlend
		_cameras = Null

		finished = False
		_facing = RIGHT
		_animations = New StringMap<FlxAnim>
		_flipped = False
		_curAnim = Null
		_curFrame = 0
		_curIndex = 0
		_frameTimer = 0

		_callback = Null

		_mixedColor = New FlxColor(FlxG.WHITE)

		If (simpleGraphic.Length() = 0)
			simpleGraphic = "default" + FlxG.DATA_SUFFIX
		End If

		LoadGraphic(simpleGraphic)
	End Method

	Method Destroy:Void()
		If (_animations <> Null) Then
			_animations.Clear()
			_animations = Null
		End If

		offset = Null
		origin = Null
		scale = Null
		_curAnim = Null
		_callback = Null
		_color = Null
		_mixedColor = Null
		_camera = Null
		_renderer = Null

		Super.Destroy()
	End Method

	Method LoadGraphic:FlxSprite(graphic:String, animated:Bool = False, reverse:Bool = False, width:Int = 0, height:Int = 0, unique:Bool = False)
		_bakedRotation = 0

		_GraphicLoader.name = graphic
		_GraphicLoader.animated = animated
		_GraphicLoader.width = width
		_GraphicLoader.height = height

		_pixels = FlxG.AddBitmap(graphic, _GraphicLoader, unique)

		_flipped = reverse

		Self.width = _pixels.Width()
		frameWidth = Self.width

		Self.height = _pixels.Height()
		frameHeight = Self.height

		_ResetHelpers()

		Return Self
	End Method

	Method LoadRotatedGraphic:FlxSprite(graphic:String, rotations:Int = 16, frame:Int = -1)
		Error "LoadRotatedGraphic not currenlty support in " + FlxG.LIBRARY_NAME
		'TODO
		Return Null
	End Method

	Method MakeGraphic:FlxSprite(width:Int, height:Int, color:Int = FlxG.WHITE, unique:Bool = False, key:String = "")
		_pixels = FlxG.CreateBitmap(width, height, color, unique, key)
		_bakedRotation = 0

		Self.width = width
		frameWidth = width
		Self.height = height
		frameHeight = height

		_ResetHelpers()

		Return Self
	End Method

	Method PostUpdate:Void()
		Super.PostUpdate()
		_UpdateAnimation()
	End Method

	Method Draw:Void()
		If (_flickerTimer <> 0) Then
			_flicker = Not _flicker
			If (_flicker) Return
		End If

		_camera = FlxG._CurrentCamera

		If (_cameras <> Null And Not _cameras.Contains(_camera.ID)) Return
		If (Not OnScreen(_camera)) Return

		If (dirty) _CalcFrame()

		If (FlxG._LastDrawingBlend <> blend) Then
			SetBlend(blend)
			FlxG._LastDrawingBlend = blend
		End If

		_point.x = x - int(_camera.scroll.x * scrollFactor.x) - offset.x
		_point.y = y - int(_camera.scroll.y * scrollFactor.y) - offset.y

		If (_point.x > 0) Then
			_point.x += 0.0000001
		Else
			_point.x -= 0.0000001
		End If

		If (_point.y > 0) Then
			_point.y += 0.0000001
		Else
			_point.y -= 0.0000001
		End If

		If (_camera.Color <> FlxG.WHITE) Then
			_mixedColor.MixRGB(_color, _camera._color)

			If (FlxG._LastDrawingColor <> _mixedColor.argb) Then
				SetColor(_mixedColor.r, _mixedColor.g, _mixedColor.b)
				FlxG._LastDrawingColor = _mixedColor.argb
			End If
		Else
			If (FlxG._LastDrawingColor <> _color.argb) Then
				SetColor(_color.r, _color.g, _color.b)
				FlxG._LastDrawingColor = _color.argb
			End If
		End If

		If (_camera.Alpha < 1) Then
			Local _mixedAlpha:Float = _camera.Alpha * _alpha

			If (FlxG._LastDrawingAlpha <> _mixedAlpha) Then
				SetAlpha(_mixedAlpha)
				FlxG._LastDrawingAlpha = _mixedAlpha
			End If
		Else
			If (FlxG._LastDrawingAlpha <> _alpha) Then
				SetAlpha(_alpha)
				FlxG._LastDrawingAlpha = _alpha
			End If
		End If

		If ((angle = 0 Or _bakedRotation > 0) And scale.x = 1 And scale.y = 1) Then
			If ( Not _flipNeeded) Then
				If (_renderer = Null) Then
					DrawImage(_pixels, _point.x, _point.y, _curIndex)
				Else
					_renderer.OnSpriteRender(_point.x, _point.y)
				End If
			Else
				PushMatrix()
					Transform(-1, 0, 0, 1, _point.x + _halfWidth, _point.y + _halfHeight)

					If (_renderer = Null) Then
						DrawImage(_pixels, -_halfWidth, -_halfHeight, _curIndex)
					Else
						_renderer.OnSpriteRender(-_halfWidth, -_halfHeight)
					End If
				PopMatrix()
			End If
		Else
			PushMatrix()
				'Translate
				_Matrix[4] = _point.x + origin.x
				_Matrix[5] = _point.y + origin.y

				'Scale
				_Matrix[0] = scale.x
				_Matrix[3] = scale.y

				'Rotate
				If (angle <> 0 And _bakedRotation = 0) Then
					Local sin:Float = Sin(angle)
					Local cos:Float = Cos(angle)

					_Matrix[1] = sin * _Matrix[0]
					_Matrix[2] = -sin * _Matrix[3]
					_Matrix[0] *= cos
					_Matrix[3] *= cos
				Else
					_Matrix[1] = 0
					_Matrix[2] = 0
				End If

				Transform(_Matrix[0], _Matrix[1], _Matrix[2], _Matrix[3], _Matrix[4], _Matrix[5])

				If (_flipNeeded) Then
					Transform(-1, 0, 0, 1, _halfWidth - origin.x, _halfHeight - origin.y)
				End If

				If (_renderer = Null) Then
					DrawImage(_pixels, -origin.x, -origin.y, _curIndex)
				Else
					_renderer.OnSpriteRender(-origin.x, -origin.y)
				End If
			PopMatrix()
		End If

	#If FLX_DEBUG_ENABLED = "1"
		_VisibleCount += 1;
		If (FlxG.VisualDebug And Not ignoreDrawDebug) DrawDebug(_camera);
	#End
	End Method

	Method DrawFrame:Void(force:Bool = False)
		If (force Or dirty) _CalcFrame()
	End Method

	Method AddAnimation:Void(name:String, frames:Int[], frameRate:Float = 0, looped:Bool = True)
		_animations.Set(name, New FlxAnim(name, frames, frameRate, looped))
	End Method

	Method AddAnimation:Void(name:String, startFrame:Int, endFrame:Int, frameRate:Float = 0, looped:Bool = True)
		Local i:Int = 0
		Local l:Int = endFrame - startFrame + 1
		Local frames:Int[] = New Int[l]

		While (i < l)
			frames[i] = i
			i += 1
		Wend

		AddAnimation(name, frames, frameRate, looped)
	End Method

	Method AddAnimation:Void(name:String, frameRate:Float = 0, looped:Bool = True)
		AddAnimation(name, 0, _pixels.Frames(), frameRate, looped)
	End Method

	Method AddAnimationCallback:Void(animationCallback:FlxAnimationListener)
		_callback = animationCallback
	End Method

	Method Play:Void(animName:String, force:Bool = False)
		If (Not force And _curAnim <> Null And animName = _curAnim.name And( _curAnim.looped Or Not finished )) Return

		_curFrame = 0
		_curIndex = 0
		_frameTimer = 0

		Local anim:FlxAnim = _animations.Get(animName)

		If (anim <> Null) Then
			_curAnim = anim

			If (_curAnim.delay <= 0) Then
				finished = True
			Else
				finished = False
			End If

			_curIndex = _curAnim.frames[_curFrame]
			dirty = True
			Return
		End If

		FlxG.Log("WARNING: No animation called ~q" + animName + "~q")
	End Method

	Method GetAnimation:FlxAnim(animName:String)
		Return _animations.Get(animName)
	End Method

	Method GetAnimation:FlxAnim()
		Return _curAnim
	End Method

	Method RandomFrame:Void()
		_curAnim = Null

		If (_pixels <> Null) Then
			_curIndex = Int(FlxG.Random() * (_pixels.Frames() - 1))
		Else
			_curIndex = 0
		End If

		dirty = True
	End Method

	Method SetOriginToCorner:Void()
		origin.x = 0
		origin.y = 0
	End Method

	Method CenterOffsets:Void(adjustPosition:Bool = False)
		offset.x = (frameWidth - width) * .5
		offset.y = (frameHeight - height) * .5

		If (adjustPosition) Then
			x += offset.x
			y += offset.y
		End If
	End Method

	Method Pixels:Image() Property
		Return _pixels
	End Method

	Method Pixels:Void(pixels:Image) Property
		_pixels = pixels

		If (_pixels <> Null) Then
			width = pixels.Width()
			height = pixels.Height()
		Else
			width = 0
			height = 0
		End If

		frameWidth = width
		frameHeight = height
		_ResetHelpers()
	End Method

	Method Facing:Int() Property
		Return _facing
	End Method

	Method Facing:Void(direction:Int) Property
		If (_facing <> direction) dirty = True
		_facing = direction

		_flipNeeded = (_flipped And _facing = LEFT)
	End Method

	Method Alpha:Float() Property
		Return _alpha
	End Method

	Method Alpha:Void(alpha:Float) Property
		If (alpha < 0) alpha = 0
		_alpha = alpha
	End Method

	Method Color:Int() Property
		Return _color.argb
	End Method

	Method Color:Void(color:Int) Property
		_color.SetRGB(color)
	End Method

	Method Frame:Int() Property
		Return _curIndex
	End Method

	Method Frame:Void(frame:Int) Property
		_curAnim = Null
		_curIndex = frame
		dirty = True
	End Method

	Method OnScreen:Bool(camera:FlxCamera = Null)
		If (camera = Null) camera = FlxG.Camera
		GetScreenXY(_point, camera)

		_point.x = _point.x - offset.x
		_point.y = _point.y - offset.y

		If ((angle = 0 Or _bakedRotation > 0) And scale.x = 1 And scale.y = 1) Then
			Return _point.x + frameWidth > 0 And _point.x < camera.Width And _point.y + frameHeight > 0 And _point.y < camera.Height
		End If

		Local radius:Float = Sqrt(_halfWidth * _halfWidth + _halfHeight * _halfHeight) * Max(Abs(scale.x), Abs(scale.y))
		_point.x += _halfWidth
		_point.y += _halfHeight

		Return _point.x + radius > 0 And _point.x - radius < camera.Width And _point.y + radius > 0 And _point.y - radius < camera.Height
	End Method

	Method SetRenderer:Void(render:FlxSpriteRenderer)
		_renderer = render
	End Method

	Method ClearRenderer:Void()
		_renderer = Null
	End Method

	Method _ResetHelpers:Void()
		_halfWidth = frameWidth * .5
		_halfHeight = frameHeight * .5
		origin.Make(_halfWidth, _halfHeight)

		If (_pixels <> Null) Then
			frames = _pixels.Frames()
		Else
			frames = 1
		End If

		_curIndex = 0
		_mixedColor.SetARGB(FlxG.WHITE)
	End Method

Private
	Method _UpdateAnimation:Void()
		If (_bakedRotation > 0) Then
			Local oldIndex:Int = _curIndex
			Local angleHelper:Int = angle Mod 360

			If (angleHelper < 0) angleHelper += 360
			_curIndex = angleHelper / _bakedRotation + 0.5

			If (oldIndex <> _curIndex) dirty = True

		ElseIf (_curAnim <> Null And _curAnim.delay > 0 And (_curAnim.looped Or Not finished))
			_frameTimer += FlxG.Elapsed
			While (_frameTimer > _curAnim.delay)
				_frameTimer -= _curAnim.delay

				If (_curFrame = _curAnim.frames.Length() - 1) Then
					If (_curAnim.looped) _curFrame = 0
					finished = True
				Else
					_curFrame += 1
				End If

				_curIndex = _curAnim.frames[_curFrame]
				dirty = True
			Wend
		End If

		If (dirty) _CalcFrame()
	End Method

	Method _CalcFrame:Void()
		If (_callback <> Null) Then
			If (_curAnim <> Null) Then
				_callback.OnAnimationFrame(_curAnim.name, _curFrame, _curIndex)
			Else
				_callback.OnAnimationFrame("", _curFrame, _curIndex)
			End If
		End If
		dirty = False
	End Method

End Class

Interface FlxSpriteRenderer

	Method OnSpriteRender:Void(x:Float, y:Float)

End Interface

Private
Class FlxGraphicLoader Extends FlxResourceLoader<Image>

	Field name:String
	Field animated:Bool
	Field width:Float
	Field height:Float

	Method Load:Image(name:String)
		Local image:Image = LoadImage(FlxAssetsManager.GetImagePath(Self.name))

		If (Not animated) Then
			Return image
		Else
			Local frames:Int

			If (width = 0 And height = 0) Then
				width = image.Height()
			ElseIf (width = 0) Then
				width = height
			ElseIf (height = 0) Then
				height = width
			End If

			If (height = 0) Then
				frames = Ceil(image.Width() / width)
				height = width
			Else
				frames = Ceil((image.Width() * image.Height()) / (width * height))
			End If

			Return image.GrabImage(0, 0, width, height, frames)
		End If
	End Method

End Class


add Target.IS_MARKET_SAMSUNG

add Target.IS_MARKET_SAMSUNG

Strict

#BONO_ANDROID_MARKET="google"
#If Not (BONO_ANDROID_MARKET="google") And Not (BONO_ANDROID_MARKET="amazon") And Not (BONO_ANDROID_MARKET="samsung")
    #Error "BONO: Invalid BONO_ANDROID_MARKET setting"
#End

Class Target Abstract

#If BONO_ANDROID_MARKET="google"
    Const IS_MARKET_GOOGLE:Bool = True
#Else
    Const IS_MARKET_GOOGLE:Bool = False
#End

#If BONO_ANDROID_MARKET="amazon"
    Const IS_MARKET_AMAZON:Bool = True
#Else
    Const IS_MARKET_AMAZON:Bool = False
#End

#If BONO_ANDROID_MARKET="samsung"
    Const IS_MARKET_SAMSUNG:Bool = True
#Else
    Const IS_MARKET_SAMSUNG:Bool = False
#End

#If LANG="js"
    Const LANG:String = "js"
#ElseIf LANG="as"
    Const LANG:String = "as"
#ElseIf LANG="java"
    Const LANG:String = "java"
#ElseIf LANG="cpp"
    Const LANG:String = "cpp"
#Else
    #Error "BONO: Unknown LANG in utils.Target"
#End

#If HOST="winnt"
    Const HOST:String = "winnt"
    Const IS_MAC:Bool = False
    Const IS_WIN:Bool = True
#ElseIf HOST="macos"
    Const HOST:String = "macos"
    Const IS_MAC:Bool = True
    Const IS_WIN:Bool = False
#Else
    #Error "BONO: Unknown HOST in utils.Target"
#End

#If CONFIG="debug"
    Const CONFIG:String = "debug"
    Const IS_DEBUG:Bool = True
    Const IS_RELEASE:Bool = False
#ElseIf CONFIG="release"
    Const CONFIG:String = "release"
    Const IS_DEBUG:Bool = False
    Const IS_RELEASE:Bool = True
#Else
    #Error "BONO: Unknown CONFIG in utils.Target"
#End

#If TARGET="android"
    Const TARGET:String = "android"
    Const IS_ANDROID:Bool = True
#Else
    Const IS_ANDROID:Bool = False
#End

#If TARGET="flash"
    Const TARGET:String = "flash"
    Const IS_FLASH:Bool = True
#Else
    Const IS_FLASH:Bool = False
#End

#If TARGET="glfw"
    Const TARGET:String = "glfw"
    Const IS_GLFW:Bool = True
#Else
    Const IS_GLFW:Bool = False
#End

#If TARGET="html5"
    Const TARGET:String = "html5"
    Const IS_HTML5:Bool = True
#Else
    Const IS_HTML5:Bool = False
#End

#If TARGET="ios"
    Const TARGET:String = "ios"
    Const IS_IOS:Bool = True
#Else
    Const IS_IOS:Bool = False
#End

#If TARGET="metro"
    Const TARGET:String = "metro"
    Const IS_METRO:Bool = True
#Else
    Const IS_METRO:Bool = False
#End

#If TARGET="psm"
    Const TARGET:String = "psm"
    Const IS_PSM:Bool = True
#Else
    Const IS_PSM:Bool = False
#End

#If TARGET="stdcpp"
    Const TARGET:String = "stdcpp"
    Const IS_STDCPP:Bool = True
#Else
    Const IS_STDCPP:Bool = False
#End

#If TARGET="xna"
    Const TARGET:String = "xna"
    Const IS_XNA:Bool = True
#Else
    Const IS_XNA:Bool = False
#End

End

Strict

#BONO_ANDROID_MARKET="google"
#If Not (BONO_ANDROID_MARKET="google") And Not (BONO_ANDROID_MARKET="amazon")
    #Error "BONO: Invalid BONO_ANDROID_MARKET setting"
#End

Class Target Abstract

#If BONO_ANDROID_MARKET="google"
    Const IS_MARKET_GOOGLE:Bool = True
#Else
    Const IS_MARKET_GOOGLE:Bool = False
#End

#If BONO_ANDROID_MARKET="amazon"
    Const IS_MARKET_AMAZON:Bool = True
#Else
    Const IS_MARKET_AMAZON:Bool = False
#End

#If LANG="js"
    Const LANG:String = "js"
#ElseIf LANG="as"
    Const LANG:String = "as"
#ElseIf LANG="java"
    Const LANG:String = "java"
#ElseIf LANG="cpp"
    Const LANG:String = "cpp"
#Else
    #Error "BONO: Unknown LANG in utils.Target"
#End

#If HOST="winnt"
    Const HOST:String = "winnt"
    Const IS_MAC:Bool = False
    Const IS_WIN:Bool = True
#ElseIf HOST="macos"
    Const HOST:String = "macos"
    Const IS_MAC:Bool = True
    Const IS_WIN:Bool = False
#Else
    #Error "BONO: Unknown HOST in utils.Target"
#End

#If CONFIG="debug"
    Const CONFIG:String = "debug"
    Const IS_DEBUG:Bool = True
    Const IS_RELEASE:Bool = False
#ElseIf CONFIG="release"
    Const CONFIG:String = "release"
    Const IS_DEBUG:Bool = False
    Const IS_RELEASE:Bool = True
#Else
    #Error "BONO: Unknown CONFIG in utils.Target"
#End

#If TARGET="android"
    Const TARGET:String = "android"
    Const IS_ANDROID:Bool = True
#Else
    Const IS_ANDROID:Bool = False
#End

#If TARGET="flash"
    Const TARGET:String = "flash"
    Const IS_FLASH:Bool = True
#Else
    Const IS_FLASH:Bool = False
#End

#If TARGET="glfw"
    Const TARGET:String = "glfw"
    Const IS_GLFW:Bool = True
#Else
    Const IS_GLFW:Bool = False
#End

#If TARGET="html5"
    Const TARGET:String = "html5"
    Const IS_HTML5:Bool = True
#Else
    Const IS_HTML5:Bool = False
#End

#If TARGET="ios"
    Const TARGET:String = "ios"
    Const IS_IOS:Bool = True
#Else
    Const IS_IOS:Bool = False
#End

#If TARGET="metro"
    Const TARGET:String = "metro"
    Const IS_METRO:Bool = True
#Else
    Const IS_METRO:Bool = False
#End

#If TARGET="psm"
    Const TARGET:String = "psm"
    Const IS_PSM:Bool = True
#Else
    Const IS_PSM:Bool = False
#End

#If TARGET="stdcpp"
    Const TARGET:String = "stdcpp"
    Const IS_STDCPP:Bool = True
#Else
    Const IS_STDCPP:Bool = False
#End

#If TARGET="xna"
    Const TARGET:String = "xna"
    Const IS_XNA:Bool = True
#Else
    Const IS_XNA:Bool = False
#End

End