Change Sprite size accordingly to the used scale

Strict

Private

Import baseobject
Import deltatimer
Import director
Import mojo.graphics
Import vector2d

Public

Class Sprite Extends BaseObject
    Private

    Field currentFrame:Int
    Field frameCount:Int
    Field frameSize:Vector2D
    Field frameTimer:Int
    Field image:Image
    Field imageName:String
    Field _scale:Vector2D = New Vector2D(1, 1)

    Public

    Field frameSpeed:Int
    Field loopAnimation:Bool
    Field rotation:Float

    Method New(imageName:String, pos:Vector2D=Null)
        SetNameAndPos(imageName, pos)
    End

    Method New(imageName:String, frameSize:Vector2D, frameCount:Int, frameSpeed:Int, pos:Vector2D=Null)
        SetNameAndPos(imageName, pos)

        Self.frameSize = frameSize
        Self.frameCount = frameCount
        Self.frameSpeed = frameSpeed
    End

    Method OnCreate:Void(director:Director)
        Super.OnCreate(director)

        If frameSize
            image = LoadImage(imageName, frameSize.x, frameSize.y, frameCount)
            size = frameSize.Copy()
        Else
            image = LoadImage(imageName)
            size = New Vector2D(image.Width(), image.Height())
        End

        size.Mul(scale)
    End

    Method OnRender:Void()
        If color Then color.Activate()
        DrawImage(image, pos.x, pos.y, rotation, scale.x, scale.y, currentFrame)
        If color Then color.Deactivate()
    End

    Method OnUpdate:Void(deltaTimer:DeltaTimer)
        If frameCount <= 0 Then Return
        If animationIsDone Then Return

        If frameTimer < frameSpeed
            frameTimer += deltaTimer.frameTime
            Return
        End

        If (currentFrame + 1) = frameCount
            If loopAnimation
                currentFrame = 1
            End
        Else
            currentFrame += 1
        End
        frameTimer = 0
    End

    Method Restart:Void()
        currentFrame = 0
    End

    Method Collide:Bool(checkPos:Vector2D)
        If checkPos.x < pos.x Or checkPos.x > pos.x + size.x Then Return False
        If checkPos.y < pos.y Or checkPos.y > pos.y + size.y Then Return False
        Return True
    End

    Method animationIsDone:Bool() Property
        If loopAnimation Then Return False
        Return (currentFrame = frameCount)
    End

    Method scale:Vector2D() Property
        Return _scale
    End

    Method scale:Void(newScale:Vector2D) Property
        If image Then size = size.Div(_scale).Mul(newScale)
        _scale = newScale
    End

    Private

    Method SetNameAndPos:Void(imageName:String, pos:Vector2D=Null)
        Self.imageName = imageName
        If Not pos Then pos = New Vector2D(0, 0)
        Self.pos = pos
    End
End

Strict

Private

Import baseobject
Import deltatimer
Import director
Import mojo.graphics
Import vector2d

Public

Class Sprite Extends BaseObject
    Private

    Field currentFrame:Int
    Field frameCount:Int
    Field frameSize:Vector2D
    Field frameTimer:Int
    Field image:Image
    Field imageName:String

    Public

    Field frameSpeed:Int
    Field loopAnimation:Bool
    Field rotation:Float
    Field scale:Vector2D = New Vector2D(1, 1)

    Method New(imageName:String, pos:Vector2D=Null)
        SetNameAndPos(imageName, pos)
    End

    Method New(imageName:String, frameSize:Vector2D, frameCount:Int, frameSpeed:Int, pos:Vector2D=Null)
        SetNameAndPos(imageName, pos)

        Self.frameSize = frameSize
        Self.frameCount = frameCount
        Self.frameSpeed = frameSpeed
    End

    Method OnCreate:Void(director:Director)
        Super.OnCreate(director)

        If frameSize
            image = LoadImage(imageName, frameSize.x, frameSize.y, frameCount)
            size = frameSize.Copy()
        Else
            image = LoadImage(imageName)
            size = New Vector2D(image.Width(), image.Height())
        End
    End

    Method OnRender:Void()
        If color Then color.Activate()
        DrawImage(image, pos.x, pos.y, rotation, scale.x, scale.y, currentFrame)
        If color Then color.Deactivate()
    End

    Method OnUpdate:Void(deltaTimer:DeltaTimer)
        If frameCount <= 0 Then Return
        If animationIsDone Then Return

        If frameTimer < frameSpeed
            frameTimer += deltaTimer.frameTime
            Return
        End

        If (currentFrame + 1) = frameCount
            If loopAnimation
                currentFrame = 1
            End
        Else
            currentFrame += 1
        End
        frameTimer = 0
    End

    Method Restart:Void()
        currentFrame = 0
    End

    Method Collide:Bool(checkPos:Vector2D)
        If checkPos.x < pos.x Or checkPos.x > pos.x + size.x Then Return False
        If checkPos.y < pos.y Or checkPos.y > pos.y + size.y Then Return False
        Return True
    End

    Method animationIsDone:Bool() Property
        If loopAnimation Then Return False
        Return (currentFrame = frameCount)
    End

    Private

    Method SetNameAndPos:Void(imageName:String, pos:Vector2D=Null)
        Self.imageName = imageName
        If Not pos Then pos = New Vector2D(0, 0)
        Self.pos = pos
    End
End


Bug fixes. Refactoring

Bug fixes. Refactoring

Strict

Import mojo.graphics
Import flixel.flxpoint
Import flixel.flxrect
Import flixel.system.flxcolor

Class FlxBitmapData

Private
	Global _ZeroPoint:FlxPoint = New FlxPoint()

	Field _width:Int

	Field _height:Int

	Field _scroll:FlxPoint

	Field _padding:FlxPoint

	Field _withPixelsArray:Bool

	Field _image:Image

	Field _sourceImage:Image

	Field _destImage:Image

	Field _color:FlxColor

	Field _rect:FlxRect

	Field _pixels:Int[]

	Field _dirty:Bool

Public
	Method New(width:Int, height:Int, withPixelsArray:Bool = False, fillColor:Int = $00000000)
		_image = CreateImage(width, height)
		_color = New FlxColor(fillColor)
		_rect = New FlxRect()

		_width = width
		_height = height
		_scroll = New FlxPoint()
		_padding = New FlxPoint()
		_withPixelsArray = withPixelsArray
		_dirty = False

		If (_withPixelsArray) _pixels = New Int[_width * _height]

		If (_color.a > 0) Then
			If ( Not _withPixelsArray) _pixels = New Int[_width * _height]
			_WritePixels(0, 0, _width, _height, fillColor)
		End If
	End Method

	Method Destroy:Void(discard:Bool = False)
		_pixels =[]
		_color = Null
		_rect = Null
		_scroll = Null
		_padding = Null

		If (discard) _image.Discard()
		If (_sourceImage <> Null) _sourceImage.Discard()

		_image = Null
		_sourceImage = Null
		_destImage = Null
	End Method

	Method CopyPixels:Void(sourceBitmapData:FlxBitmapData, sourceRect:FlxRect = Null, destPoint:FlxPoint = Null)
		If (sourceRect = Null) sourceRect = New FlxRect(0, 0, Min(_width - Int(_scroll.x), sourceBitmapData._width), Min(_height - Int(_scroll.y), sourceBitmapData._height))
		If (destPoint = Null) destPoint = _ZeroPoint

		If (sourceBitmapData._withPixelsArray) Then
			SetPixels(_rect.Make(destPoint.x, destPoint.y, sourceRect.width, sourceRect.height), sourceBitmapData.GetPixels(sourceRect))
		Else
			Cls
			DrawImage(sourceBitmapData._image, 0, 0)
			_GrabPixels(sourceRect.x, sourceRect.y, sourceRect.width, sourceRect.height, destPoint.x, destPoint.y)
			Cls
		End If
	End Method

	Method CopyPixels:Void(sourceImage:Image, sourceRect:FlxRect = Null, destPoint:FlxPoint = Null)
		If (sourceRect = Null) Then
			If (sourceImage.Frames() = 1) Then
				sourceRect = _rect.Make(0, 0, Min(_width - Int(_scroll.x), sourceImage.Width()), Min(_height - Int(_scroll.y), sourceImage.Height()))
			Else
				sourceRect = _rect.Make(0, 0, _width - Int(_scroll.x), _height - Int(_scroll.y))
			 End If
		End If

		If (destPoint = Null) destPoint = _ZeroPoint

		Cls
		_DrawAsSpriteSheet(sourceImage, _padding.x, _padding.y, True)
		_GrabPixels(sourceRect.x, sourceRect.y, sourceRect.width, sourceRect.height, destPoint.x, destPoint.y)
		Cls
	End Method

	Method CopyPixels:Void(sourceRect:FlxRect = Null, destPoint:FlxPoint = Null)
		If (sourceRect = Null) sourceRect = _rect.Make(0, 0, Min(_width - Int(_scroll.x), DeviceWidth()), Min(_height - Int(_scroll.y), DeviceHeight()))
		If (destPoint = Null) destPoint = _ZeroPoint

		_GrabPixels(sourceRect.x, sourceRect.y, sourceRect.width, sourceRect.height, destPoint.x, destPoint.y)
	End Method

	Method Dispose:Void()
		_pixels =[]
		_withPixelsArray = False
		If (_sourceImage <> Null) _sourceImage.Discard()
	End Method

	Method FillRect:Void(rect:FlxRect, color:Int)
		_WritePixels(rect.x, rect.y, rect.width, rect.height, color)
	End Method

	Method FloodFill:Void(x:Int, y:Int, color:Int)
		FillRect(_rect.Make(x, y, _width - x, _height - y), color)
	End Method

	Method GetPixel:Int(x:Float, y:Float)
		If ( Not _withPixelsArray) Then
			_ReadPixels(x, y, 1, 1)
			Return _pixels[0]
		Else
			Return _pixels[x + y * _width]
		End If
	End Method

	Method GetPixels:Int[] (rect:FlxRect)
		Local result:Int[] = New Int[rect.width * rect.height]

		If ( Not _withPixelsArray) Then
			Local i:Int = 0, l:Int = result.Length()
			_ReadPixels(rect.x, rect.y, rect.width, rect.height)

			While (i < l)
				result[i] = _pixels[i]
				i += 1
			Wend
		Else
			Local i:Int, j:Int, k:Int = rect.x + rect.y * _width, index:Int

			For i = 0 Until rect.height
				For j = 0 Until rect.width
					result[index] = _pixels[k]
					k += 1
					index += 1
				Next
				k += _width - rect.width
			Next
		End If

		Return result
	End Method

	Method Scroll:Void(x:Int, y:Int)
		_scroll.Make(x, y)
	End Method

	Method SetPixel:Void(x:Int, y:Float, color:Int)
		FillRect(_rect.Make(x, y, 1, 1), color)
	End Method

	Method SetPixels:Void(rect:FlxRect, pixels:Int[])
		_WritePixels(rect.x, rect.y, rect.width, rect.height, pixels)
	End Method

	Method Width:Int() Property
		Return _width
	End Method

	Method Height:Int() Property
		Return _height
	End Method

	Method Image:Image() Property
		If (_sourceImage <> Null) Then
			If ( Not _dirty) Return _destImage

			Local flags:Int

			If (_padding.x = 1) flags |= graphics.Image.XPadding
			If (_padding.y = 1) flags |= graphics.Image.YPadding

			_destImage = _image.GrabImage(0, 0, _sourceImage.Width() +_padding.x * 2, _sourceImage.Height() +_padding.y * 2, _sourceImage.Frames(), flags)
			_destImage.SetHandle(_sourceImage.HandleX(), _sourceImage.HandleY())
			_dirty = False

			Return _destImage
		End If

		Return _image
	End Method

	Function FromImage:FlxBitmapData(image:Image, withPixelsArray:Bool = False, paddingX:Int = 0, paddingY:Int)
		Return _FromImage(image, withPixelsArray, paddingX, paddingY)
	End Function

	Function FromImage:FlxBitmapData(image:Image, withPixelsArray:Bool = False, paddings:Int = 0)
		Local paddingX:Int, paddingY:Int

		If (paddings & graphics.Image.XPadding) paddingX = 1
		If (paddings & graphics.Image.YPadding) paddingY = 1

		Return _FromImage(image, withPixelsArray, paddingX, paddingY)
	End Function

	Function FromImage:FlxBitmapData(image:Image, withPixelsArray:Bool = False)
		Local paddingX:Int, paddingY:Int

		If (image.Flags() & graphics.Image.XPadding) paddingX = 1
		If (image.Flags() & graphics.Image.YPadding) paddingY = 1

		Return _FromImage(image, withPixelsArray, paddingX, paddingY)
	End Function

Private
	Function _FromImage:FlxBitmapData(image:Image, withPixelsArray:Bool, paddingX:Int, paddingY:Int)
		Local rows:Int = Sqrt(image.Frames()), cols:Int = image.Frames() / rows

		Local bitmapData:FlxBitmapData = New FlxBitmapData(cols * (image.Width() +paddingX * 2), rows * (image.Height() +paddingY * 2), withPixelsArray)

		bitmapData._padding.x = paddingX
		bitmapData._padding.y = paddingY

		bitmapData.CopyPixels(image)
		bitmapData._sourceImage = image

		Return bitmapData
	End Function

	Method _DrawAsSpriteSheet:Void(image:Image, paddingX:Int = 0, paddingY:Int = 0, fillPaddings:Bool = False)
		Local x:Float = paddingX, y:Float = paddingY
		Local w:Int = image.Width(), h:Int = image.Height()
		Local hx:Int = image.HandleX(), hy:Int = image.HandleY()
		Local i:Int = 0, l:Int = image.Frames()

		image.SetHandle(0, 0)

		While (i < l)
			If (paddingX > 0 And fillPaddings) DrawImageRect(image, x - paddingX, y, 0, 0, paddingX, h, i)

			If (paddingY > 0 And fillPaddings) Then
				DrawImageRect(image, x - paddingX, y - paddingY, 0, 0, paddingX, paddingY, i)
				DrawImageRect(image, x, y - paddingY, 0, 0, w, paddingY, i)
				DrawImageRect(image, x + w, y - paddingY, w - paddingX, 0, paddingX, paddingY, i)
			End If

			DrawImage(image, x, y, i)

			If (paddingX > 0 And fillPaddings) DrawImageRect(image, x + w, y, w - paddingX, 0, paddingX, h, i)

			If (paddingY > 0 And fillPaddings) Then
				DrawImageRect(image, x - paddingX, y + h, 0, h - paddingY, paddingX, paddingY, i)
				DrawImageRect(image, x, y + h, 0, h - paddingY, w, paddingY, i)
				DrawImageRect(image, x + w, y + h, w - paddingX, h - paddingY, paddingX, paddingY, i)
			End If

			x += w + paddingX * 2

			If (x + w + paddingX * 2 > _width + paddingX) Then
				x = paddingX
				y += h + paddingY * 2

				If (y + h + paddingY * 2 > _height + paddingY) Then
					Exit
				End If
			End If

			i += 1
		Wend

		image.SetHandle(hx, hy)
	End Method

	Method _CheckPixelsArray:Void(width:Int, height:Int)
		If (_pixels.Length() < width * height) Then
			_pixels = _pixels.Resize(width * height)
		End If
	End Method

	Method _ReadPixels:Void(x:Int, y:Int, width:Int, height:Int)
		x += _scroll.x
		y += _scroll.y

		If ( Not _withPixelsArray) Then
			_CheckPixelsArray(width, height)
			ReadPixels(_pixels, x, y, width, height)
		Else
			Local offset:Int = x + y * width
			ReadPixels(_pixels, x, y, width, height, offset, _width)
		End If
	End Method

	Method _GrabPixels:Void(x:Int, y:Int, width:Int, height:Int, destX:Int, destY:Int)
		destX += _scroll.x
		destY += _scroll.y

		If ( Not _withPixelsArray) Then
			_CheckPixelsArray(width, height)
			ReadPixels(_pixels, x, y, width, height)
			_image.WritePixels(_pixels, destX, destY, width, height)
		Else
			Local offset:Int = destX + destY * width

			ReadPixels(_pixels, x, y, width, height, offset, _width)
			_image.WritePixels(_pixels, destX, destY, width, height, offset, _width)
		End If

		_Invalidate()
	End Method

	Method _WritePixels:Void(x:Int, y:Int, width:Int, height:Int, color:Int)
		x += _scroll.x
		y += _scroll.y

		If ( Not _withPixelsArray) Then
			Local i:Int = 0, l:Int = width * height
			_CheckPixelsArray(width, height)

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

			_image.WritePixels(_pixels, x, y, width, height)
		Else
			Local i:Int, j:Int, k:Int = x + y * width

			For i = 0 Until height
				For j = 0 Until width
					_pixels[k] = color
					k += 1
				Next
				k += _width - width
			Next

			_image.WritePixels(_pixels, x, y, width, height, x + y * width, _width)
		End If

		_Invalidate()
	End Method

	Method _WritePixels:Void(x:Int, y:Int, width:Int, height:Int, pixels:Int[])
		x += _scroll.x
		y += _scroll.y

		If ( Not _withPixelsArray) Then
			_image.WritePixels(pixels, x, y, width, height)
		Else
			Local offset:Int = x + y * width
			Local i:Int, j:Int, index:Int, k:Int = offset

			For i = 0 Until height
				For j = 0 Until width
					_pixels[k] = pixels[index]
					k += 1
					index += 1
				Next
				k += _width - width
			Next

			_image.WritePixels(_pixels, x, y, width, height, offset, _width)
		End If

		_Invalidate()
	End Method

	Method _Invalidate:Void()
		_destImage = Null
		_dirty = True
	End Method

End Class

Strict

Import mojo.graphics
Import flixel.flxpoint
Import flixel.flxrect
Import flixel.system.flxcolor

Class FlxBitmapData

Private
	Global _ZeroPoint:FlxPoint = New FlxPoint()

	Field _width:Int

	Field _height:Int

	Field _scroll:FlxPoint

	Field _padding:FlxPoint

	Field _storePixels:Bool

	Field _image:Image

	Field _grabbedImage:Image

	Field _sourceImage:Image

	Field _color:FlxColor

	Field _rect:FlxRect

	Field _pixels:Int[]

Public
	Method New(width:Int, height:Int, storePixels:Bool = False, fillColor:Int = $00000000)
		_image = CreateImage(width, height)
		_color = New FlxColor(fillColor)
		_rect = New FlxRect()

		_width = width
		_height = height
		_scroll = New FlxPoint(0, 0)
		_padding = New FlxPoint(0, 0)
		_storePixels = storePixels

		If (_storePixels) _pixels = New Int[_width * _height]

		If (_color.a > 0) Then
			If ( Not _storePixels) _pixels = New Int[_width * _height]
			_WritePixels(0, 0, _width, _height, fillColor)
		End If
	End Method

	Method Destroy:Void(discard:Bool = False)
		_pixels =[]
		_color = Null
		_rect = Null
		_scroll = Null
		_padding = Null

		If (discard) _image.Discard()
		If (_sourceImage <> Null) _sourceImage.Discard()

		_image = Null
		_sourceImage = Null
		_grabbedImage = Null
	End Method

	Method CopyPixels:Void(sourceBitmapData:FlxBitmapData, sourceRect:FlxRect = Null, destPoint:FlxPoint = Null)
		If (sourceRect = Null) sourceRect = New FlxRect(0, 0, Min(_width - Int(_scroll.x), sourceBitmapData._width), Min(_height - Int(_scroll.y), sourceBitmapData._height))
		If (destPoint = Null) destPoint = _ZeroPoint

		If (sourceBitmapData._storePixels) Then
			SetPixels(_rect.Make(destPoint.x, destPoint.y, sourceRect.width, sourceRect.height), sourceBitmapData.GetPixels(sourceRect))
		Else
			Cls()
				DrawImage(sourceBitmapData._image, 0, 0)
				_GrabPixels(sourceRect.x, sourceRect.y, sourceRect.width, sourceRect.height, destPoint.x, destPoint.y)
			Cls()
		End If
	End Method

	Method CopyPixels:Void(sourceImage:Image, sourceRect:FlxRect = Null, destPoint:FlxPoint = Null)
		If (sourceRect = Null) Then
			If (sourceImage.Frames() = 1) Then
				sourceRect = _rect.Make(0, 0, Min(_width - Int(_scroll.x), sourceImage.Width()), Min(_height - Int(_scroll.y), sourceImage.Height()))
			Else
				sourceRect = _rect.Make(0, 0, _width - Int(_scroll.x), _height - Int(_scroll.y))
			 End If
		End If

		If (destPoint = Null) destPoint = _ZeroPoint

		Cls()
			_DrawAsSpriteSheet(sourceImage, _padding.x, _padding.y, True)
			_GrabPixels(sourceRect.x, sourceRect.y, sourceRect.width, sourceRect.height, destPoint.x, destPoint.y)
		Cls()
	End Method

	Method CopyPixels:Void(sourceRect:FlxRect = Null, destPoint:FlxPoint = Null)
		If (sourceRect = Null) sourceRect = _rect.Make(0, 0, Min(_width - Int(_scroll.x), DeviceWidth()), Min(_height - Int(_scroll.y), DeviceHeight()))
		If (destPoint = Null) destPoint = _ZeroPoint

		_GrabPixels(sourceRect.x, sourceRect.y, sourceRect.width, sourceRect.height, destPoint.x, destPoint.y)
	End Method

	Method Dispose:Void()
		_pixels =[]
		_storePixels = False
		If (_sourceImage <> Null) _sourceImage.Discard()
	End Method

	Method FillRect:Void(rect:FlxRect, color:Int)
		_WritePixels(rect.x, rect.y, rect.width, rect.height, color)
	End Method

	Method FloodFill:Void(x:Int, y:Int, color:Int)
		FillRect(_rect.Make(x, y, _width - x, _height - y), color)
	End Method

	Method GetPixel:Int(x:Float, y:Float)
		If (_storePixels) Then
			Return _pixels[x + y * _width]
		End If

		Return 0
	End Method

	Method GetPixels:Int[] (rect:FlxRect)
		Local result:Int[] = New Int[rect.width * rect.height]

		If (_storePixels) Then
			Local i:Int, j:Int, k:Int = rect.x + rect.y * _width, index:Int

			For i = 0 Until rect.height
				For j = 0 Until rect.width
					result[index] = _pixels[k]
					k += 1
					index += 1
				Next
				k += _width - rect.width
			Next
		End If

		Return result
	End Method

	Method Scroll:Void(x:Int, y:Int)
		_scroll.Make(x, y)
	End Method

	Method SetPixel:Void(x:Int, y:Float, color:Int)
		FillRect(_rect.Make(x, y, 1, 1), color)
	End Method

	Method SetPixels:Void(rect:FlxRect, pixels:Int[])
		_WritePixels(rect.x, rect.y, rect.width, rect.height, pixels)
	End Method

	Method DrawAsSpriteSheet:Void()
		_DrawAsSpriteSheet(_image, _padding.x, padding.y, True)
	End Method

	Method Width:Int() Property
		Return _width
	End Method

	Method Height:Int() Property
		Return _height
	End Method

	Method Image:Image() Property
		If (_sourceImage <> Null) Then
			If (_grabbedImage <> Null) Return _grabbedImage

			Local flags:Int

			If (_padding.x = 1) flags |= graphics.Image.XPadding
			If (_padding.y = 1) flags |= graphics.Image.YPadding

			_grabbedImage = _image.GrabImage(0, 0, _sourceImage.Width() +_padding.x * 2, _sourceImage.Height() +_padding.y * 2, _sourceImage.Frames(), flags)
			_grabbedImage.SetHandle(_sourceImage.HandleX(), _sourceImage.HandleY())

			Return _grabbedImage
		End If

		Return _image
	End Method

	Function FromImage:FlxBitmapData(image:Image, storePixels:Bool = False, paddingX:Int = 0, paddingY:Int)
		Return _FromImage(image, storePixels, paddingX, paddingY)
	End Function

	Function FromImage:FlxBitmapData(image:Image, storePixels:Bool = False, paddings:Int = 0)
		Local paddingX:Int, paddingY:Int

		If (paddings & graphics.Image.XPadding) paddingX = 1
		If (paddings & graphics.Image.YPadding) paddingY = 1

		Return _FromImage(image, storePixels, paddingX, paddingY)
	End Function

	Function FromImage:FlxBitmapData(image:Image, storePixels:Bool = False)
		Local paddingX:Int, paddingY:Int

		If (image.Flags() & graphics.Image.XPadding) paddingX = 1
		If (image.Flags() & graphics.Image.YPadding) paddingY = 1

		Return _FromImage(image, storePixels, paddingX, paddingY)
	End Function

Private
	Function _FromImage:FlxBitmapData(image:Image, storePixels:Bool, paddingX:Int, paddingY:Int)
		Local rows:Int = Sqrt(image.Frames()), cols:Int = image.Frames() / rows

		Local bitmapData:FlxBitmapData = New FlxBitmapData(cols * (image.Width() +paddingX * 2), rows * (image.Height() +paddingY * 2), storePixels)

		bitmapData._padding.x = paddingX
		bitmapData._padding.y = paddingY

		bitmapData.CopyPixels(image)
		bitmapData._sourceImage = image

		Return bitmapData
	End Function

	Method _DrawAsSpriteSheet:Void(image:Image, paddingX:Int = 0, paddingY:Int = 0, fillPaddings:Bool = False)
		Local x:Float = paddingX, y:Float = paddingY
		Local w:Int = image.Width(), h:Int = image.Height()
		Local hx:Int = image.HandleX(), hy:Int = image.HandleY()
		Local i:Int = 0, l:Int = image.Frames()

		image.SetHandle(0, 0)

		While (i < l)
			If (paddingX > 0 And fillPaddings) DrawImageRect(image, x - paddingX, y, 0, 0, paddingX, h, i)
			If (paddingY > 0 And fillPaddings) DrawImageRect(image, x, y - paddingY, 0, 0, w, paddingY, i)

			DrawImage(image, x, y, i)

			If (paddingX > 0 And fillPaddings) DrawImageRect(image, x + w, y, w - paddingX, 0, paddingX, h, i)
			If (paddingY > 0 And fillPaddings) DrawImageRect(image, x, y + h, 0, h - paddingY, w, paddingY, i)

			x += w + paddingX * 2

			If (x + w + paddingX * 2 > _width + paddingX) Then
				x = paddingX
				y += h + paddingY * 2

				If (y + h + paddingY * 2 > _height + paddingY) Then
					Exit
				End If
			End If

			i += 1
		Wend

		image.SetHandle(hx, hy)
	End Method

	Method _CheckPixelsArray:Void(width:Int, height:Int)
		If (_pixels.Length() < width * height) Then
			_pixels = _pixels.Resize(width * height)
		End If
	End Method

	Method _GrabPixels:Void(x:Int, y:Int, width:Int, height:Int, destX:Int, destY:Int)
		destX += _scroll.x
		destY += _scroll.y

		Local offset:Int = destX + destY * width

		If ( Not _storePixels) Then
			_CheckPixelsArray(width, height)
			ReadPixels(_pixels, x, y, width, height)
			_image.WritePixels(_pixels, destX, destY, width, height)
		Else
			ReadPixels(_pixels, x, y, width, height, offset, _width)
			_image.WritePixels(_pixels, destX, destY, width, height, offset, _width)
		End If

		_grabbedImage = Null
	End Method

	Method _WritePixels:Void(x:Int, y:Int, width:Int, height:Int, color:Int)
		x += _scroll.x
		y += _scroll.y

		If ( Not _storePixels) Then
			Local i:Int = 0, l:Int = width * height
			_CheckPixelsArray(width, height)

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

			_image.WritePixels(_pixels, x, y, width, height)
		Else
			Local i:Int, j:Int, k:Int = x + y * width

			For i = 0 Until height
				For j = 0 Until width
					_pixels[k] = color
					k += 1
				Next
				k += _width - width
			Next

			_image.WritePixels(_pixels, x, y, width, height, x + y * width, _width)
		End If

		_grabbedImage = Null
	End Method

	Method _WritePixels:Void(x:Int, y:Int, width:Int, height:Int, pixels:Int[])
		x += _scroll.x
		y += _scroll.y

		If ( Not _storePixels) Then
			_image.WritePixels(pixels, x, y, width, height)
		Else
			Local offset:Int = x + y * width
			Local i:Int, j:Int, index:Int, k:Int = offset

			For i = 0 Until height
				For j = 0 Until width
					_pixels[k] = pixels[index]
					k += 1
					index += 1
				Next
				k += _width - width
			Next

			_image.WritePixels(_pixels, x, y, width, height, offset, _width)
		End If

		_grabbedImage = Null
	End Method

End Class


Fixed 'Read' in 'SpecializedChainStream'.

#Rem
	THIS MODULE IS CURRENTLY EXPERIMENTAL; USE AT YOUR OWN RISK.
#End

Strict

Public

' Imports (Public):
Import brl.stream

' Imports (Private):
Private

Import byteorder

Import brl.databuffer

Public

' Classes:
Class ChainStream Extends SpecializedChainStream<Stream> Final
	' Constructor(s):
	Method New(BigEndian:Bool=Default_BigEndian, CloseRights:Bool=True, Link:Int=0)
		Super.New(BigEndian, CloseRights, Link)
	End

	Method New(Streams:Stream[], BigEndian:Bool=Default_BigEndian, CloseRights:Bool=True, Link:Int=0)
		Super.New(Streams, BigEndian, CloseRights, Link)
	End

	Method New(Streams:Stack<StreamType>, BigEndian:Bool=Default_BigEndian, CloseRights:Bool=True, Link:Int=0)
		Super.New(Streams, BigEndian, CloseRights, Link)
	End
End

Class SpecializedChainStream<StreamType> Extends Stream
	' Constant variable(s):

	' Defaults:

	' Booleans / Flags:
	Const Default_BigEndian:Bool = False

	' Constructor(s) (Public):
	Method New(BigEndian:Bool=Default_BigEndian, CloseRights:Bool=True, Link:Int=0)
		Construct(New Stack<StreamType>(), BigEndian, CloseRights, Link)
	End

	' All containers passed to these constructors should be assumed to be under this object's control:
	Method New(Streams:StreamType[], BigEndian:Bool=Default_BigEndian, CloseRights:Bool=True, Link:Int=0)
		Construct(New Stack<StreamType>(Streams), BigEndian, CloseRights, Link)
	End

	Method New(Streams:Stack<StreamType>, BigEndian:Bool=Default_BigEndian, CloseRights:Bool=True, Link:Int=0)
		Construct(Streams, BigEndian, CloseRights, Link)
	End

	' Constructor(s) (Protected):
	Protected

	Method Construct:Void(Streams:Stack<StreamType>, BigEndian:Bool=Default_BigEndian, CloseRights:Bool=True, Link:Int=0)
		Self.Chain = Streams
		Self.Link = Link

		Self.BigEndian = BigEndian
		Self.CanCloseStreams = CloseRights

		Return
	End

	Public

	' Destructor(s):
	Method Close:Void()
		If (CanCloseStreams) Then
			For Local Node:= Eachin Chain
				Node.Close()
			Next
		Endif

		' Empty the stream-chain.
		Chain.Clear()

		Return
	End

	' Methods (Public):
	Method ObjectEnumerator:stack.Enumerator<StreamType>()
		Return Chain.ObjectEnumerator()
	End

	' This is pretty bloated, but it works:
	Method Seek:Int(Position:Int)
		Local Target:Int = -1
		Local BackwardOffset:Int = 0

		For Local I:= FinalChainIndex To 0 Step -1
			Local CL:= ChainLength(I)

			If (Position >= CL) Then
				Target = I
				BackwardOffset = CL
			Else
				Chain.Get(I).Seek(0)
			Endif
		Next

		If (Target = -1) Then
			Return Self.Position
		Endif

		Link = Target
		CurrentLink.Seek(Position-BackwardOffset)

		Return Position
	End

	Method ReadShort:Int()
		If (BigEndian) Then
			Return NToHS(Super.ReadShort())
		Endif

		Return Super.ReadShort()
	End

	Method ReadInt:Int()
		If (BigEndian) Then
			Return NToHL(Super.ReadInt())
		Endif

		Return Super.ReadInt()
	End

	Method ReadFloat:Float()
		If (BigEndian) Then
			Return NToHF(Super.ReadInt())
		Endif

		Return Super.ReadFloat()
	End

	Method WriteShort:Void(Value:Int)
		If (BigEndian) Then
			Super.WriteShort(HToNS(Value))
		Else
			Super.WriteShort(Value)
		Endif

		Return
	End

	Method WriteInt:Void(Value:Int)
		If (BigEndian) Then
			Super.WriteInt(HToNL(Value))
		Else
			Super.WriteInt(Value)
		Endif

		Return
	End

	Method WriteFloat:Void(Value:Float)
		If (BigEndian) Then
			Super.WriteInt(HToNF(Value))
		Else
			Super.WriteFloat(Value)
		Endif

		Return
	End

	Method Read:Int(Buffer:DataBuffer, Offset:Int, Count:Int)
		Local BytesRead:= CurrentLink.Read(Buffer, Offset, Count)

		If (Not OnFinalLink And BytesRead < Count) Then
			Link += 1

			Return (BytesRead + Read(Buffer, Offset+BytesRead, (Count-BytesRead)))
		Endif

		Return BytesRead
	End

	Method Write:Int(Buffer:DataBuffer, Offset:Int, Count:Int)
		Local BytesWritten:= CurrentLink.Write(Buffer, Offset, Count)

		If (Not OnFinalLink And BytesWritten < Count) Then
			Link += 1

			Return (BytesWritten + Write(Buffer, Offset+BytesWritten, (Count-BytesWritten)))
		Endif

		Return BytesWritten
	End

	' Methods (Protected):
	Protected

	' The length of the chain as-of the link specified.
	Method ChainLength:Int(LinkPosition:Int)
		If (LinkPosition < 0 Or LinkPosition > LinkCount) Then
			Return 0
		Endif

		Local P:Int = 0

		For Local I:= 0 Until LinkPosition
			' Add the length of the previous link in the chain.
			P += Chain.Get(I).Length
		Next

		Return (P + Chain.Get(LinkPosition).Position)
	End

	Public

	' Properties (Public):

	' The active element of 'Chain';
	' the stream currently used for I/O.
	Method Link:Int() Property
		Return Self._Link
	End

	' This specifies if we are at the end of the stream.
	' This uses the final chain as a reference, as normal operations
	' will automatically move through each link in the chain.
	Method Eof:Int() Property
		'Return CurrentLink.Eof
		Return FinalLink.Eof
	End

	' The overall length of this stream. (Bytes contained)
	Method Length:Int() Property
		Local L:Int = 0

		For Local Node:= Eachin Chain
			L += Node.Length
		Next

		Return L
	End

	' The current "virtual" position in the stream;
	' functions like a normal stream, use as you would normally.
	Method Position:Int() Property
		' Add the previous links' lengths to the current link's position.
		Return (ChainLength(Link))
	End

	' A public "accessor" for the internal "chain".
	' Mutation may result in undefined behavior; use at your own risk.
	Method Links:Stack<StreamType>() Property
		Return Chain
	End

	' The number of links in the internal "chain".
	Method LinkCount:Int() Property
		Return Chain.Length
	End

	' This specifies if we are currently
	' using the final link in the chain.
	Method OnFinalLink:Bool() Property
		Return (Link = FinalChainIndex)
	End

	' Properties (Protected):
	Protected

	' This acts as the internal mutation property for '_Link'.
	Method Link:Void(Input:Int) Property
		Self._Link = Input

		Return
	End

	' The final chain-index (Link) in the chain.
	Method FinalChainIndex:Int() Property
		Return Max(LinkCount-1, 0)
	End

	' The current stream-link in the chain. (Use at your own risk)
	Method CurrentLink:StreamType() Property
		Return Chain.Get(Link)
	End

	' The final stream in the "chain". (Use at your own risk)
	Method FinalLink:StreamType() Property
		Return Chain.Get(FinalChainIndex)
	End

	Public

	' Fields (Protected):
	Protected

	' A "chain" of streams representing
	' the data this stream delegates.
	Field Chain:Stack<StreamType>

	' See the 'Link' property for details.
	Field _Link:Int

	' Booleans / Flags:

	' This specifies if big-endian storage should be used/expected.
	Field BigEndian:Bool

	' This specifies if this object has the right to
	' close the elements of the internal "chain".
	Field CanCloseStreams:Bool = True

	Public
End

#Rem
	THIS MODULE IS CURRENTLY EXPERIMENTAL; USE AT YOUR OWN RISK.
#End

Strict

Public

' Imports (Public):
Import brl.stream

' Imports (Private):
Private

Import byteorder

Import brl.databuffer

Public

' Classes:
Class ChainStream Extends SpecializedChainStream<Stream> Final
	' Constructor(s):
	Method New(BigEndian:Bool=Default_BigEndian, CloseRights:Bool=True, Link:Int=0)
		Super.New(BigEndian, CloseRights, Link)
	End

	Method New(Streams:Stream[], BigEndian:Bool=Default_BigEndian, CloseRights:Bool=True, Link:Int=0)
		Super.New(Streams, BigEndian, CloseRights, Link)
	End

	Method New(Streams:Stack<StreamType>, BigEndian:Bool=Default_BigEndian, CloseRights:Bool=True, Link:Int=0)
		Super.New(Streams, BigEndian, CloseRights, Link)
	End
End

Class SpecializedChainStream<StreamType> Extends Stream
	' Constant variable(s):

	' Defaults:

	' Booleans / Flags:
	Const Default_BigEndian:Bool = False

	' Constructor(s) (Public):
	Method New(BigEndian:Bool=Default_BigEndian, CloseRights:Bool=True, Link:Int=0)
		Construct(New Stack<StreamType>(), BigEndian, CloseRights, Link)
	End

	' All containers passed to these constructors should be assumed to be under this object's control:
	Method New(Streams:StreamType[], BigEndian:Bool=Default_BigEndian, CloseRights:Bool=True, Link:Int=0)
		Construct(New Stack<StreamType>(Streams), BigEndian, CloseRights, Link)
	End

	Method New(Streams:Stack<StreamType>, BigEndian:Bool=Default_BigEndian, CloseRights:Bool=True, Link:Int=0)
		Construct(Streams, BigEndian, CloseRights, Link)
	End

	' Constructor(s) (Protected):
	Protected

	Method Construct:Void(Streams:Stack<StreamType>, BigEndian:Bool=Default_BigEndian, CloseRights:Bool=True, Link:Int=0)
		Self.Chain = Streams
		Self.Link = Link

		Self.BigEndian = BigEndian
		Self.CanCloseStreams = CloseRights

		Return
	End

	Public

	' Destructor(s):
	Method Close:Void()
		If (CanCloseStreams) Then
			For Local Node:= Eachin Chain
				Node.Close()
			Next
		Endif

		' Empty the stream-chain.
		Chain.Clear()

		Return
	End

	' Methods (Public):
	Method ObjectEnumerator:stack.Enumerator<StreamType>()
		Return Chain.ObjectEnumerator()
	End

	' This is pretty bloated, but it works:
	Method Seek:Int(Position:Int)
		Local Target:Int = -1
		Local BackwardOffset:Int = 0

		For Local I:= FinalChainIndex To 0 Step -1
			Local CL:= ChainLength(I)

			If (Position >= CL) Then
				Target = I
				BackwardOffset = CL
			Else
				Chain.Get(I).Seek(0)
			Endif
		Next

		If (Target = -1) Then
			Return Self.Position
		Endif

		Link = Target
		CurrentLink.Seek(Position-BackwardOffset)

		Return Position
	End

	Method ReadShort:Int()
		If (BigEndian) Then
			Return NToHS(Super.ReadShort())
		Endif

		Return Super.ReadShort()
	End

	Method ReadInt:Int()
		If (BigEndian) Then
			Return NToHL(Super.ReadInt())
		Endif

		Return Super.ReadInt()
	End

	Method ReadFloat:Float()
		If (BigEndian) Then
			Return NToHF(Super.ReadInt())
		Endif

		Return Super.ReadFloat()
	End

	Method WriteShort:Void(Value:Int)
		If (BigEndian) Then
			Super.WriteShort(HToNS(Value))
		Else
			Super.WriteShort(Value)
		Endif

		Return
	End

	Method WriteInt:Void(Value:Int)
		If (BigEndian) Then
			Super.WriteInt(HToNL(Value))
		Else
			Super.WriteInt(Value)
		Endif

		Return
	End

	Method WriteFloat:Void(Value:Float)
		If (BigEndian) Then
			Super.WriteInt(HToNF(Value))
		Else
			Super.WriteFloat(Value)
		Endif

		Return
	End

	Method Read:Int(Buffer:DataBuffer, Offset:Int, Count:Int)
		Local BytesRead:= CurrentLink.Read(Buffer, Offset, Count)

		If (BytesRead < Count) Then
			If (OnFinalLink) Then
				Return 0 ' -1
			Endif

			Link += 1

			Return (BytesRead + Read(Buffer, Offset+BytesRead, (Count-BytesRead)))
		Endif

		Return BytesRead
	End

	Method Write:Int(Buffer:DataBuffer, Offset:Int, Count:Int)
		Local BytesWritten:= CurrentLink.Write(Buffer, Offset, Count)

		If (Not OnFinalLink And BytesWritten < Count) Then
			Link += 1

			Return (BytesWritten + Write(Buffer, Offset+BytesWritten, (Count-BytesWritten)))
		Endif

		Return BytesWritten
	End

	' Methods (Protected):
	Protected

	' The length of the chain as-of the link specified.
	Method ChainLength:Int(LinkPosition:Int)
		If (LinkPosition < 0 Or LinkPosition > LinkCount) Then
			Return 0
		Endif

		Local P:Int = 0

		For Local I:= 0 Until LinkPosition
			' Add the length of the previous link in the chain.
			P += Chain.Get(I).Length
		Next

		Return (P + Chain.Get(LinkPosition).Position)
	End

	Public

	' Properties (Public):

	' The active element of 'Chain';
	' the stream currently used for I/O.
	Method Link:Int() Property
		Return Self._Link
	End

	' This specifies if we are at the end of the stream.
	' This uses the final chain as a reference, as normal operations
	' will automatically move through each link in the chain.
	Method Eof:Int() Property
		'Return CurrentLink.Eof
		Return FinalLink.Eof
	End

	' The overall length of this stream. (Bytes contained)
	Method Length:Int() Property
		Local L:Int = 0

		For Local Node:= Eachin Chain
			L += Node.Length
		Next

		Return L
	End

	' The current "virtual" position in the stream;
	' functions like a normal stream, use as you would normally.
	Method Position:Int() Property
		' Add the previous links' lengths to the current link's position.
		Return (ChainLength(Link))
	End

	' A public "accessor" for the internal "chain".
	' Mutation may result in undefined behavior; use at your own risk.
	Method Links:Stack<StreamType>() Property
		Return Chain
	End

	' The number of links in the internal "chain".
	Method LinkCount:Int() Property
		Return Chain.Length
	End

	' This specifies if we are currently
	' using the final link in the chain.
	Method OnFinalLink:Bool() Property
		Return (Link = FinalChainIndex)
	End

	' Properties (Protected):
	Protected

	' This acts as the internal mutation property for '_Link'.
	Method Link:Void(Input:Int) Property
		Self._Link = Input

		Return
	End

	' The final chain-index (Link) in the chain.
	Method FinalChainIndex:Int() Property
		Return Max(LinkCount-1, 0)
	End

	' The current stream-link in the chain. (Use at your own risk)
	Method CurrentLink:StreamType() Property
		Return Chain.Get(Link)
	End

	' The final stream in the "chain". (Use at your own risk)
	Method FinalLink:StreamType() Property
		Return Chain.Get(FinalChainIndex)
	End

	Public

	' Fields (Protected):
	Protected

	' A "chain" of streams representing
	' the data this stream delegates.
	Field Chain:Stack<StreamType>

	' See the 'Link' property for details.
	Field _Link:Int

	' Booleans / Flags:

	' This specifies if big-endian storage should be used/expected.
	Field BigEndian:Bool

	' This specifies if this object has the right to
	' close the elements of the internal "chain".
	Field CanCloseStreams:Bool = True

	Public
End


Fixed carriage return handling

Fixed carriage return handling

Strict

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

Private

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

Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_8_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_8_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_9_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_9_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_10_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_10_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_11_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_11_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_12_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_12_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_13_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_13_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_14_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_14_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_15_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_15_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_16_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_16_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_17_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_17_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_18_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_18_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_19_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_19_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_20_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_20_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_21_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_21_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_22_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_22_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_23_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_23_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_24_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_24_flx.${FLX_FONT_EXTENSION}"

Public

Class FlxText Extends FlxSprite Implements FlxSpriteRenderer

	Global __CLASS__:Object

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

	Const SYSTEM_FONT:String = "system"

Private
	Global _FontsManager:FlxResourcesManager<FlxBitmapFont> = New FlxResourcesManager<FlxBitmapFont>()

	Field _shadow:FlxColor

	Field _value:String

	Field _lines:FlxTextLine[]

	Field _countLines:Int

	Field _alignment:Float

	Field _fontFamily:String

	Field _fontSize:Int

	Field _fontHeight:Int

	Field _fontObject:FlxBitmapFont

	Field _fontShadowEnabled:Bool

	Field _fontBorderEnabled:Bool

	Field _isEmpty:Bool

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

		_fontShadowEnabled = False
		_fontBorderEnabled = False

		Self.width = width
		SetRenderer(Self)

		_shadow = New FlxColor(0)
		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 SetFontShadowEnabled:Void(enabled:Bool)
		_fontShadowEnabled = enabled
	End Method

	Method SetFontBoderEnabled:Void(enabled:Bool)
		_fontBorderEnabled = enabled
	End Method

	Method OnSpriteBind:Void(sprite:FlxSprite)
		Pixels = Null
	End Method

	Method OnSpriteUnbind:Void()
	End Method

	Method OnSpriteRender:Void(x:Float, y:Float)
		If (_isEmpty) Return

		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

	Method GetTextWidth:Float()
		Return _fontObject.GetTextWidth(Self)
	End Method

	Method GetTextHeight:Float()
		Return height
	End Method

	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
			_isEmpty = False
		Else
			Self.height = 0
			frameHeight = 0
			_isEmpty = True
		End If

		Super.ResetHelpers()
	End Method

Private

	Method _ResetFont:Void()
		_fontObject = _FontsManager.GetResource(_fontFamily + _fontSize, New FontResource(_fontFamily, _fontSize))
		_fontHeight = _fontObject.GetFontHeight(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 _fontObject.GetTextHeight(Self)
		End If
	End Method

	Method _ParseText:Void()
		_countLines = 0

		Local prevOffset:Int = 0
		Local offset:Int = -1

		Local i:Int = 0, l:Int = _value.Length()

		While (i < l)
			If (_value[i] = 10 Or _value[i] = KEY_ENTER) Then
				offset = i
				If (_value[i] = KEY_ENTER) offset += 1
				Exit
			End If

			i += 1
		Wend

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

				prevOffset = offset + 1

				i = prevOffset
				offset = -1

				While (i < l)
					If (_value[i] = 10 Or _value[i] = KEY_ENTER) Then
						offset = i
						If (_value[i] = KEY_ENTER) offset += 1
						Exit
					End If

					i += 1
				Wend
			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
				If (range >= textLength) Then
					range = textLength + 1
					Exit
				End If
				textWidth = _fontObject.GetTextWidth(Self, startPos, startPos + range)
			Until (textWidth >= width)

			Local maxOffset:Int = startPos + range
			Local minOffset:Int = startPos
			Local offset:Int = maxOffset
			Local tmpOffset:Int = 0
			Local dirty:Bool = False
			Local finalTextWidth:Int = 0
			Local success:Bool

			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
						success = False

						If (_value[i] = KEY_SPACE Or _value[i] = KEY_TAB) Then
							tmpOffset = i
							success = True
							Exit
						End If
					Next

					If (tmpOffset < 0) Then
						tmpOffset = _GetMinOffset(minOffset, offset)
					Else
						If (_value[minOffset] = KEY_SPACE Or _value[minOffset] = KEY_TAB) Then
							For Local i:Int = minOffset To offset
								If (_value[i] <> KEY_SPACE And _value[i] <> KEY_TAB) Then
									minOffset = i
									Exit
								End If
							Next
						End If
					End If

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

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

				If (finalTextWidth > width And offset - 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
					If (success) minOffset += 1

					maxOffset = Min(minOffset + range, maxOffset)
					offset = maxOffset
				Else
					Local l:Int = endPos

					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 (l - minOffset <= 0) Exit

					If ( Not dirty) Then
						_AddLine(minOffset, l, finalTextWidth)
					Else
						_AddLine(minOffset, l, _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, startPos, startPos + offset) > width)
			offset -= 1
			If (offset = 1) Return offset
		Wend

		Return startPos + 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

Class FontResource Extends FlxResource<FlxBitmapFont>

	Field size:Int

	Field font:FlxBitmapFont

	Method New(fontFamily:String, fontSize:Int)
		Super.New(fontFamily)
		Self.size = fontSize
	End Method

	Method Load:FlxBitmapFont()
		font = New FlxBitmapFont(FlxAssetsManager.GetFont(name).GetPath(size))
		Return font
	End Method

	Method Use:FlxBitmapFont()
		Return font
	End Method

	Method Discard:Void()
		font.Discard()
		font = Null
	End Method

End Class

#If FLX_TEXT_DRIVER = "angelfont"
	Class FlxBitmapFont
	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 New(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 Discard:Void()
			For Local i:Image = EachIn image
				i.Discard()
			Next
		End Method

		Method GetTextWidth:Float(txt:FlxText, startPos:Int = 0, endPos:Int = -1)
			If (startPos = endPos) Return 0

			Local prevChar:Int = 0
			Local width:Float = 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

						prevChar = asc
					EndIf

					width += ac.xAdvance
				EndIf
			Next

			Return width
		End Method

		Method GetFontHeight:Int(txt:FlxText)
			Local h:Int = 0

			If (txt._value.Length() <> 0) Then
				Local l:Int = txt._value.Length()

				For Local i:= 0 Until l
					Local asc:Int = txt._value[i]
					Local ac:Char = chars[asc]
					If ac <> Null And 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 GetTextHeight:Int(txt:FlxText)
			Return ( (txt._fontHeight + lineGap) * txt._countLines) - lineGap
		End Method

		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 = y
			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 = x + line.xOffset

				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

							prevChar = asc
						Endif

						ac.Draw(image[ac.page], xOffset, yOffset)
						xOffset += ac.xAdvance
					Endif

					i += 1
				Wend

				lineIndex += 1
				yOffset += lineHeight
			Wend
		End Method

	End Class

#ElseIf FLX_TEXT_DRIVER = "fontmachine"

	Class FlxBitmapFont

		Method New(fontDescriptionFilePath:String)
			Local text:String = LoadString(fontDescriptionFilePath + ".txt")
			If text = "" Then Print "FONT " + fontDescriptionFilePath + " WAS NOT FOUND!!!"

			_kerning = New drawingpoint.DrawingPoint
			LoadFontData(text, fontDescriptionFilePath, False)
		End

		Method Discard:Void()
			For Local b:BitMapChar = EachIn borderChars
				b.UnloadCharImage()
			Next

			For Local b:BitMapChar = EachIn faceChars
				b.UnloadCharImage()
			Next

			For Local b:BitMapChar = EachIn shadowChars
				b.UnloadCharImage()
			Next

			For Local i:Image = EachIn packedImages
				i.Discard()
			Next
		End Method

		Method GetTextWidth:Float(text:FlxText, fromChar:Int = 0, toChar:Int = -1)
			If (fromChar = toChar) Return 0

			Local twidth:Float
			Local char:Int
			Local lastchar:Int = 0

			If (toChar < 0) toChar = text._value.Length()

			For Local i:Int = fromChar Until toChar
				char = text._value[i]

				If faceChars[char] <> Null Then
					lastchar = char
					twidth = twidth + faceChars[char].drawingMetrics.drawingWidth + _kerning.x
				End If
			Next

			Return twidth - faceChars[lastchar].drawingMetrics.drawingWidth + faceChars[lastchar].drawingMetrics.drawingSize.x
		End Method

		Method GetTextHeight:Float(text:FlxText)
			Return ( (text._fontHeight + _kerning.y) * text._countLines) - _kerning.y
		End

		Method GetFontHeight:Int(txt:FlxText)
			If faceChars[32] = Null Then Return 0
			Return faceChars[32].drawingMetrics.drawingSize.y
		End Method

		Method DrawText:Void(text:FlxText, x:Float, y:Float)
			If (text._fontShadowEnabled) DrawChars(text, x, y, shadowChars)
			If (text._fontBorderEnabled) DrawChars(text, x, y, borderChars)
			DrawChars(text, x, y, faceChars)
		End

	Private
		Field borderChars:BitMapChar[]
		Field faceChars:BitMapChar[]
		Field shadowChars:BitMapChar[]

		Method LoadFontData:Void(Info:String, fontName:String, dynamicLoad:bool)
			if Info.StartsWith("P1") Then
				LoadPacked(Info,fontName,dynamicLoad)
				return
			EndIf
			Local tokenStream:String[] = Info.Split(",")
			local index:Int = 0
			borderChars = New BitMapChar[65536]
			faceChars = New BitMapChar[65536]
			shadowChars = New BitMapChar[65536]

			Local prefixName:String = fontName
			if prefixName.ToLower().EndsWith(".txt") Then prefixName = prefixName[..-4]

			Local char:Int = 0
			While index < tokenStream.Length
				Local strChar:String = tokenStream[index]
				If strChar.Trim() = "" Then
					index += 1
					Exit
				endif
				char = int(strChar)
				index += 1

				Local kind:String = tokenStream[index]
				index += 1

				Select kind
					Case "{BR"
						index += 3
						borderChars[char] = New BitMapChar
						borderChars[char].drawingMetrics.drawingOffset.x = Int(tokenStream[index])
						borderChars[char].drawingMetrics.drawingOffset.y = Int(tokenStream[index+1])
						borderChars[char].drawingMetrics.drawingSize.x = Int(tokenStream[index+2])
						borderChars[char].drawingMetrics.drawingSize.y = Int(tokenStream[index+3])
						borderChars[char].drawingMetrics.drawingWidth = Int(tokenStream[index+4])
						if dynamicLoad  = False then
							borderChars[char].image = LoadImage(prefixName + "_BORDER_" + char + ".png")
							borderChars[char].image.SetHandle(-borderChars[char].drawingMetrics.drawingOffset.x,-borderChars[char].drawingMetrics.drawingOffset.y)
						Else
							borderChars[char].SetImageResourceName  prefixName + "_BORDER_" + char + ".png"
						endif
						index += 5
						index += 1

					Case "{SH"
						index += 3
						shadowChars[char] = New BitMapChar
						shadowChars[char].drawingMetrics.drawingOffset.x = Int(tokenStream[index])
						shadowChars[char].drawingMetrics.drawingOffset.y = Int(tokenStream[index+1])
						shadowChars[char].drawingMetrics.drawingSize.x = Int(tokenStream[index+2])
						shadowChars[char].drawingMetrics.drawingSize.y = Int(tokenStream[index+3])
						shadowChars[char].drawingMetrics.drawingWidth = Int(tokenStream[index+4])
						Local filename:String = prefixName + "_SHADOW_" + char + ".png"
						if dynamicLoad  = False then
							shadowChars[char].image = LoadImage(filename)
							shadowChars[char].image.SetHandle(-shadowChars[char].drawingMetrics.drawingOffset.x,-shadowChars[char].drawingMetrics.drawingOffset.y)
						Else
							shadowChars[char].SetImageResourceName  filename
						endif

						index+=5
						index += 1

					Case "{FC"
						index += 3
						faceChars[char] = New BitMapChar
						faceChars[char].drawingMetrics.drawingOffset.x = Int(tokenStream[index])
						faceChars[char].drawingMetrics.drawingOffset.y = Int(tokenStream[index+1])
						faceChars[char].drawingMetrics.drawingSize.x = Int(tokenStream[index+2])
						faceChars[char].drawingMetrics.drawingSize.y = Int(tokenStream[index+3])
						faceChars[char].drawingMetrics.drawingWidth = Int(tokenStream[index+4])
						if dynamicLoad = False then
							faceChars[char].image = LoadImage(prefixName + "_" + char + ".png")
							faceChars[char].image.SetHandle(-faceChars[char].drawingMetrics.drawingOffset.x,-faceChars[char].drawingMetrics.drawingOffset.y)
						Else
							faceChars[char].SetImageResourceName prefixName + "_" + char + ".png"
						endif
						index += 5
						index += 1

					Default
						Print "Error loading font! Char = " + char

				End
			Wend
			borderChars = borderChars[..char+1]
			faceChars = faceChars[..char+1]
			shadowChars = shadowChars[..char+1]
		End

		Field packedImages:Image[]

		Method LoadPacked:Void(info:String, fontName:String, dynamicLoad:bool)

			Local header:String = info[.. info.Find(",")]

			Local separator:String
			Select header
				Case "P1"
					separator = "."
				Case "P1.01"
					separator = "_P_"
			End Select
			info = info[info.Find(",")+1..]
			borderChars = New BitMapChar[65536]
			faceChars = New BitMapChar[65536]
			shadowChars = New BitMapChar[65536]
			packedImages = New Image[256]
			Local maxPacked:Int = 0
			Local maxChar:Int = 0

			Local prefixName:String = fontName
			if prefixName.ToLower().EndsWith(".txt") Then prefixName = prefixName[..-4]

			Local charList:string[] = info.Split(";")
			For local chr:String = EachIn charList

				Local chrdata:string[] = chr.Split(",")
				if chrdata.Length() <2 Then Exit
				Local char:bitmapchar.BitMapChar
				Local charIndex:Int = int(chrdata[0])
				if maxChar<charIndex Then maxChar = charIndex

				select chrdata[1]
					Case "B"
						borderChars[charIndex] = New BitMapChar
						char = borderChars[charIndex]
					Case "F"
						faceChars [charIndex] = New BitMapChar
						char = faceChars[charIndex]
					Case "S"
						shadowChars [charIndex] = New BitMapChar
						char = shadowChars[charIndex]
				End Select
				char.packedFontIndex = Int(chrdata[2])
				if packedImages[char.packedFontIndex] = null Then
					packedImages[char.packedFontIndex] = LoadImage(prefixName + separator + char.packedFontIndex +  ".png")
					if maxPacked<char.packedFontIndex Then maxPacked = char.packedFontIndex
				endif
				char.packedPosition.x = Int(chrdata[3])
				char.packedPosition.y = Int(chrdata[4])
				char.packedSize.x = Int(chrdata[5])
				char.packedSize.y = Int(chrdata[6])
				char.drawingMetrics.drawingOffset.x = Int(chrdata[8])
				char.drawingMetrics.drawingOffset.y = Int(chrdata[9])
				char.drawingMetrics.drawingSize.x = Int(chrdata[10])
				char.drawingMetrics.drawingSize.y = Int(chrdata[11])
				char.drawingMetrics.drawingWidth = Int(chrdata[12])

			Next

			borderChars = borderChars[..maxChar+1]
			faceChars = faceChars[..maxChar+1]
			shadowChars = shadowChars[..maxChar+1]
			packedImages = packedImages[..maxPacked+1]

		End

		Method DrawChars:Void(text:FlxText, x:Float, y:Float, target:BitMapChar[])
			Local lineIndex:Int = 0, countLines:Int = text._countLines, line:FlxTextLine

			Local drx:Int = x, dry:Int = y
			Local i:Int = 0, l:Int
			Local char:Int

			Local lineHeight:Int = text._fontHeight + _kerning.y
			Local targetLength:Int = target.Length()

			While (lineIndex < countLines)
				line = text._lines[lineIndex]
				i = line.startPos
				l = line.endPos
				drx = x + line.xOffset

				While (i < l)
					char = text._value[i]

					If char >= 0 And char <= targetLength And target[char] <> Null Then
						If target[char].packedFontIndex > 0 Then
								DrawImageRect(packedImages[target[char].packedFontIndex], drx + target[char].drawingMetrics.drawingOffset.x, dry + target[char].drawingMetrics.drawingOffset.y, target[char].packedPosition.x, target[char].packedPosition.y, target[char].packedSize.x, target[char].packedSize.y)
						ElseIf target[char].image <> Null Then
							DrawImage(target[char].image, drx, dry)
						EndIf

						drx += faceChars[char].drawingMetrics.drawingWidth + _kerning.x
					End If

					i += 1
				Wend

				lineIndex += 1
				dry += lineHeight
			Wend
		End Method

		Field _kerning:drawingpoint.DrawingPoint
	End
#End

Strict

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

Private

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

Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_8_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_8_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_9_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_9_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_10_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_10_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_11_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_11_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_12_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_12_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_13_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_13_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_14_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_14_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_15_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_15_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_16_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_16_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_17_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_17_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_18_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_18_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_19_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_19_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_20_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_20_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_21_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_21_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_22_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_22_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_23_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_23_flx.${FLX_FONT_EXTENSION}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_24_flx_${FLX_FONT_IMAGE_MASK}"
Import "data/fonts/${FLX_TEXT_DRIVER}/system_font_24_flx.${FLX_FONT_EXTENSION}"

Public

Class FlxText Extends FlxSprite Implements FlxSpriteRenderer

	Global __CLASS__:Object

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

	Const SYSTEM_FONT:String = "system"

Private
	Global _FontsManager:FlxResourcesManager<FlxBitmapFont> = New FlxResourcesManager<FlxBitmapFont>()

	Field _shadow:FlxColor

	Field _value:String

	Field _lines:FlxTextLine[]

	Field _countLines:Int

	Field _alignment:Float

	Field _fontFamily:String

	Field _fontSize:Int

	Field _fontHeight:Int

	Field _fontObject:FlxBitmapFont

	Field _fontShadowEnabled:Bool

	Field _fontBorderEnabled:Bool

	Field _isEmpty:Bool

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

		_fontShadowEnabled = False
		_fontBorderEnabled = False

		Self.width = width
		SetRenderer(Self)

		_shadow = New FlxColor(0)
		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 SetFontShadowEnabled:Void(enabled:Bool)
		_fontShadowEnabled = enabled
	End Method

	Method SetFontBoderEnabled:Void(enabled:Bool)
		_fontBorderEnabled = enabled
	End Method

	Method OnSpriteBind:Void(sprite:FlxSprite)
		Pixels = Null
	End Method

	Method OnSpriteUnbind:Void()
	End Method

	Method OnSpriteRender:Void(x:Float, y:Float)
		If (_isEmpty) Return

		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

	Method GetTextWidth:Float()
		Return _fontObject.GetTextWidth(Self)
	End Method

	Method GetTextHeight:Float()
		Return height
	End Method

	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
			_isEmpty = False
		Else
			Self.height = 0
			frameHeight = 0
			_isEmpty = True
		End If

		Super.ResetHelpers()
	End Method

Private

	Method _ResetFont:Void()
		_fontObject = _FontsManager.GetResource(_fontFamily + _fontSize, New FontResource(_fontFamily, _fontSize))
		_fontHeight = _fontObject.GetFontHeight(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 _fontObject.GetTextHeight(Self)
		End If
	End Method

	Method _ParseText:Void()
		_countLines = 0

		Local prevOffset:Int = 0
		Local offset:Int = -1

		Local i:Int = 0, l:Int = _value.Length()

		While (i < l)
			If (_value[i] = 10 Or _value[i] = KEY_ENTER) Then
				offset = i
				Exit
			End If

			i += 1
		Wend

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

				prevOffset = offset + 1

				i = prevOffset
				offset = -1

				While (i < l)
					If (_value[i] = 10 Or _value[i] = KEY_ENTER) Then
						offset = i
						Exit
					End If

					i += 1
				Wend
			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
				If (range >= textLength) Then
					range = textLength + 1
					Exit
				End If
				textWidth = _fontObject.GetTextWidth(Self, startPos, startPos + range)
			Until (textWidth >= width)

			Local maxOffset:Int = startPos + range
			Local minOffset:Int = startPos
			Local offset:Int = maxOffset
			Local tmpOffset:Int = 0
			Local dirty:Bool = False
			Local finalTextWidth:Int = 0
			Local success:Bool

			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
						success = False

						If (_value[i] = KEY_SPACE Or _value[i] = KEY_TAB) Then
							tmpOffset = i
							success = True
							Exit
						End If
					Next

					If (tmpOffset < 0) Then
						tmpOffset = _GetMinOffset(minOffset, offset)
					Else
						If (_value[minOffset] = KEY_SPACE Or _value[minOffset] = KEY_TAB) Then
							For Local i:Int = minOffset To offset
								If (_value[i] <> KEY_SPACE And _value[i] <> KEY_TAB) Then
									minOffset = i
									Exit
								End If
							Next
						End If
					End If

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

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

				If (finalTextWidth > width And offset - 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
					If (success) minOffset += 1

					maxOffset = Min(minOffset + range, maxOffset)
					offset = maxOffset
				Else
					Local l:Int = endPos

					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 (l - minOffset <= 0) Exit

					If ( Not dirty) Then
						_AddLine(minOffset, l, finalTextWidth)
					Else
						_AddLine(minOffset, l, _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, startPos, startPos + offset) > width)
			offset -= 1
			If (offset = 1) Return offset
		Wend

		Return startPos + 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

Class FontResource Extends FlxResource<FlxBitmapFont>

	Field size:Int

	Field font:FlxBitmapFont

	Method New(fontFamily:String, fontSize:Int)
		Super.New(fontFamily)
		Self.size = fontSize
	End Method

	Method Load:FlxBitmapFont()
		font = New FlxBitmapFont(FlxAssetsManager.GetFont(name).GetPath(size))
		Return font
	End Method

	Method Use:FlxBitmapFont()
		Return font
	End Method

	Method Discard:Void()
		font.Discard()
		font = Null
	End Method

End Class

#If FLX_TEXT_DRIVER = "angelfont"
	Class FlxBitmapFont
	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 New(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 Discard:Void()
			For Local i:Image = EachIn image
				i.Discard()
			Next
		End Method

		Method GetTextWidth:Float(txt:FlxText, startPos:Int = 0, endPos:Int = -1)
			If (startPos = endPos) Return 0

			Local prevChar:Int = 0
			Local width:Float = 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

						prevChar = asc
					EndIf

					width += ac.xAdvance
				EndIf
			Next

			Return width
		End Method

		Method GetFontHeight:Int(txt:FlxText)
			Local h:Int = 0

			If (txt._value.Length() <> 0) Then
				Local l:Int = txt._value.Length()

				For Local i:= 0 Until l
					Local asc:Int = txt._value[i]
					Local ac:Char = chars[asc]
					If ac <> Null And 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 GetTextHeight:Int(txt:FlxText)
			Return ( (txt._fontHeight + lineGap) * txt._countLines) - lineGap
		End Method

		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 = y
			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 = x + line.xOffset

				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

							prevChar = asc
						Endif

						ac.Draw(image[ac.page], xOffset, yOffset)
						xOffset += ac.xAdvance
					Endif

					i += 1
				Wend

				lineIndex += 1
				yOffset += lineHeight
			Wend
		End Method

	End Class

#ElseIf FLX_TEXT_DRIVER = "fontmachine"

	Class FlxBitmapFont

		Method New(fontDescriptionFilePath:String)
			Local text:String = LoadString(fontDescriptionFilePath + ".txt")
			If text = "" Then Print "FONT " + fontDescriptionFilePath + " WAS NOT FOUND!!!"

			_kerning = New drawingpoint.DrawingPoint
			LoadFontData(text, fontDescriptionFilePath, False)
		End

		Method Discard:Void()
			For Local b:BitMapChar = EachIn borderChars
				b.UnloadCharImage()
			Next

			For Local b:BitMapChar = EachIn faceChars
				b.UnloadCharImage()
			Next

			For Local b:BitMapChar = EachIn shadowChars
				b.UnloadCharImage()
			Next

			For Local i:Image = EachIn packedImages
				i.Discard()
			Next
		End Method

		Method GetTextWidth:Float(text:FlxText, fromChar:Int = 0, toChar:Int = -1)
			If (fromChar = toChar) Return 0

			Local twidth:Float
			Local char:Int
			Local lastchar:Int = 0

			If (toChar < 0) toChar = text._value.Length()

			For Local i:Int = fromChar Until toChar
				char = text._value[i]

				If faceChars[char] <> Null Then
					lastchar = char
					twidth = twidth + faceChars[char].drawingMetrics.drawingWidth + _kerning.x
				End If
			Next

			Return twidth - faceChars[lastchar].drawingMetrics.drawingWidth + faceChars[lastchar].drawingMetrics.drawingSize.x
		End Method

		Method GetTextHeight:Float(text:FlxText)
			Return ( (text._fontHeight + _kerning.y) * text._countLines) - _kerning.y
		End

		Method GetFontHeight:Int(txt:FlxText)
			If faceChars[32] = Null Then Return 0
			Return faceChars[32].drawingMetrics.drawingSize.y
		End Method

		Method DrawText:Void(text:FlxText, x:Float, y:Float)
			If (text._fontShadowEnabled) DrawChars(text, x, y, shadowChars)
			If (text._fontBorderEnabled) DrawChars(text, x, y, borderChars)
			DrawChars(text, x, y, faceChars)
		End

	Private
		Field borderChars:BitMapChar[]
		Field faceChars:BitMapChar[]
		Field shadowChars:BitMapChar[]

		Method LoadFontData:Void(Info:String, fontName:String, dynamicLoad:bool)
			if Info.StartsWith("P1") Then
				LoadPacked(Info,fontName,dynamicLoad)
				return
			EndIf
			Local tokenStream:String[] = Info.Split(",")
			local index:Int = 0
			borderChars = New BitMapChar[65536]
			faceChars = New BitMapChar[65536]
			shadowChars = New BitMapChar[65536]

			Local prefixName:String = fontName
			if prefixName.ToLower().EndsWith(".txt") Then prefixName = prefixName[..-4]

			Local char:Int = 0
			While index < tokenStream.Length
				Local strChar:String = tokenStream[index]
				If strChar.Trim() = "" Then
					index += 1
					Exit
				endif
				char = int(strChar)
				index += 1

				Local kind:String = tokenStream[index]
				index += 1

				Select kind
					Case "{BR"
						index += 3
						borderChars[char] = New BitMapChar
						borderChars[char].drawingMetrics.drawingOffset.x = Int(tokenStream[index])
						borderChars[char].drawingMetrics.drawingOffset.y = Int(tokenStream[index+1])
						borderChars[char].drawingMetrics.drawingSize.x = Int(tokenStream[index+2])
						borderChars[char].drawingMetrics.drawingSize.y = Int(tokenStream[index+3])
						borderChars[char].drawingMetrics.drawingWidth = Int(tokenStream[index+4])
						if dynamicLoad  = False then
							borderChars[char].image = LoadImage(prefixName + "_BORDER_" + char + ".png")
							borderChars[char].image.SetHandle(-borderChars[char].drawingMetrics.drawingOffset.x,-borderChars[char].drawingMetrics.drawingOffset.y)
						Else
							borderChars[char].SetImageResourceName  prefixName + "_BORDER_" + char + ".png"
						endif
						index += 5
						index += 1

					Case "{SH"
						index += 3
						shadowChars[char] = New BitMapChar
						shadowChars[char].drawingMetrics.drawingOffset.x = Int(tokenStream[index])
						shadowChars[char].drawingMetrics.drawingOffset.y = Int(tokenStream[index+1])
						shadowChars[char].drawingMetrics.drawingSize.x = Int(tokenStream[index+2])
						shadowChars[char].drawingMetrics.drawingSize.y = Int(tokenStream[index+3])
						shadowChars[char].drawingMetrics.drawingWidth = Int(tokenStream[index+4])
						Local filename:String = prefixName + "_SHADOW_" + char + ".png"
						if dynamicLoad  = False then
							shadowChars[char].image = LoadImage(filename)
							shadowChars[char].image.SetHandle(-shadowChars[char].drawingMetrics.drawingOffset.x,-shadowChars[char].drawingMetrics.drawingOffset.y)
						Else
							shadowChars[char].SetImageResourceName  filename
						endif

						index+=5
						index += 1

					Case "{FC"
						index += 3
						faceChars[char] = New BitMapChar
						faceChars[char].drawingMetrics.drawingOffset.x = Int(tokenStream[index])
						faceChars[char].drawingMetrics.drawingOffset.y = Int(tokenStream[index+1])
						faceChars[char].drawingMetrics.drawingSize.x = Int(tokenStream[index+2])
						faceChars[char].drawingMetrics.drawingSize.y = Int(tokenStream[index+3])
						faceChars[char].drawingMetrics.drawingWidth = Int(tokenStream[index+4])
						if dynamicLoad = False then
							faceChars[char].image = LoadImage(prefixName + "_" + char + ".png")
							faceChars[char].image.SetHandle(-faceChars[char].drawingMetrics.drawingOffset.x,-faceChars[char].drawingMetrics.drawingOffset.y)
						Else
							faceChars[char].SetImageResourceName prefixName + "_" + char + ".png"
						endif
						index += 5
						index += 1

					Default
						Print "Error loading font! Char = " + char

				End
			Wend
			borderChars = borderChars[..char+1]
			faceChars = faceChars[..char+1]
			shadowChars = shadowChars[..char+1]
		End

		Field packedImages:Image[]

		Method LoadPacked:Void(info:String, fontName:String, dynamicLoad:bool)

			Local header:String = info[.. info.Find(",")]

			Local separator:String
			Select header
				Case "P1"
					separator = "."
				Case "P1.01"
					separator = "_P_"
			End Select
			info = info[info.Find(",")+1..]
			borderChars = New BitMapChar[65536]
			faceChars = New BitMapChar[65536]
			shadowChars = New BitMapChar[65536]
			packedImages = New Image[256]
			Local maxPacked:Int = 0
			Local maxChar:Int = 0

			Local prefixName:String = fontName
			if prefixName.ToLower().EndsWith(".txt") Then prefixName = prefixName[..-4]

			Local charList:string[] = info.Split(";")
			For local chr:String = EachIn charList

				Local chrdata:string[] = chr.Split(",")
				if chrdata.Length() <2 Then Exit
				Local char:bitmapchar.BitMapChar
				Local charIndex:Int = int(chrdata[0])
				if maxChar<charIndex Then maxChar = charIndex

				select chrdata[1]
					Case "B"
						borderChars[charIndex] = New BitMapChar
						char = borderChars[charIndex]
					Case "F"
						faceChars [charIndex] = New BitMapChar
						char = faceChars[charIndex]
					Case "S"
						shadowChars [charIndex] = New BitMapChar
						char = shadowChars[charIndex]
				End Select
				char.packedFontIndex = Int(chrdata[2])
				if packedImages[char.packedFontIndex] = null Then
					packedImages[char.packedFontIndex] = LoadImage(prefixName + separator + char.packedFontIndex +  ".png")
					if maxPacked<char.packedFontIndex Then maxPacked = char.packedFontIndex
				endif
				char.packedPosition.x = Int(chrdata[3])
				char.packedPosition.y = Int(chrdata[4])
				char.packedSize.x = Int(chrdata[5])
				char.packedSize.y = Int(chrdata[6])
				char.drawingMetrics.drawingOffset.x = Int(chrdata[8])
				char.drawingMetrics.drawingOffset.y = Int(chrdata[9])
				char.drawingMetrics.drawingSize.x = Int(chrdata[10])
				char.drawingMetrics.drawingSize.y = Int(chrdata[11])
				char.drawingMetrics.drawingWidth = Int(chrdata[12])

			Next

			borderChars = borderChars[..maxChar+1]
			faceChars = faceChars[..maxChar+1]
			shadowChars = shadowChars[..maxChar+1]
			packedImages = packedImages[..maxPacked+1]

		End

		Method DrawChars:Void(text:FlxText, x:Float, y:Float, target:BitMapChar[])
			Local lineIndex:Int = 0, countLines:Int = text._countLines, line:FlxTextLine

			Local drx:Int = x, dry:Int = y
			Local i:Int = 0, l:Int
			Local char:Int

			Local lineHeight:Int = text._fontHeight + _kerning.y
			Local targetLength:Int = target.Length()

			While (lineIndex < countLines)
				line = text._lines[lineIndex]
				i = line.startPos
				l = line.endPos
				drx = x + line.xOffset

				While (i < l)
					char = text._value[i]

					If char >= 0 And char <= targetLength And target[char] <> Null Then
						If target[char].packedFontIndex > 0 Then
								DrawImageRect(packedImages[target[char].packedFontIndex], drx + target[char].drawingMetrics.drawingOffset.x, dry + target[char].drawingMetrics.drawingOffset.y, target[char].packedPosition.x, target[char].packedPosition.y, target[char].packedSize.x, target[char].packedSize.y)
						ElseIf target[char].image <> Null Then
							DrawImage(target[char].image, drx, dry)
						EndIf

						drx += faceChars[char].drawingMetrics.drawingWidth + _kerning.x
					End If

					i += 1
				Wend

				lineIndex += 1
				dry += lineHeight
			Wend
		End Method

		Field _kerning:drawingpoint.DrawingPoint
	End
#End