More storyboard stuff.

More storyboard stuff.

Strict

Private
Import mojo
Import functions
Import collections
Import xml

Public
Import exception

Const TRANSFORM_POSITION:Int = 0
Const TRANSFORM_ALPHA:Int = 1
Const TRANSFORM_SCALE:Int = 2
Const TRANSFORM_SCALE_VECTOR:Int = 3
Const TRANSFORM_ROTATION:Int = 4
Const TRANSFORM_COLOR:Int = 5
Const TRANSFORM_HANDLE:Int = 6
Const TRANSFORM_SHAKE:Int = 7
Const TRANSFORM_COUNT:Int = 8

Const EASE_NONE:Int = 0
Const EASE_IN_DOUBLE:Int = 1
Const EASE_IN:Int = 2
Const EASE_IN_HALF:Int = 3
Const EASE_OUT:Int = 4
Const EASE_OUT_HALF:Int = 5
Const EASE_OUT_DOUBLE:Int = 6
Const EASE_IN_OUT:Int = 7

Class Storyboard
Private
	Field sprites:ArrayList<StoryboardSprite> = New ArrayList<StoryboardSprite>
	Field sounds:ArrayList<StoryboardSound> = New ArrayList<StoryboardSound>

Public
	Function LoadXML:Storyboard(filename:String)
		Local parser:XMLParser = New XMLParser
		Local doc:XMLDocument = parser.ParseFile("storyboard.xml")
		Local root:XMLElement = doc.Root
		Local sb:Storyboard = New Storyboard
		For Local node:XMLElement = EachIn root.Children
			If node.Name = "layer" Then
				Local index:Int = Int(node.GetAttribute("index","0"))
				For Local spriteNode:XMLElement = EachIn node.Children
					If spriteNode.Name = "sprite" Then
						sb.sprites.Add(StoryboardSprite.CreateFromXML(spriteNode, index))
					End
				Next
			End
		Next
		sb.sprites.Sort()
		Return sb
	End

	#Rem
	Function LoadOSB:Storyboard(filename:String)
		Local osb:String = LoadString(filename)
		Local lines:List<String> = New List<String>
		Local s:Int = 0, e:Int = 0
		Local prev:Int = 0
		For Local e:Int = 0 Until osb.Length
			Local newline:Bool = False
			If osb[e] = 13 Then
				newline = True
			ElseIf osb[e] = 10 Then
				If prev <> 13 Then
					newline = True
				Else
					s += 1
				End
			End
			If newline Then
				lines.AddLast(osb[s..e])
				s = e+1
			End
			prev = osb[e]
		Next
		If s < e Then lines.AddLast(osb[s..e])
		For Local i:Int = 0 Until lines.Count
			Local str:String = lines.Get(i)
			If str.StartsWith("Sprite") Then
				Local tokens:String[] = str.Split(",")
				Local layerStr:String = tokens[1]
				Local imageName:String = tokens[3]
		Next
	End
	#End

	Method Update:Void(currentTime:Int)
		For Local i:Int = 0 Until sprites.Size
			Local sprite:StoryboardSprite = sprites.Get(i)
			sprite.Update(currentTime)
		Next
		'For Local i:Int = 0 Until sounds.Size
		'	Local sound:StoryboardSound = sounds.Get(i)
		'	sound.Update(currentTime)
		'Next
	End

	Method Render:Void()
		For Local i:Int = 0 Until sprites.Size
			Local sprite:StoryboardSprite = sprites.Get(i)
			sprite.Render()
		Next
	End
End

Class StoryboardElement Implements IComparable Abstract
Private
	Global nextId:Int = 0
	Field id:Int

Public
	Method New()
		id = nextId
		nextId += 1
	End

	Method Compare:Int(other:Object)
		Local o:StoryboardElement = StoryboardElement(other)
		If Not o Then Return -1
		If o = Self Then Return 0
		If id < o.id Then Return -1
		If id > o.id Then Return 1
		Return 0
	End

	Method Equals:Bool(other:Object)
		Return Compare(other)=0
	End
End

Class StoryboardSound Extends StoryboardElement
Private
	Field soundName:String
	Field sound:GameSound

Public
	Function CreateFromXML:StoryboardSound(node:XMLElement)
		Return Null
	End

	Method New(soundName:String)
		Super.New()
		Self.soundName = soundName
	End
End

Class StoryboardSprite Extends StoryboardElement
Private
	Field layer:Int
	Field imageName:String
	Field image:GameImage

	Field firstX:Float, firstY:Float
	field firstScaleX:Float, firstScaleY:Float
	Field firstScale:Float, firstRotation:Float
	Field firstRed:Float, firstGreen:Float, firstBlue:Float, firstAlpha:Float

	Field x:Float, y:Float
	field scaleX:Float, scaleY:Float
	Field scale:Float, rotation:Float
	Field red:Float, green:Float, blue:Float, alpha:Float

	Field transforms:ArrayList<StoryboardSpriteTransform> = New ArrayList<StoryboardSpriteTransform>
	Field currentTransforms:StoryboardSpriteTransform[] = New StoryboardSpriteTransform[TRANSFORM_COUNT]

Public
	Function CreateFromXML:StoryboardSprite(node:XMLElement, layer:Int)
		Local imageName:String = node.GetAttribute("image","")
		Local sprite:StoryboardSprite = New StoryboardSprite(imageName, layer)
		sprite.firstX = Float(node.GetAttribute("x","0"))
		sprite.firstY = Float(node.GetAttribute("y","0"))
		sprite.firstScaleX = Float(node.GetAttribute("scaleX","1"))
		sprite.firstScaleY = Float(node.GetAttribute("scaleY","1"))
		sprite.firstScale = Float(node.GetAttribute("scale","1"))
		sprite.firstRotation = Float(node.GetAttribute("rotation","0"))
		sprite.firstRed = Float(node.GetAttribute("red","255"))
		sprite.firstGreen = Float(node.GetAttribute("green","255"))
		sprite.firstBlue = Float(node.GetAttribute("blue","255"))
		sprite.firstAlpha = Float(node.GetAttribute("alpha","0"))
		CreateTransformsFromXML(sprite, node)
		Return sprite
	End

	Function CreateTransformsFromXML:Void(sprite:StoryboardSprite, node:XMLElement, timeOffset:Int=0)
		For Local childNode:XMLElement = EachIn node.Children
			Local name:String = childNode.Name
			If name = "group" Then
				Local loopCount:Int = Int(childNode.GetAttribute("loopCount","1"))
				Local startTime:Int = Int(childNode.GetAttribute("startTime","0"))
				Local endTime:Int = Int(childNode.GetAttribute("endTime","0"))
				Local myOffset:Int = timeOffset + startTime
				For Local i:Int = 0 Until loopCount
					CreateTransformsFromXML(sprite, childNode, myOffset)
					myOffset += endTime - startTime
				Next
			Else
				sprite.transforms.Add(StoryboardSpriteTransform.CreateFromXML(childNode, timeOffset))
			End
		Next
	End

	Method New(imageName:String, layer:Int)
		Super.New()
		Self.imageName = imageName
		Self.layer = layer
	End

	Method Compare:Int(other:Object)
		Local o:StoryboardSprite = StoryboardSprite(other)
		If Not o Then Return -1
		If o = Self Then Return 0
		If layer < o.layer Then Return -1
		If layer > o.layer Then Return 1
		Return Super.Compare(other)
	End

	Method Update:Void(currentTime:Int)
		x = firstX; y = firstY
		scaleX = firstScaleX; scaleY = firstScaleY
		scale = firstScale; rotation = firstRotation
		red = firstRed; green = firstGreen; blue = firstBlue; alpha = firstAlpha

		For Local i:Int = 0 Until transforms.Size
			transforms.Get(i).Update(currentTime)
		Next
		For Local i:Int = 0 Until currentTransforms.Length
			currentTransforms[i] = GetActiveTransform(i, currentTime)
			If currentTransforms[i] Then currentTransforms[i].Apply(Self)
		Next
	End

	Method Render:Void()
		If Not image Then image = game.images.Find(imageName)
		If Not image Then Return

		If alpha = 0 Then Return

		' translation, scale, rotation, handle, other effects
		PushMatrix
		Translate x, y
		Scale scaleX, scaleY
		Scale scale, scale
		Rotate rotation
		SetColor red, green, blue
		SetAlpha alpha

		image.Draw(0, 0)
		PopMatrix
	End

	Method GetActiveTransform:StoryboardSpriteTransform(findType:Int, atTime:Int)
		' loop on all children
		For Local i:Int = 0 Until transforms.Size
			Local tr:StoryboardSpriteTransform = transforms.Get(i)
			If tr.transformType = findType Then
				' if we're past the start time for this transform
				If atTime >= tr.startTime And atTime <= tr.endTime Then
					Return tr
				End
			End
		Next
		Return Null
	End
End

Class StoryboardSpriteTransform Implements IComparable
Private
	Global hslArray:Float[] = New Float[3]
	Global rgbArray:Int[] = New Int[3]

	Field transformType:Int = 0

	Field currentTime:Int
	Field startTime:Int
	Field endTime:Int
	Field easeType:Int

	Field startValues:Float[]
	Field endValues:Float[]
	Field currentValues:Float[]

Public
	Function CreateFromXML:StoryboardSpriteTransform(node:XMLElement, timeOffset:Int=0)
		Local name:String = node.Name
		Local startTime:Int = Int(node.GetAttribute("startTime","0"))+timeOffset
		Local endTime:Int = Int(node.GetAttribute("endTime","0"))+timeOffset
		Local easeType:Int = Int(node.GetAttribute("easeType","0"))
		If name = "scale" Then
			Local startScale:Float = Float(node.GetAttribute("startScale","1"))
			Local endScale:Float = Float(node.GetAttribute("endScale","1"))
			Return CreateScale(startTime, endTime, easeType, startScale, endScale)
		ElseIf name = "scaleVector" Then
			Local startScaleX:Float = Float(node.GetAttribute("startScaleX","1"))
			Local endScaleX:Float = Float(node.GetAttribute("endScaleX","1"))
			Local startScaleY:Float = Float(node.GetAttribute("startScaleY","1"))
			Local endScaleY:Float = Float(node.GetAttribute("endScaleY","1"))
			Return CreateScaleVector(startTime, endTime, easeType, startScaleX, startScaleY, endScaleX, endScaleY)
		ElseIf name = "alpha" Then
			Local startAlpha:Float = Float(node.GetAttribute("startAlpha","1"))
			Local endAlpha:Float = Float(node.GetAttribute("endAlpha","1"))
			Return CreateAlpha(startTime, endTime, easeType, startAlpha, endAlpha)
		ElseIf name = "rotation" Then
			Local startRotation:Float = Float(node.GetAttribute("startRotation","0"))
			Local endRotation:Float = Float(node.GetAttribute("endRotation","0"))
			Return CreateRotation(startTime, endTime, easeType, startRotation, endRotation)
		ElseIf name = "position" Then
			Local startX:Float = Float(node.GetAttribute("startX","0"))
			Local endX:Float = Float(node.GetAttribute("endX","0"))
			Local startY:Float = Float(node.GetAttribute("startY","0"))
			Local endY:Float = Float(node.GetAttribute("endY","0"))
			Return CreatePosition(startTime, endTime, easeType, startX, startY, endX, endY)
		ElseIf name = "handle" Then
			Local startX:Float = Float(node.GetAttribute("startX","0"))
			Local endX:Float = Float(node.GetAttribute("endX","0"))
			Local startY:Float = Float(node.GetAttribute("startY","0"))
			Local endY:Float = Float(node.GetAttribute("endY","0"))
			Return CreateHandle(startTime, endTime, easeType, startX, startY, endX, endY)
		ElseIf name = "color" Then
			If node.HasAttribute("startRed") Or node.HasAttribute("startGreen") Or node.HasAttribute("startBlue") Then
				Local startRed:Float = Float(node.GetAttribute("startRed","255"))
				Local endRed:Float = Float(node.GetAttribute("endRed","255"))
				Local startGreen:Float = Float(node.GetAttribute("startGreen","255"))
				Local endGreen:Float = Float(node.GetAttribute("endGreen","255"))
				Local startBlue:Float = Float(node.GetAttribute("startBlue","255"))
				Local endBlue:Float = Float(node.GetAttribute("endBlue","255"))
				Return CreateColorRGB(startTime, endTime, easeType, startRed, startGreen, startBlue, endRed, endGreen, endBlue)
			Else
				Local startHue:Float = Float(node.GetAttribute("startHue","0"))
				Local endHue:Float = Float(node.GetAttribute("endHue","0"))
				Local startSaturation:Float = Float(node.GetAttribute("startSaturation","1"))
				Local endSaturation:Float = Float(node.GetAttribute("endSaturation","1"))
				Local startLuminance:Float = Float(node.GetAttribute("startLuminance","1"))
				Local endLuminance:Float = Float(node.GetAttribute("endLuminance","1"))
				Return CreateColorHSL(startTime, endTime, easeType, startHue, startSaturation, startLuminance, endHue, endSaturation, endLuminance)
			End
		End
		Return Null
	End

	Function CreateScale:StoryboardSpriteTransform(startTime%, endTime%, easeType%, startScale#, endScale#)
		Return New StoryboardSpriteTransform(TRANSFORM_SCALE, startTime, endTime, easeType, startScale, endScale)
	End

	Function CreateScaleVector:StoryboardSpriteTransform(startTime%, endTime%, easeType%, startScaleX#, startScaleY#, endScaleX#, endScaleY#)
		Return New StoryboardSpriteTransform(TRANSFORM_SCALE_VECTOR, startTime, endTime, easeType, startScaleX, endScaleX, startScaleY, endScaleY)
	End

	Function CreateAlpha:StoryboardSpriteTransform(startTime%, endTime%, easeType%, startAlpha#, endAlpha#)
		startAlpha = Max(0.0,Min(1.0,startAlpha))
		endAlpha = Max(0.0,Min(1.0,endAlpha))
		Return New StoryboardSpriteTransform(TRANSFORM_ALPHA, startTime, endTime, easeType, startAlpha, endAlpha)
	End

	Function CreateRotation:StoryboardSpriteTransform(startTime%, endTime%, easeType%, startRotation#, endRotation#)
		Return New StoryboardSpriteTransform(TRANSFORM_ROTATION, startTime, endTime, easeType, startRotation, endRotation)
	End

	Function CreatePosition:StoryboardSpriteTransform(startTime%, endTime%, easeType%, startX#, startY#, endX#, endY#)
		Return New StoryboardSpriteTransform(TRANSFORM_POSITION, startTime, endTime, easeType, startX, endX, startY, endY)
	End

	Function CreateHandle:StoryboardSpriteTransform(startTime%, endTime%, easeType%, startX#, startY#, endX#, endY#)
		Return New StoryboardSpriteTransform(TRANSFORM_HANDLE, startTime, endTime, easeType, startX, endX, startY, endY)
	End

	Function CreateColorRGB:StoryboardSpriteTransform(startTime%, endTime%, easeType%, startRed#, startGreen#, startBlue#, endRed#, endGreen#, endBlue#)
		startRed = Max(0.0,Min(255.0,startRed))
		startGreen = Max(0.0,Min(255.0,startGreen))
		startBlue = Max(0.0,Min(255.0,startBlue))
		endRed = Max(0.0,Min(255.0,endRed))
		endGreen = Max(0.0,Min(255.0,endGreen))
		endBlue = Max(0.0,Min(255.0,endBlue))
		RGBtoHSL(startRed, startGreen, startBlue, hslArray)
		Local startHue:Float = hslArray[0], startSaturation:Float = hslArray[1], startLuminance:Float = hslArray[2]
		RGBtoHSL(endRed, endGreen, endBlue, hslArray)
		Local endHue:Float = hslArray[0], endSaturation:Float = hslArray[1], endLuminance:Float = hslArray[2]
		Return CreateColorHSL(startTime, endTime, easeType, startHue, startSaturation, startLuminance, endHue, endSaturation, endLuminance)
	End

	Function CreateColorHSL:StoryboardSpriteTransform(startTime%, endTime%, easeType%, startHue#, startSaturation#, startLuminance#, endHue#, endSaturation#, endLuminance#)
		startHue = Max(0.0, Min(1.0, startHue))
		startSaturation = Max(0.0, Min(1.0, startSaturation))
		startLuminance = Max(0.0, Min(1.0, startLuminance))
		endHue = Max(0.0, Min(1.0, endHue))
		endSaturation = Max(0.0, Min(1.0, endSaturation))
		endLuminance = Max(0.0, Min(1.0, endLuminance))
		Return New StoryboardSpriteTransform(TRANSFORM_COLOR, startTime, endTime, easeType, startHue, endHue, startSaturation, endSaturation, startLuminance, endLuminance)
	End

	Method New(transformType:Int, startTime:Int, endTime:Int, easeType:Int,
							startValue1:Float=0, endValue1:Float=0,
							startValue2:Float=0, endValue2:Float=0,
							startValue3:Float=0, endValue3:Float=0,
							startValue4:Float=0, endValue4:Float=0,
							startValue5:Float=0, endValue5:Float=0)
		Self.transformType = transformType
		Self.startTime = startTime
		Self.endTime = endTime
		Self.easeType = easeType
		Select transformType
			Case TRANSFORM_ALPHA, TRANSFORM_SCALE, TRANSFORM_ROTATION
				Init(1, startValue1, endValue1)
			Case TRANSFORM_POSITION, TRANSFORM_SCALE_VECTOR, TRANSFORM_HANDLE
				Init(2, startValue1, endValue1, startValue2, endValue2)
			Case TRANSFORM_COLOR
				Init(3, startValue1, endValue1, startValue2, endValue2, startValue3, endValue3)
		End
	End

	Method Update:Void(currentTime:Int)
		Self.currentTime = currentTime
		For Local i:Int = 0 Until startValues.Length
			currentValues[i] = Calculate(startValues[i], endValues[i])
		Next
	End

	Method Apply:Void(sprite:StoryboardSprite)
		Select transformType
			Case TRANSFORM_ALPHA
				sprite.alpha = currentValues[0]
			Case TRANSFORM_SCALE
				sprite.scale = currentValues[0]
			Case TRANSFORM_ROTATION
				sprite.rotation = currentValues[0]
			Case TRANSFORM_POSITION
				sprite.x = currentValues[0]
				sprite.y = currentValues[1]
			Case TRANSFORM_SCALE_VECTOR
				sprite.scaleX = currentValues[0]
				sprite.scaleY = currentValues[1]
			Case TRANSFORM_COLOR
				HSLtoRGB(currentValues[0], currentValues[1], currentValues[2], rgbArray)
				sprite.red = rgbArray[0]
				sprite.green = rgbArray[1]
				sprite.blue = rgbArray[2]
			Case TRANSFORM_HANDLE
				If sprite And sprite.image And sprite.image.image Then
					sprite.image.image.SetHandle(currentValues[0], currentValues[1])
				End
		End
	End

	Method Compare:Int(other:Object)
		Local o:StoryboardSpriteTransform = StoryboardSpriteTransform(other)
		If Not o Then Return -1
		If o = Self Then Return 0
		If startTime > o.startTime Then Return 1
		If startTime < o.startTime Then Return -1
		If endTime > o.endTime Then Return 1
		If endTime < o.endTime Then Return -1
		If transformType > o.transformType Then Return 1
		If transformType < o.transformType Then Return -1
		Return 0
	End

	Method Equals:Bool(other:Object)
		Return Compare(other)=0
	End

Private
	Method Init:Void(elementCount:Int,
							startValue1:Float=0, endValue1:Float=0,
							startValue2:Float=0, endValue2:Float=0,
							startValue3:Float=0, endValue3:Float=0,
							startValue4:Float=0, endValue4:Float=0,
							startValue5:Float=0, endValue5:Float=0)
		startValues = New Float[elementCount]
		endValues = New Float[elementCount]
		currentValues = New Float[elementCount]
		If elementCount >= 1 Then
			startValues[0] = startValue1
			endValues[0] = endValue1
		End
		If elementCount >= 2 Then
			startValues[1] = startValue2
			endValues[1] = endValue2
		End
		If elementCount >= 3 Then
			startValues[2] = startValue3
			endValues[2] = endValue3
		End
		If elementCount >= 4 Then
			startValues[3] = startValue4
			endValues[3] = endValue4
		End
		If elementCount >= 5 Then
			startValues[4] = startValue5
			endValues[4] = endValue5
		End
	End

	Method Calculate:Float(startValue:Float, endValue:Float)
		' shortcut for start/end (also accounts for the case when startTime==endTime)
		' we check endTime first because if startTime==endTime==currentTime, we want to use endValue
		If currentTime >= endTime Then Return endValue
		If currentTime <= startTime Then Return startValue

		' how far through are we?
		Local progress:Float = Float(currentTime - startTime) / Float(endTime - startTime)

		Select easeType
			Case EASE_IN_DOUBLE
				Return Lerp(endValue, startValue, (1-progress)*(1-progress)*(1-progress)*(1-progress))
			Case EASE_IN
				Return Lerp(endValue, startValue, (1-progress)*(1-progress))
			Case EASE_IN_HALF
				Return Lerp(endValue, startValue, Pow(1-progress, 1.5))
			Case EASE_OUT
				Return Lerp(startValue, endValue, progress * progress)
			Case EASE_OUT_HALF
				Return Lerp(startValue, endValue, Pow(progress, 1.5))
			Case EASE_OUT_DOUBLE
				Return Lerp(startValue, endValue, progress*progress*progress*progress)
			Case EASE_IN_OUT
				Return startValue + (-2*(progress*progress*progress) + 3*(progress*progress)) * (endValue - startValue)
			Default
				Return Lerp(startValue, endValue, progress);
		End
	End

	Method Lerp:Float(startValue:Float, endValue:Float, progress:Float)
		Return startValue + (endValue-startValue) * progress
	End
End

Strict

Public
Import exception

Private
Import mojo
Import functions
Import collections

Const TRANSFORM_POSITION:Int = 0
Const TRANSFORM_ALPHA:Int = 1
Const TRANSFORM_SCALE:Int = 2
Const TRANSFORM_SCALE_VECTOR:Int = 3
Const TRANSFORM_ROTATION:Int = 4
Const TRANSFORM_COLOR:Int = 5
Const TRANSFORM_HANDLE:Int = 6
Const TRANSFORM_SHAKE:Int = 7
Const TRANSFORM_COUNT:Int = 8

Const EASE_NONE:Int = 0
Const EASE_IN_DOUBLE:Int = 1
Const EASE_IN:Int = 2
Const EASE_IN_HALF:Int = 3
Const EASE_OUT:Int = 4
Const EASE_OUT_HALF:Int = 5
Const EASE_OUT_DOUBLE:Int = 6
Const EASE_IN_OUT:Int = 7

Class Storyboard
Private
	Field sprites:ArrayList<StoryboardSprite> = New ArrayList<StoryboardSprite>
	Field sounds:ArrayList<StoryboardSound> = New ArrayList<StoryboardSound>

Public
	Function LoadXML:Storyboard(filename:String)
		Local parser:XMLParser = New XMLParser
		Local doc:XMLDocument = parser.LoadFile("storyboard.xml")
		Local root:XMLElement = doc.Root
		Local sb:Storyboard = New Storyboard
		For Local node:XMLElement = EachIn root.Children
			If node.Name = "layer" Then
				Local index:Int = Int(node.GetAttribute("index","0"))
				For Local spriteNode:XMLElement = EachIn node.Children
					If spriteNode.Name = "sprite" Then
						sb.sprites.Add(StoryboardSprite.CreateFromXML(spriteNode, index))
					End
				Next
			End
		Next
		sb.sprites.Sort()
		Return sb
	End

	Method Update:Void(currentTime:Int)
		For Local i:Int = 0 Until sprites
			Local sprite:StoryboardSprite = sprites.Get(i)
			sprite.Update(currentTime)
		Next
		'For Local i:Int = 0 Until sounds
		'	Local sound:StoryboardSound = sounds.Get(i)
		'	sound.Update(currentTime)
		'Next
	End

	Method Render:Void()
		For Local i:Int = 0 Until sprites
			Local sprite:StoryboardSprite = sprites.Get(i)
			sprite.Render()
		Next
	End
End

Class StoryboardElement Implements IComparable Abstract
Private
	Global nextId:Int = 0
	Field id:Int

Public
	Method New()
		id = nextId
		nextId += 1
	End

	Method Compare:Int(other:Object)
		Local o:StoryboardElement = StoryboardElement(other)
		If Not o Then Return -1
		If o = Self Then Return 0
		If id < o.id Then Return -1
		If id > o.id Then Return 1
		Return 0
	End

	Method Equals:Bool(other:Object)
		Return Compare(other)=0
	End
End

Class StoryboardSound Extends StoryboardElement
Private
	Field soundName:String
	Field sound:GameSound

Public
	Function CreateFromXML:StoryboardSound(node:XMLElement)
		Return Null
	End

	Method New(soundName:String)
		Super.New()
		Self.soundName = soundName
	End
End

Class StoryboardSprite Extends StoryboardElement
Private
	Field layer:Int
	Field imageName:String
	Field image:GameImage

	Field transforms:ArrayList<StoryboardSpriteTransform> = New ArrayList<StoryboardSpriteTransform>
	Field currentTransforms:StoryboardSpriteTransform[] = New StoryboardSpriteTransform[TRANSFORM_COUNT]

Public
	Function CreateFromXML:StoryboardSprite(node:XMLElement, layer:Int)
		Local imageName:String = node.GetAttribute("imageName","")
		Local sprite:StoryboardSprite = New StoryboardSprite(imageName, layer)
		CreateTransformsFromXML(sprite, node)
		Return sprite
	End

	Function CreateTransformsFromXML:Void(sprite:StoryboardSprite, node:XMLElement, timeOffset:Int=0)
		For Local childNode:XMLElement = EachIn node.Children
			Local name:String = childNode.Name
			If name = "group" Then
				Local loopCount:Int = Int(childNode.GetAttribute("loopCount","1"))
				Local startTime:Int = Int(childNode.GetAttribute("startTime","0"))
				Local endTime:Int = Int(childNode.GetAttribute("endTime","0"))
				Local myOffset:Int = timeOffset + startTime
				For Local i:Int = 0 Until loopCount
					CreateTransformsFromXML(sprite, childNode, myOffset)
					myOffset += endTime - startTime
				Next
			Else
				sprite.transforms.Add(StoryboardSpriteTransform.CreateFromXML(childNode, timeOffset))
			End
		Next
	End

	Method New(imageName:String, layer:Int)
		Super.New()
		Self.imageName = imageName
		Self.layer = layer
	End

	Method Compare:Int(other:Object)
		Local o:StoryboardSprite = StoryboardSprite(other)
		If Not o Then Return -1
		If o = Self Then Return 0
		If layer < o.layer Then Return -1
		If layer > o.layer Then Return 1
		Return Super.Compare(other)
	End

	Method Update:Void(currentTime:Int)
		For Local i:Int = 0 Until transforms.Size
			transforms.Get(i).Update(currentTime)
		Next
		For Local i:Int = 0 Until currentTransforms.Length
			currentTransforms[i] = GetActiveTransform(i, currentTime)
		Next
	End

	Method Render:Void()
		If Not image Then image = game.images.Find(imageName)
		If Not image Then Return
		PushMatrix
		' translation, scale, rotation, handle, other effects
		If currentTransforms[TRANSFORM_POSITION] Then currentTransforms[TRANSFORM_POSITION].Apply()
		If currentTransforms[TRANSFORM_SCALE_VECTOR] Then currentTransforms[TRANSFORM_SCALE_VECTOR].Apply()
		If currentTransforms[TRANSFORM_SCALE] Then currentTransforms[TRANSFORM_SCALE].Apply()
		If currentTransforms[TRANSFORM_ROTATION] Then currentTransforms[TRANSFORM_ROTATION].Apply()
		If currentTransforms[TRANSFORM_HANDLE] Then currentTransforms[TRANSFORM_HANDLE].Apply()
		If currentTransforms[TRANSFORM_SHAKE] Then currentTransforms[TRANSFORM_SHAKE].Apply()
		If currentTransforms[TRANSFORM_COLOR] Then currentTransforms[TRANSFORM_COLOR].Apply()
		image.Draw(0, 0)
		PopMatrix
	End

	Method GetActiveTransform:StoryboardSpriteTransform(findType:Int, atTime:Int)
		' by default, we haven't found anything
		Local active:StoryboardSpriteTransform = Null
		' loop on all children
		For Local i:Int = 0 Until transforms.Size
			Local tr:StoryboardSpriteTransform = transforms.Get(i)
			If tr.transformType = findType Then
				' if we're past the start time for this transform
				If atTime >= tr.startTime Then
					active = child
				Else
					' we've gone past the current time, so break out
					Exit
				End
			End
		Next
		' return what we have
		Return active
	End
End

Class StoryboardSpriteTransform Implements IComparable
Private
	Global hslArray:Float[] = New Float[3]
	Global rgbArray:Int[] = New Int[3]

	Field transformType:Int = TRANSFORM_NONE

	Field currentTime:Int
	Field startTime:Int
	Field endTime:Int
	Field easeType:Int

	Field startValues:Float[]
	Field endValues:Float[]
	Field currentValues:Float[]

Public
	Function CreateFromXML:StoryboardSpriteTransform(node:XMLElement, timeOffset:Int=0)
		Local name:String = node.Name
		Local startTime:Int = Int(node.GetAttribute("startTime","0"))+timeOffset
		Local endTime:Int = Int(node.GetAttribute("endTime","0"))+timeOffset
		Local easeType:Int = Int(node.GetAttribute("easeType","0"))
		If name = "scale" Then
			Local startScale:Float = Float(node.GetAttribute("startScale","1"))
			Local endScale:Float = Float(node.GetAttribute("endScale","1"))
			Return CreateScale(startTime, endTime, easeType, startScale, endScale)
		ElseIf name = "scaleVector" Then
			Local startScaleX:Float = Float(node.GetAttribute("startScaleX","1"))
			Local endScaleX:Float = Float(node.GetAttribute("endScaleX","1"))
			Local startScaleY:Float = Float(node.GetAttribute("startScaleY","1"))
			Local endScaleY:Float = Float(node.GetAttribute("endScaleY","1"))
			Return CreateScaleVector(startTime, endTime, easeType, startScaleX, startScaleY, endScaleX, endScaleY)
		ElseIf name = "alpha" Then
			Local startAlpha:Float = Float(node.GetAttribute("startAlpha","1"))
			Local endAlpha:Float = Float(node.GetAttribute("endAlpha","1"))
			Return CreateAlpha(startTime, endTime, easeType, startAlpha, endAlpha)
		ElseIf name = "rotation" Then
			Local startRotation:Float = Float(node.GetAttribute("startRotation","0"))
			Local endRotation:Float = Float(node.GetAttribute("endRotation","0"))
			Return CreateRotation(startTime, endTime, easeType, startRotation, endRotation)
		ElseIf name = "position" Then
			Local startX:Float = Float(node.GetAttribute("startX","0"))
			Local endX:Float = Float(node.GetAttribute("endX","0"))
			Local startY:Float = Float(node.GetAttribute("startY","0"))
			Local endY:Float = Float(node.GetAttribute("endY","0"))
			Return CreatePosition(startTime, endTime, easeType, startX, startY, endX, endY)
		ElseIf name = "handle" Then
			Local startX:Float = Float(node.GetAttribute("startX","0"))
			Local endX:Float = Float(node.GetAttribute("endX","0"))
			Local startY:Float = Float(node.GetAttribute("startY","0"))
			Local endY:Float = Float(node.GetAttribute("endY","0"))
			Return CreateHandle(startTime, endTime, easeType, startX, startY, endX, endY)
		ElseIf name = "color" Then
			If node.HasAttribute("startRed") Or node.HasAttribute("startGreen") Or node.HasAttribute("startBlue") Then
				Local startRed:Float = Float(node.GetAttribute("startRed","255"))
				Local endRed:Float = Float(node.GetAttribute("endRed","255"))
				Local startGreen:Float = Float(node.GetAttribute("startGreen","255"))
				Local endGreen:Float = Float(node.GetAttribute("endGreen","255"))
				Local startBlue:Float = Float(node.GetAttribute("startBlue","255"))
				Local endBlue:Float = Float(node.GetAttribute("endBlue","255"))
				Return CreateColorRGB(startTime, endTime, easeType, startRed, startGreen, startBlue, endRed, endGreen, endBlue)
			Else
				Local startHue:Float = Float(node.GetAttribute("startHue","0"))
				Local endHue:Float = Float(node.GetAttribute("endHue","0"))
				Local startSaturation:Float = Float(node.GetAttribute("startSaturation","1"))
				Local endSaturation:Float = Float(node.GetAttribute("endSaturation","1"))
				Local startLuminance:Float = Float(node.GetAttribute("startLuminance","1"))
				Local endLuminance:Float = Float(node.GetAttribute("endLuminance","1"))
				Return CreateColorHSL(startTime, endTime, easeType, startHue, startSaturation, startLuminance, endHue, endSaturation, endLuminance)
			End
		End
	End

	Function CreateScale:StoryboardSpriteTransform(startTime%, endTime%, easeType%, startScale#, endScale#)
		Return New StoryboardSpriteTransform(TRANSFORM_SCALE, startTime, endTime, easeType, startScale, endScale)
	End

	Function CreateScaleVector:StoryboardSpriteTransform(startTime%, endTime%, easeType%, startScaleX#, startScaleY#, endScaleX#, endScaleY#)
		Return New StoryboardSpriteTransform(TRANSFORM_SCALE_VECTOR, startTime, endTime, easeType, startScaleX, endScaleX, startScaleY, endScaleY)
	End

	Function CreateAlpha:StoryboardSpriteTransform(startTime%, endTime%, easeType%, startAlpha#, endAlpha#)
		startAlpha = Max(0.0,Min(1.0,startAlpha))
		endAlpha = Max(0.0,Min(1.0,endAlpha))
		Return New StoryboardSpriteTransform(TRANSFORM_ALPHA, startTime, endTime, easeType, startAlpha, endAlpha)
	End

	Function CreateRotation:StoryboardSpriteTransform(startTime%, endTime%, easeType%, startRotation#, endRotation#)
		Return New StoryboardSpriteTransform(TRANSFORM_ROTATION, startTime, endTime, easeType, startRotation, endRotation)
	End

	Function CreatePosition:StoryboardSpriteTransform(startTime%, endTime%, easeType%, startX#, startY#, endX#, endY#)
		Return New StoryboardSpriteTransform(TRANSFORM_POSITION, startTime, endTime, easeType, startX, endX, startY, endY)
	End

	Function CreateHandle:StoryboardSpriteTransform(startTime%, endTime%, easeType%, startX#, startY#, endX#, endY#)
		Return New StoryboardSpriteTransform(TRANSFORM_HANDLE, startTime, endTime, easeType, startX, endX, startY, endY)
	End

	Function CreateColorRGB:StoryboardSpriteTransform(startTime%, endTime%, easeType%, startRed#, startGreen#, startBlue#, endRed#, endGreen#, endBlue#)
		startRed = Max(0.0,Min(255.0,startRed))
		startGreen = Max(0.0,Min(255.0,startGreen))
		startBlue = Max(0.0,Min(255.0,startBlue))
		endRed = Max(0.0,Min(255.0,endRed))
		endGreen = Max(0.0,Min(255.0,endGreen))
		endBlue = Max(0.0,Min(255.0,endBlue))
		RGBtoHSL(startRed, startGreen, startBlue, hslArray)
		Local startHue:Float = hslArray[0], startSaturation:Float = hslArray[1], startLuminance:Float = hslArray[2]
		RGBtoHSL(endRed, endGreen, endBlue, hslArray)
		Local endHue:Float = hslArray[0], endSaturation:Float = hslArray[1], endLuminance:Float = hslArray[2]
		Return CreateColorHSL(startTime, endTime, easeType, startHue, startSaturation, startLuminance, endHue, endSaturation, endLuminance)
	End

	Function CreateColorHSL:StoryboardSpriteTransform(startTime%, endTime%, easeType%, startHue#, startSaturation#, startLuminance#, endHue#, endSaturation#, endLuminance#)
		startHue = Max(0.0,Min(1.0,startHue))
		startSaturation = Max(0.0,Min(1.0,startGreen))
		startLuminance = Max(0.0,Min(1.0,startBlue))
		endHue = Max(0.0,Min(1.0,endHue))
		endSaturation = Max(0.0,Min(1.0,endGreen))
		endLuminance = Max(0.0,Min(1.0,endBlue))
		Return New StoryboardSpriteTransform(TRANSFORM_COLOR, startTime, endTime, easeType, startHue, endHue, startSaturation, endSaturation, startLuminance, endLuminance)
	End

	Method New(transformType:Int, startTime:Int, endTime:Int, easeType:Int
							startValue1:Float=0, endValue1:Float=0,
							startValue2:Float=0, endValue2:Float=0,
							startValue3:Float=0, endValue3:Float=0,
							startValue4:Float=0, endValue4:Float=0,
							startValue5:Float=0, endValue5:Float=0)
		Self.transformType = transformType
		Self.startTime = startTime
		Self.endTime = endTime
		Self.easeType = easeType
		Select transformType
			Case TRANSFORM_ALPHA, Case TRANSFORM_SCALE, Case TRANSFORM_ROTATION
				Init(1, startValue1, endValue1)
			Case TRANSFORM_POSITION, TRANSFORM_SCALE_VECTOR, TRANSFORM_HANDLE
				Init(2, startValue1, endValue1, startValue2, endValue2)
			Case TRANSFORM_COLOR
				Init(3, startValue1, endValue1, startValue2, endValue2, startValue3, endValue3)
		End
	End

	Method Update:Void(currentTime:Int)
		Self.currentTime = currentTime
		For Local i:Int = 0 Until startValues.Length
			currentValues[i] = Calculate(startValues[i], endValues[i])
		Next
	End

	Method Apply:Void(sprite:StoryboardSprite=Null)
		Select type
			Case TRANSFORM_ALPHA
				SetAlpha(currentValues[0])
			Case TRANSFORM_SCALE
				Scale(currentValues[0], currentValues[0])
			Case TRANSFORM_ROTATION
				Rotate(currentValues[0])
			Case TRANSFORM_POSITION, TRANSFORM_HANDLE
				Translate(currentValues[0], currentValues[1])
			Case TRANSFORM_SCALE_VECTOR
				Scale(currentValues[0], currentValues[1])
			Case TRANSFORM_COLOR
				HSLtoRGB(currentValues[0], currentValues[1], currentValues[2], rgbArray)
				SetColor(rgbArray[0], rgbArray[1], rgbArray[2])
			Case TRANSFORM_HANDLE
				If sprite And sprite.image And sprite.image.image Then
					sprite.image.image.SetHandle(currentValues[0], currentValues[1])
				End
		End
	End

	Method Compare:Int(other:Object)
		Local o:StoryboardSpriteTransform = StoryboardSpriteTransform(other)
		If Not o Then Return -1
		If o = Self Then Return 0
		If startTime > o.startTime Then Return 1
		If startTime < o.startTime Then Return -1
		If endTime > o.endTime Then Return 1
		If endTime < o.endTime Then Return -1
		If transformType > o.transformType Then Return 1
		If transformType < o.transformType Then Return -1
		Return 0
	End

	Method Equals:Bool(other:Object)
		Return Compare(other)=0
	End

Private
	Method Init:Void(elementCount:Int,
							startValue1:Float=0, endValue1:Float=0,
							startValue2:Float=0, endValue2:Float=0,
							startValue3:Float=0, endValue3:Float=0,
							startValue4:Float=0, endValue4:Float=0,
							startValue5:Float=0, endValue5:Float=0)
		startValues = New Float[elementCount]
		endValues = New Float[elementCount]
		currentValues = New Float[elementCount]
		If elementCount <= 1 Then
			startValues[0] = startValue1
			endValues[0] = endValue1
		End
		If elementCount <= 2 Then
			startValues[1] = startValue2
			endValues[1] = endValue2
		End
		If elementCount <= 3 Then
			startValues[2] = startValue3
			endValues[2] = endValue3
		End
		If elementCount <= 4 Then
			startValues[3] = startValue4
			endValues[3] = endValue4
		End
		If elementCount <= 5 Then
			startValues[4] = startValue5
			endValues[4] = endValue5
		End
	End

	Method Calculate:Float(startValue:Float, endValue:Float)
		' shortcut for start/end (also accounts for the case when startTime==endTime)
		' we check endTime first because if startTime==endTime==currentTime, we want to use endValue
		If currentTime >= endTime Then Return endValue
		If currentTime <= startTime Then Return startValue

		' how far through are we?
		Local progress:Float = Float(currentTime - startTime) / Float(endTime - startTime)

		Select easeType
			Case EASE_IN_DOUBLE
				Return Lerp(endValue, startValue, (1-progress)*(1-progress)*(1-progress)*(1-progress))
			Case EASE_IN
				Return Lerp(endValue, startValue, (1-progress)*(1-progress))
			Case EASE_IN_HALF
				Return Lerp(endValue, startValue, Pow(1-progress, 1.5))
			Case EASE_OUT
				Return Lerp(startValue, endValue, progress * progress)
			Case EASE_OUT_HALF
				Return Lerp(startValue, endValue, Pow(progress, 1.5))
			Case EASE_OUT_DOUBLE
				Return Lerp(startValue, endValue, progress*progress*progress*progress)
			Case EASE_IN_OUT
				Return startValue + (-2*(progress*progress*progress) + 3*(progress*progress)) * (endValue - startValue)
			Default
				Return Lerp(startValue, endValue, progress);
		End
	End

	Method Lerp:Float(startValue:Float, endValue:Float, progress:Float)
		Return startValue + (endValue-startValue) * progress
	End
End


MonkeyMax - Monkey's Shr is BlitzMax's Sar Fix

' Module trans.bmxtranslator
'
' Placed into the public domain 24/02/2011.
' No warranty implied; use at your own risk.

Import trans

Const KLUDGE_INTERFACES:=True

'To be used after reflection/semant immediately before translate
'
Function KludgeInterfaces( app:AppDecl )

	'find Object decl
	'
	Local odecl:ClassDecl
	For Local decl:=Eachin app.allSemantedDecls
		Local cdecl:=ClassDecl( decl )
		If cdecl And cdecl.munged="Object"
			odecl=cdecl
			Exit
		Endif
	Next

	'create Kludge class
	'
	Local idecl:=New ClassDecl
	idecl.ident="_Object"
	idecl.munged="_Object"
	idecl.attrs=DECL_SEMANTED
	idecl.superTy=Type.objectType
	idecl.superClass=odecl
	idecl.objectType=New ObjectType( idecl )

	Local inull:=New ConstExpr
	inull.exprType=idecl.objectType

	'find all interfaces/methods
	'
	Local ifaces:=New List<ClassDecl>
	Local icasts:=New StringMap<FuncDecl>
	Local imethods:=New StringMap<List<FuncDecl>>

	For Local decl:=Eachin app.Semanted

		Local cdecl:=ClassDecl( decl )

		If cdecl And cdecl.IsInterface()

			'create 'To' casting method...
			'
			Local fdecl:=New FuncDecl
			fdecl.ident="_To"+cdecl.ident
			fdecl.munged="_To"+cdecl.ident
			fdecl.attrs=DECL_SEMANTED|FUNC_METHOD
			fdecl.retType=idecl.objectType
			idecl.InsertDecl fdecl
			icasts.Set fdecl.munged,fdecl
			fdecl.AddStmt New ReturnStmt( inull )

			For Local decl:=Eachin cdecl.Semanted
				Local fdecl:=FuncDecl( decl )
				If fdecl
					Local list:=imethods.Get( fdecl.ident )
					If list
						Local found:=False
						For Local fdecl2:=Eachin list
							If fdecl.EqualsFunc( fdecl2 )
								found=True
								Exit
							Endif
						Next
						If found Continue
					Else
						list=New List<FuncDecl>
						imethods.Set fdecl.ident,list
					Endif
					'
					list.AddLast fdecl
					'
					'move decl to Kludge object...
					'
					fdecl.scope=Null
					idecl.InsertDecl fdecl
					fdecl.attrs&=~DECL_ABSTRACT
					If Not VoidType( fdecl.retType )
						Local expr:=New ConstExpr
						expr.exprType=fdecl.retType
						fdecl.AddStmt New ReturnStmt( expr )
					Endif
					'
				Endif
			Next
		Endif
	Next

	'update method overrides
	'
	For Local decl:=Eachin app.Semanted

		Local cdecl:=ClassDecl( decl )

		If cdecl And Not cdecl.IsInterface()

			'change super class to kludge class
			'
			If cdecl.superClass=odecl
				cdecl.superClass=idecl
			Endif

			'create cast ops for implemented interfaces
			'
			Local mdone:=New StringSet
			For Local iface:=Eachin cdecl.implmentsAll
				If mdone.Contains( iface.ident ) Continue
				mdone.Insert iface.ident
				Local fdecl:=New FuncDecl
				fdecl.ident="_To"+iface.ident
				fdecl.munged="_To"+iface.ident
				fdecl.attrs=DECL_SEMANTED|FUNC_METHOD
				fdecl.retType=idecl.objectType
				fdecl.overrides=icasts.Get( fdecl.munged )
				cdecl.InsertDecl fdecl
				Local expr:=New SelfExpr
				expr.exprType=cdecl.objectType
				fdecl.AddStmt New ReturnStmt( expr )
			Next

			'fix method overrides
			'
			For Local decl:=Eachin cdecl.Semanted
				Local fdecl:=FuncDecl( decl )
				If fdecl And fdecl.IsMethod() And Not fdecl.overrides
					Local list:=imethods.Get( fdecl.ident )
					If list
						For Local fdecl2:=Eachin list
							If fdecl.EqualsFunc( fdecl2 )
								fdecl.overrides=fdecl2
								Exit
							Endif
						Next
					Endif
				Endif
			Next
		Endif
	Next

	app.mainModule.InsertDecl idecl

	app.Semanted.AddFirst idecl
	app.allSemantedDecls.AddFirst idecl

End

Class BmxTranslator Extends CTranslator

	Method TransType$( ty:Type )
		If VoidType( ty ) Return "Int" ' no Void type in BlitzMax
		If BoolType( ty ) Return "Int"
		If IntType( ty ) Return "Int"
		If FloatType( ty ) Return "Float"
		If StringType( ty ) Return "String"
		If ArrayType( ty ) Return TransType( ArrayType(ty).elemType )+"[]"
		If ObjectType( ty )
			Local cdecl:=ty.GetClass()
			If KLUDGE_INTERFACES
				If cdecl.IsInterface() Or cdecl.munged="Object" Return "_Object"
			Endif
			Return cdecl.munged
		Endif
		InternalErr
	End

	Method TransValue$( ty:Type,value$ )
'		Print "value = "+value
		If value
			If IntType( ty ) And value.StartsWith( "$" ) Return "0x"+value[1..]
			If BoolType( ty ) Return "true"
			If NumericType( ty ) Return value
			If StringType( ty ) Return Enquote( value )
		Else
			If BoolType( ty ) Return "false"
			If NumericType( ty ) Return "0"
			If StringType( ty ) Return "~q~q"
			If ArrayType( ty )
				Local elemTy:=ArrayType( ty ).elemType
				Local t$="[0]"
				Local arrayOfArrays?=False
				Local count%=0
				While ArrayType( elemTy )
					count+=1
					elemTy=ArrayType( elemTy ).elemType
					t+=",[0]"
					arrayOfArrays=True
				Wend
				If arrayOfArrays
					'Return "["+t+"]"
					t = "["+t+"]"
				Else
					'Return t
					t = t
				End
'				Print "elemTy = "+elemTy
				If elemTy="Int" Or elemTy="Bool" Then
					Return t
				Else
					Return "New "+TransType( elemTy )+t
				Endif

			Endif
'			If ObjectType( ty ) Return "null"
			If ObjectType( ty ) Return TransType( ty ) + "(null)"
		Endif
		InternalErr
	End

	Method TransValDecl$( decl:ValDecl )
		Return decl.munged+":"+TransType( decl.type )
	End

	Method TransArgs$( args:Expr[] )
		Local t$
		For Local arg:=Eachin args
			If t t+=","
			t+=arg.Trans()
		Next
		Return Bra(t)
	End

	'***** Utility *****

	Method TransLocalDecl$( munged$,init:Expr )
		Return "local "+munged+":"+TransType( init.exprType )+"="+init.Trans()
	End

	Method EmitEnter( func$ )
		Emit "pushErr();"
	End

	Method EmitSetErr( info$ )
		Emit "_errInfo=~q"+info.Replace( "\","/" )+"~q;"
	End

	Method EmitLeave()
		Emit "popErr();"
	End

	'***** Declarations *****

	Method TransStatic$( decl:Decl )
		If decl.IsExtern()
			Return decl.munged
		Else If _env And decl.scope And decl.scope=_env.ClassScope
			Return decl.munged
		Else If ClassDecl( decl.scope )
			Return decl.scope.munged+"."+decl.munged
		Else If ModuleDecl( decl.scope )
			Return decl.munged
		Endif
		InternalErr
	End

	Method TransTemplateCast$( ty:Type,src:Type,expr$ )
		If ty.ActualType().EqualsType( src.ActualType() ) Return expr

		If Not ObjectType( src ) Err "Can't convert from "+src.ToString()+" to "+ty.ToString()

		'Return Bra( expr+" as "+TransType(ty) )
		Return TransType(ty)+Bra(expr)
	End

	Method TransGlobal$( decl:GlobalDecl )
		Return TransStatic( decl )
	End

	Method TransField$( decl:FieldDecl,lhs:Expr )
		Local t_lhs$="self"
		If lhs
			t_lhs=TransSubExpr( lhs )
		Endif
		Return t_lhs+"."+decl.munged
	End

	Method TransFunc$( decl:FuncDecl,args:Expr[],lhs:Expr )
		If decl.IsMethod()
			Local t_lhs$="self"
			If lhs
				t_lhs=TransSubExpr( lhs )
			Endif
			Return t_lhs+"."+decl.munged+TransArgs( args )
		Endif
		Return TransStatic( decl )+TransArgs( args )
	End

	Method TransSuperFunc$( decl:FuncDecl,args:Expr[] )
		Return "super."+decl.munged+TransArgs( args )
	End

	'***** Expressions *****

	Method TransConstExpr$( expr:ConstExpr )
		Return TransValue( expr.exprType,expr.value )
	End

	Method TransNewObjectExpr$( expr:NewObjectExpr )
		Local t$
		If expr.classDecl.munged<>"Object"
			t="(new "+expr.classDecl.munged+")"
		Else
			t="(new "+expr.classDecl.munged+"[0])"
		End
		If expr.ctor t+="."+expr.ctor.munged+TransArgs( expr.args )
		Return t

	End

	Method TransNewArrayExpr$( expr:NewArrayExpr )
		Local texpr$=expr.expr.Trans()
'		Print "TransNewArrayExpr texpr="+texpr
		Local elemTy:=ArrayType( expr.exprType ).elemType
		'
	'	If StringType( elemTy ) Return "bb_std_lang.stringArray"+Bra(texpr)
		'
		Local t$="["+texpr+"]"
		Local ma?=False
		While ArrayType( elemTy )
			elemTy=ArrayType( elemTy ).elemType
			t+=",new "+TransType( elemTy )+"[0]"
			ma = True
		Wend
		' TEST THIS BIT LATER!!!!!!!!!!!!!!!!!!!!!!!!<!<!>!<!><!

		If ma
			Return "["+"new "+TransType( elemTy )+t+"]"
		Else
			Return "new "+TransType( elemTy )+t
		End

	End

	Method TransSelfExpr$( expr:SelfExpr )
		Return "self"
	End

	Method TransCastExpr$( expr:CastExpr )
		Local dst:=expr.exprType
		Local src:=expr.expr.exprType
		Local texpr$=Bra( expr.expr.Trans() )

		If BoolType( dst )
			If BoolType( src ) Return texpr
			If IntType( src ) Return Bra( texpr )
			If FloatType( src ) Return Bra( texpr )
			If StringType( src ) Return Bra( texpr )
			If ArrayType( src ) Return Bra( texpr)
			If ObjectType( src ) Return Bra( texpr )
		Else If IntType( dst )
			If BoolType( src ) Return Bra( texpr )
			If IntType( src ) Return texpr
			If FloatType( src ) Return "Int("+Bra( texpr )+")"
'			If StringType( src ) Return Bra( texpr )
			If StringType( src ) Return "Int("+Bra( texpr )+")"
		Else If FloatType( dst )
'			If NumericType( src ) Return texpr
			If NumericType( src ) Return "Float("+texpr+")"
			'If StringType( src ) 	Return texpr
			If StringType( src ) Return "Float("+Bra( texpr )+")"
		Else If StringType( dst )
			If NumericType( src ) Return "String("+texpr+")"
			If StringType( src )  Return texpr
		Else If ObjectType( dst ) And ObjectType( src )
			If src.GetClass().ExtendsClass( dst.GetClass() )
				Return texpr
			Else If KLUDGE_INTERFACES And dst.GetClass().IsInterface()
				Return texpr+"._To"+dst.GetClass().ident+"()"
			Else
				Return Bra( "(" + TransType( dst ) + ")(" + texpr + ")" )
			Endif

		Endif
#rem

		If src.GetClass().ExtendsClass( dst.GetClass() )
			Return texpr
		Else If dst.GetClass().ExtendsClass( src.GetClass() )
 			'
			If KLUDGE_INTERFACES And dst.GetClass().IsInterface()
				Return texpr+"._To"+dst.GetClass().ident+"()"
			Endif
			'

'			Return Bra( texpr + " as "+TransType( dst ) )
			Return Bra( "(" + TransType( dst ) + ")(" + texpr + ")" )
		Endif
#end
		Err "BMax translator can't convert "+src.ToString()+" to "+dst.ToString()
	End

	Method TransUnaryExpr$( expr:UnaryExpr )
		Local pri=ExprPri( expr )
		Local t_expr$=TransSubExpr( expr.expr,pri )
'		Return TransUnaryOp( expr.op )+t_expr
		If( expr.op = "not" )
			Return "(" + TransUnaryOp( expr.op )+t_expr + ")"
		Else
			Return TransUnaryOp( expr.op )+t_expr
		Endif
	End

	Method TransBinaryExpr$( expr:BinaryExpr )
		Local pri=ExprPri( expr )
		Local t_lhs$=TransSubExpr( expr.lhs,pri )
		Local t_rhs$=TransSubExpr( expr.rhs,pri-1 )
		Local t_expr$=t_lhs+TransBinaryOp( expr.op,t_rhs )+t_rhs
		If expr.op="/" And IntType( expr.exprType ) t_expr=Bra( Bra(t_expr)+"|0" )
'		Return t_expr
		If( expr.op="and" Or expr.op="or" )
			Return "(" + t_expr + ")"
		Else
			Return t_expr
		Endif
	End

	Method TransIndexExpr$( expr:IndexExpr )
		Local t_expr:=TransSubExpr( expr.expr )
		If StringType( expr.expr.exprType )
			Local t_index:=expr.index.Trans()
			'Return t_expr+".charCodeAt("+t_index+")"
			'Return t_expr+".Find("+t_expr+","+t_index+")"
			Return t_expr+"["+t_index+"]"
'			Return "Int("+t_expr+"["+t_index+"])"
		Else If ENV_CONFIG="debug"
			Local t_index:=TransExprNS( expr.index )
			Return t_expr+"["+t_index+"]"
		Else
			Local t_index:=expr.index.Trans()
			Return t_expr+"["+t_index+"]"
		Endif
	End
#Rem
	Method TransSliceExpr$( expr:SliceExpr )
		Local t_expr$=TransSubExpr( expr.expr )
		Local t_args$="0"
		If Not expr.from And Not expr.term
			Return t_expr+"[..]"
		Endif
		If expr.from t_args=expr.from.Trans()
'		If expr.term t_args+=","+expr.term.Trans()
		t_args+=".."
		If expr.term t_args+="("+expr.term.Trans()+")"
'		Return t_expr+".slice("+t_args+")"
		If StringType( expr.exprType )

			Return "bb_std_lang.slice("+expr.exprType+","+expr.from+","+expr.term+")"
		Endif
		Return t_expr+"["+t_args+"]"
		InternalErr
	End

	Method TransSliceExpr$( expr:SliceExpr )
		Local texpr$=expr.expr.Trans()
		Local from$=",0",term$
		If expr.from from=","+expr.from.Trans()
		If expr.term term=","+expr.term.Trans()
		If ArrayType( expr.exprType )
			Return "(("+TransType( expr.exprType )+")bb_std_lang.sliceArray"+Bra( texpr+from+term )+")"
		Else If StringType( expr.exprType )
			Return "bb_std_lang.slice("+texpr+from+term+")"
		Endif
		InternalErr
	End
#End
	Method TransSliceExpr$( expr:SliceExpr )
		If ArrayType( expr.exprType )
			Local t_expr$=TransSubExpr( expr.expr )
			Local t_args$="0"
			If Not expr.from And Not expr.term
				Return t_expr+"[..]"
			Endif
			If expr.from t_args=expr.from.Trans()
	'		If expr.term t_args+=","+expr.term.Trans()
			t_args+=".."
			If expr.term t_args+="("+expr.term.Trans()+")"
	'		Return t_expr+".slice("+t_args+")"
			Return t_expr+"["+t_args+"]"
		Else If StringType( expr.exprType )
			Local texpr$=expr.expr.Trans()
			Local from$=",0",term$
			If expr.from from=","+expr.from.Trans()
			If expr.term term=","+expr.term.Trans()

			Return "slice_string("+texpr+from+term+")"
		Endif
		InternalErr
	End

	Method TransArrayExpr$( expr:ArrayExpr )
		Local t$
		For Local elem:=Eachin expr.exprs
			If t t+=","
			t+=elem.Trans()
		Next
		Return "["+t+"]"
	End

	Method TransIntrinsicExpr$( decl:Decl,expr:Expr,args:Expr[] )

		Local texpr$,arg0$,arg1$,arg2$

		If expr texpr=TransSubExpr( expr )

		If args.Length>0 And args[0] arg0=args[0].Trans()
		If args.Length>1 And args[1] arg1=args[1].Trans()
		If args.Length>2 And args[2] arg2=args[2].Trans()

		Local id$=decl.munged[1..]

		Select id

		'global functions
		Case "print" Return "print("+arg0+")" ' done
		Case "error" Return "error("+arg0+")"

		'string/array methods
		Case "length" Return texpr+".length" ' tested and works

		'array methods ' TODO!!!
		Case "resize"
			Local ty:=ArrayType( expr.exprType ).elemType
			If BoolType( ty ) Return "resize_int_array"+Bra( texpr+","+arg0 ) ' bools are ints in BlitzMax!
			If IntType( ty ) Return "resize_int_array"+Bra( texpr+","+arg0 ) ' done
			If FloatType( ty ) Return "resize_float_array"+Bra( texpr+","+arg0 ) ' done
			If StringType( ty ) Return "resize_string_array"+Bra( texpr+","+arg0 ) ' done
			If ArrayType( ty ) Return "resize_array_array_"+ArrayType( ty ).elemType+Bra( texpr+","+arg0 )
'			If ObjectType( ty ) Return "resize_object_array"+Bra( TransType(ty )+Bra (texpr)+","+arg0 )
			If ObjectType( ty ) Return texpr+"[.."+arg0+"]"
			InternalErr

		'string methods
		' Done all for BMax
		Case "compare" Return texpr+".Compare"+Bra( arg0 )
		Case "find" Return texpr+".Find"+Bra( arg0+","+arg1 )
		Case "findlast" Return texpr+".FindLast"+Bra( arg0 )
		Case "findlast2" Return texpr+".FindLast"+Bra( arg0+","+arg1 )
		Case "trim" Return texpr+".Trim()"
		Case "join" Return texpr+".Join"+Bra(arg0)
		Case "split" Return texpr+".Split"+Bra( arg0 )
		Case "replace" Return texpr+".Replace"+Bra(arg0+","+arg1)
		Case "tolower" Return texpr+".ToLower()"
		Case "toupper" Return texpr+".ToUpper()"
		Case "contains" Return texpr+".Contains"+Bra( arg0 )
		Case "startswith" Return texpr+".StartsWith"+Bra( arg0 )
		Case "endswith" Return texpr+".EndsWith"+Bra( arg0 )

		'string functions
'		Case "fromchar" Return "String.fromCharCode"+Bra( arg0 )
		Case "fromchar" Return "Chr"+Bra( arg0 )

		' ** TO-DO **
		' BlitzMax angle stuff isnt proper, need to minus 90 I think from the angle!

		'trig functions - degrees
		' Done all for BMax
		Case "sin","cos","tan" Return id+Bra(arg0)' "Math."+id+Bra( Bra( arg0 )+"*D2R" )
		Case "asin","acos","atan" Return id+Bra(arg0)' Bra( "Math."+id+Bra( arg0 )+"*R2D" )
		Case "atan2" Return id+Bra(arg0+","+arg1) 'Bra( "Math."+id+Bra( arg0+","+arg1 )+"*R2D" )

		'trig functions - radians
		' Done all for BMax
		Case "sinr" Return id[..-1]+Bra( Bra( arg0 +"*R2D") )
		Case "cosr" Return id[..-1]+Bra( Bra( arg0 +"*R2D") )
		Case "tanr" Return id[..-1]+Bra( Bra( arg0 +"*R2D") )
		Case "asinr" Return id[..-1]+Bra( arg0 )+"*D2R"
		Case "acosr" Return id[..-1]+Bra( arg0 )+"*D2R"
		Case "atanr" Return id[..-1]+Bra( arg0 )+"*D2R"
		Case "atan2r" Return id[..-1]+Bra(arg0+","+arg1)+"*D2R"

		'misc math functions
		' Done all for BMax
		Case "floor","ceil","log","exp" Return id+Bra( arg0 )
		Case "sqrt" Return "Sqr"+Bra(arg0)
		Case "pow" Return Bra(arg0)+"^"+arg1

		End Select

		InternalErr
	End

	'***** Statements *****

	Method TransAssignStmt$( stmt:AssignStmt )
	#rem
		If ENV_CONFIG="debug"
			Local ie:=IndexExpr( stmt.lhs )
			If ie
				Local t_rhs:=stmt.rhs.Trans()
				Local t_expr:=ie.expr.Trans()
				Local t_index:=TransExprNS( ie.index )
				Emit "dbg_array("+t_expr+","+t_index+")["+t_index+"]"+stmt.op+t_rhs
				Return
			Endif
		Endif
	#End
		Return Super.TransAssignStmt( stmt )
	End

	'***** Declarations *****

	Method EmitFuncDecl( decl:FuncDecl )
		BeginLocalScope
'		PushMungScope

		'Find decl we override
		Local odecl:=decl
		While odecl.overrides
			odecl=odecl.overrides
		Wend

		'Generate 'args' string and arg casts
		Local args$
		Local argCasts:=New StringStack
		For Local i=0 Until decl.argDecls.Length
			Local arg:=decl.argDecls[i]
			Local oarg:=odecl.argDecls[i]
			MungDecl arg
			If args args+=","
			args+=arg.munged+":"+TransType( oarg.type )
			If arg.type.EqualsType( oarg.type ) Continue
			Local t$=arg.munged
			arg.munged=""
			MungDecl arg
			'argCasts.Push "Local "+arg.munged+":"+TransType(arg.ty)+"="+t+" new "+TransType(arg.ty)+";"
			argCasts.Push "Local "+arg.munged+":"+TransType(arg.type)+"="+TransType(arg.type)+Bra(t)
		Next

'		Local t$=" "+decl.munged+":"+TransType( odecl.retType )+Bra( args )
		Local t$
		If VoidType( odecl.retType )
			t=" "+decl.munged+Bra( args )
		Else
			t=" "+decl.munged+":"+TransType( odecl.retType )+Bra( args )
		Endif
		Local funcType$ = "Function"
		Local cdecl:=decl.ClassScope()
		If cdecl And cdecl.IsInterface()
'			Emit funcType+" "+t+";"

			Local q$
			funcType = "Method"
			q+=funcType+" "

			If decl.IsAbstract()
				Emit q+t+" Abstract"
			Else
				Emit q+t+""
			End

			If decl.IsAbstract()
				If VoidType( decl.retType )
				'	Emit "return 0;" ' return 0 as Void = Int for BlitzMax ;)
				Else
				'	Emit "return "+TransValue( decl.retType,"" )+";"
				Endif
			Else
				For Local t$=Eachin argCasts
					Emit t
				Next
				EmitBlock decl
			Endif
			If decl.IsAbstract()
				indent=indent[..indent.Length-1]
			Else
				Emit "End"+funcType
			End

		Else
			Local q$'="internal "
			If cdecl
			'	q="public "
				If decl.IsStatic()
					q+=funcType+" "
				Else
					funcType = "Method"
					q+=funcType+" "
				Endif
			'	If decl.overrides q+="override "
			Else
				q+=funcType+" "
			Endif
			If decl.IsAbstract()
				Emit q+t+" Abstract"
			Else
				Emit q+t+""
			End

			If decl.IsAbstract()
				If VoidType( decl.retType )
				'	Emit "return 0;" ' return 0 as Void = Int for BlitzMax ;)
				Else
				'	Emit "return "+TransValue( decl.retType,"" )+";"
				Endif
			Else
				For Local t$=Eachin argCasts
					Emit t
				Next
				EmitBlock decl
			Endif
			If decl.IsAbstract()
				indent=indent[..indent.Length-1]
			Else
				Emit "End"+funcType
			End

		Endif

		EndLocalScope
'		PopMungScope
	End

	'returns unreachable status!
	Method EmitBlock( block:BlockDecl )

		PushEnv block

		Local func:=FuncDecl( block )

		If func
			If func.IsAbstract() InternalErr
			If ENV_CONFIG<>"release" EmitEnter func.scope.ident+"."+func.ident
		Endif

		For Local stmt:Stmt=Eachin block.stmts

			_errInfo=stmt.errInfo

			If unreachable	' And ENV_LANG<>"as"
				'If stmt.errInfo Print "Unreachable:"+stmt.errInfo
				Exit
			Endif

			If ENV_CONFIG<>"release"
				Local rs:=ReturnStmt( stmt )
				If rs
					If rs.expr
						EmitSetErr stmt.errInfo
						Local t_expr:=TransExprNS( rs.expr )
						EmitLeave
						Emit "return "+t_expr+";"
					Else
						EmitLeave
						Emit "return;"
					Endif
					unreachable=True
					Continue
				Endif
				EmitSetErr stmt.errInfo
			Endif

			Local t$=stmt.Trans()
			If t Emit t+";"

		Next

		Local r=unreachable
		unreachable=False

		If func And Not r

			If ENV_CONFIG<>"release" EmitLeave

			If Not VoidType( func.retType )
				If func.IsCtor()
					Emit "return self;"
				Else
					If func.ModuleScope().IsStrict()
						_errInfo=func.errInfo
						Err "Missing return statement."
					Endif
					Emit "return "+TransValue( func.retType,"" )+";"
				Endif
			Endif

		Endif

		PopEnv

		Return r
	End

Method Enquote$( str$ )
	str=str.Replace( "~~","~~~~" )
	str=str.Replace( "~q","~~q" )
	str=str.Replace( "~n","~~n" )
	str=str.Replace( "~r","~~r" )
	str=str.Replace( "~t","~~t" )

	For Local i=0 Until str.Length
		If str[i]>=32 And str[i]<128 Continue
		Local t$,n=str[i]
		While n
			Local c=(n&15)+48
			If c>=58 c+=97-58
			t=String.FromChar( c )+t
			n=(n Shr 4) & $0fffffff
		Wend
		If Not t t="0"
		Select ENV_LANG
		Case "cpp"
			t="~qL~q\x"+t+"~qL~q"
		Default
			t="\u"+("0000"+t)[-4..]
		End
		str=str[..i]+t+str[i+1..]
		i+=t.Length-1
	Next
	Select ENV_LANG
	Case "cpp"
		str="L~q"+str+"~q"
	Default
		str="~q"+str+"~q"
	End
	Return str
End

	Method Emit( t$ )
		If Not t Return

		't=t.Replace( "\n","~~n" )

		If t.StartsWith( "EndIf" ) Or t.StartsWith( "EndFunction" ) Or t.StartsWith( "EndMethod" ) Or t.StartsWith( "EndType" ) Or t.StartsWith("Next") Or t.StartsWith("Else") Or t.StartsWith( "Wend" )
			indent=indent[..indent.Length-1]
		Endif
		lines.AddLast indent+t
		'code+=indent+t+"~n"
		If t.EndsWith( "Then" ) Or t.StartsWith( "Function" ) Or t.StartsWith( "Method" ) Or t.StartsWith( "Type" ) Or t.StartsWith("For") Or t.StartsWith("Else") Or t.StartsWith("While")
			indent+="~t"
		Endif
	End

	Method TransUnaryOp$( op$ )
'		Print "TransUnaryOp op="+op
		Select op
		Case "+" Return "+"
		Case "-" Return "-"
		Case "~~" Return op
		Case "not" Return op+" "
		End Select
		InternalErr
	End

	Method TransAssignOp$( op$ )
'		Print "TransAssignOp op="+op
		Select op
			Case "mod=" Return " :Mod "
			Case "shl=" Return " :shl "
			Case "shr=" Return " :sar " ' Monkey's Shr is BlitzMax's Sar
			Case "+=" Return " :+"
			Case "-=" Return " :-"
			Case "*=" Return " :*"
			Case "/=" Return " :/"
			Case "|=" Return " :|"
			Case "&=" Return " :&"
		End
		Return op
	End

	Method TransBinaryOp$( op$,rhs$ )
	#rem
		Select op
		Case "+","-"
			If rhs.StartsWith( op ) Return op+" "
			Return op
		Case "*","/" Return op
		Case "shl" Return op
		Case "shr" Return "sar" ' Monkey's Shr is BlitzMax's Sar
		Case "mod" Return op
		Case "and" Return op
		Case "or" Return op
		Case "=" Return op
		Case "<>" Return op
		Case "<","<=",">",">=" Return op
		Case "&","|" Return op
		Case "~~" Return "^"
		End Select
	#end
		Select op
			Case
				"shr" Return " sar " ' Monkey's Shr is BlitzMax's Sar
			Default
				Return " " + op + " "
		End Select

		InternalErr
	End

	Method TransIfStmt$( stmt:IfStmt )

		If ConstExpr( stmt.expr )
			If ConstExpr( stmt.expr ).value
				If EmitBlock( stmt.thenBlock ) unreachable=True
			Else If Not stmt.elseBlock.stmts.IsEmpty()
				If EmitBlock( stmt.elseBlock ) unreachable=True
			Endif
		Else If Not stmt.elseBlock.stmts.IsEmpty()
			Emit "If"+Bra( stmt.expr.Trans() )+" Then"
			Local unr=EmitBlock( stmt.thenBlock )
			Emit "Else"
			Local unr2=EmitBlock( stmt.elseBlock )
			Emit "EndIf"
			If unr And unr2 unreachable=True
		Else
			Emit "If"+Bra( stmt.expr.Trans() )+" Then"
			Local unr=EmitBlock( stmt.thenBlock )
			Emit "EndIf"
		Endif
	End

	Method EmitClassDecl( classDecl:ClassDecl )

		If KLUDGE_INTERFACES
			If classDecl.IsInterface() Return
		Endif

'		If classDecl.IsTemplateInst()
'			InternalErr
'		Endif

		Local classid$=classDecl.munged
		Local superid$=classDecl.superClass.munged

'		Print "superid = "+superid + " " + classid

		If classDecl.IsInterface()

			Local bases$

			If Not KLUDGE_INTERFACES
				For Local iface:=Eachin classDecl.implments
					If bases bases+="," Else bases=" extends "
					bases+=iface.munged
				Next
			Endif

			Local ab$=""
			If classDecl.IsAbstract()
				ab="Abstract"
			End

			If superid<>"Object"
				Emit "Type "+classid+" extends "+superid+bases + " " + ab
			Else
				Emit "Type "+classid + " " + ab
			Endif
'			Emit "interface "+classid+bases+"{"

			For Local decl:=Eachin classDecl.Semanted
				Local fdecl:=FuncDecl( decl )
				If Not fdecl Continue
				EmitFuncDecl fdecl
			Next
			Emit "EndType"
'			Emit "}"
			Return
		Endif

		Local bases$

		If Not KLUDGE_INTERFACES
			For Local iface:=Eachin classDecl.implments
  '			If bases bases+="," Else bases=" implements "
				If bases bases+="," Else bases=" extends "
				bases+=iface.munged
			Next
		Endif

		Local ab$=""
		If classDecl.IsAbstract()
			ab="Abstract"
		End

		If superid<>"Object"
			Emit "Type "+classid+" extends "+superid+bases + " " + ab
		Elseif bases<>""
			Emit "Type "+classid+bases + " " + ab
		Else
			Emit "Type "+classid + " " + ab
		Endif

		'members...
		For Local decl:=Eachin classDecl.Semanted
			Local tdecl:=FieldDecl( decl )
			If tdecl
				Emit "Field "+TransValDecl( tdecl )+"="+tdecl.init.Trans()+";"
				Continue
			Endif

			Local gdecl:=GlobalDecl( decl )
			If gdecl
				Emit "Global "+TransValDecl( gdecl )+";"
				Continue
			Endif

			Local fdecl:=FuncDecl( decl )
			If fdecl
				EmitFuncDecl fdecl
				Continue
			Endif
		Next

		Emit "EndType"
	End

	Method TransWhileStmt$( stmt:WhileStmt )
		Local nbroken=broken

		Emit "While"+Bra( stmt.expr.Trans() )+""
		Local unr=EmitBlock( stmt.block )
		Emit "Wend"

		If broken=nbroken And ConstExpr( stmt.expr ) And ConstExpr( stmt.expr ).value unreachable=True
		broken=nbroken
	End

	Method TransRepeatStmt$( stmt:RepeatStmt )
		Local nbroken=broken

		Emit "Repeat"
		Local unr=EmitBlock( stmt.block )
		Emit "Until ("+Bra( stmt.expr.Trans() )+");"

		If broken=nbroken And ConstExpr( stmt.expr ) And Not ConstExpr( stmt.expr ).value unreachable=True
		broken=nbroken
	End

	Method TransForStmt$( stmt:ForStmt )
		Local nbroken=broken

		Local init$=stmt.init.Trans()
		Local expr$=stmt.expr.Trans()
		Local incr$=stmt.incr.Trans()

		Local splitExpr:= expr.Split(" ")
		Local splitIncr:= incr.Split(" ")
		Local bmaxExpr$ = splitExpr[1]
		Local bmaxIncr$ = splitIncr[2]

		If bmaxExpr="<=" Or bmaxExpr=">="
			bmaxExpr = "To"
		Else If bmaxExpr="<" Or bmaxExpr=">"
			bmaxExpr = "Until"
		End

'		If( splitExpr.Length > 3 )
			Local out$="For "+init+" "+bmaxExpr +" "
			Local sc:Int=2
			Local first:Bool = True
			While sc < splitExpr.Length
				If first
					first=False
				Else
					out+=" "
				Endif
				out+=splitExpr[sc]
				sc+=1
			Wend
			out+=" Step "+ bmaxIncr
			Emit out
'		Else
'			Emit "For "+init+" "+bmaxExpr +" "+splitExpr[2]+ " Step "+ bmaxIncr
'		Endif
		Local unr=EmitBlock( stmt.block )
		Emit "Next"

		If broken=nbroken And ConstExpr( stmt.expr ) And ConstExpr( stmt.expr ).value unreachable=True
		broken=nbroken
	End

	Method TransBreakStmt$( stmt:BreakStmt )
		unreachable=True
		broken+=1
		Return "Exit"
	End

	Method TransApp$( app:AppDecl )

		If KLUDGE_INTERFACES
			KludgeInterfaces app
		Endif

'		app.mainFunc.munged="bbMain"
		app.mainFunc.munged="bbMain2"

		For Local decl:=Eachin app.imported.Values()
			MungDecl decl
		Next

		For Local decl:=Eachin app.Semanted

			MungDecl decl

			Local cdecl:=ClassDecl( decl )
			If Not cdecl Continue

			BeginLocalScope
'			PushMungScope

			For Local decl:=Eachin cdecl.Semanted
				If FuncDecl( decl ) And FuncDecl( decl ).IsCtor()
					decl.ident=cdecl.ident+"_"+decl.ident
				Endif
				MungDecl decl
			Next

			EndLocalScope
'			PopMungScope
		Next

		'decls
		'
		For Local decl:=Eachin app.Semanted

			Local gdecl:=GlobalDecl( decl )
			If gdecl
				Emit "Global "+TransValDecl( gdecl )+";"
				Continue
			Endif

			Local fdecl:=FuncDecl( decl )
			If fdecl
				EmitFuncDecl fdecl
				Continue
			Endif

			Local cdecl:=ClassDecl( decl )
			If cdecl
				EmitClassDecl cdecl
				Continue
			Endif
		Next

		Emit "Function bbInit()"
		For Local decl:=Eachin app.semantedGlobals
			Emit TransGlobal( decl )+"="+decl.init.Trans()+";"
		Next
		Emit "EndFunction"

		Emit "Function bbMain:Int()"
		Emit "~tLocal r:Int=bbMain2();"
		Local found:Bool = False
		For Local s:String = Eachin lines
			If s.Contains( "bb_app_device" )
				found = True
				Exit
			Endif
		Next
		If found
			Emit "~tbb_app_device.Setup();"
		Endif
		Emit "~treturn r;"
		Emit "EndFunction"

		Return JoinLines()
	End

	Method MungDecl( decl:Decl )

		If decl.munged Return

		Local fdecl:FuncDecl=FuncDecl( decl )
		If fdecl And fdecl.IsMethod() Return MungMethodDecl( fdecl )

		Local mscope$,cscope$
		If decl.ClassScope() cscope=decl.ClassScope().munged
		If decl.ModuleScope() mscope=decl.ModuleScope().munged

		Local id:=decl.ident,munged$,scope$

		If LocalDecl( decl )
			scope="$"
			munged="t_"+id
		Else If FieldDecl( decl )
			scope=cscope
			munged="f_"+id
		Else If GlobalDecl( decl ) Or FuncDecl( decl )
			If cscope And ENV_LANG<>"js"
				scope=cscope
				munged="g_"+id
			Else If cscope
				munged=cscope+"_"+id
			Else
				munged=mscope+"_"+id
			Endif
		Else If ClassDecl( decl )
			munged=mscope+"_"+id
		Else If ModuleDecl( decl )
			munged="bb_"+id
		Else
			Print "OOPS1"
			InternalErr
		Endif

		''' Modify the "munged" variable:
		''' change uppercase characters to _1

		Local newmunged:String
		For Local i:Int = 0 Until munged.Length
			Local c:Int = munged[i]
			If c = "_1" Then
				newmunged += "_1" + "_1"
			Elseif c>=65 And c<=90 Then
				newmunged += "_1" + String.FromChar(c)
			Else
				newmunged += String.FromChar(c)
			End
		Next
		munged = newmunged

		Local set:=mungedScopes.Get( scope )
		If set
			If set.Contains( munged )
				Local id=1
				Repeat
					id+=1
					Local t$=munged+String(id)
					If set.Contains(t) Continue
					munged=t
					Exit
				Forever
			Endif
		Else
			If scope="$"
				Print "OOPS2"
				InternalErr
			Endif
			set=New StringSet
			mungedScopes.Set scope,set
		Endif
		set.Insert munged
		decl.munged=munged
	End

End

' Module trans.bmxtranslator
'
' Placed into the public domain 24/02/2011.
' No warranty implied; use at your own risk.

Import trans

Const KLUDGE_INTERFACES:=True

'To be used after reflection/semant immediately before translate
'
Function KludgeInterfaces( app:AppDecl )

	'find Object decl
	'
	Local odecl:ClassDecl
	For Local decl:=Eachin app.allSemantedDecls
		Local cdecl:=ClassDecl( decl )
		If cdecl And cdecl.munged="Object"
			odecl=cdecl
			Exit
		Endif
	Next

	'create Kludge class
	'
	Local idecl:=New ClassDecl
	idecl.ident="_Object"
	idecl.munged="_Object"
	idecl.attrs=DECL_SEMANTED
	idecl.superTy=Type.objectType
	idecl.superClass=odecl
	idecl.objectType=New ObjectType( idecl )

	Local inull:=New ConstExpr
	inull.exprType=idecl.objectType

	'find all interfaces/methods
	'
	Local ifaces:=New List<ClassDecl>
	Local icasts:=New StringMap<FuncDecl>
	Local imethods:=New StringMap<List<FuncDecl>>

	For Local decl:=Eachin app.Semanted

		Local cdecl:=ClassDecl( decl )

		If cdecl And cdecl.IsInterface()

			'create 'To' casting method...
			'
			Local fdecl:=New FuncDecl
			fdecl.ident="_To"+cdecl.ident
			fdecl.munged="_To"+cdecl.ident
			fdecl.attrs=DECL_SEMANTED|FUNC_METHOD
			fdecl.retType=idecl.objectType
			idecl.InsertDecl fdecl
			icasts.Set fdecl.munged,fdecl
			fdecl.AddStmt New ReturnStmt( inull )

			For Local decl:=Eachin cdecl.Semanted
				Local fdecl:=FuncDecl( decl )
				If fdecl
					Local list:=imethods.Get( fdecl.ident )
					If list
						Local found:=False
						For Local fdecl2:=Eachin list
							If fdecl.EqualsFunc( fdecl2 )
								found=True
								Exit
							Endif
						Next
						If found Continue
					Else
						list=New List<FuncDecl>
						imethods.Set fdecl.ident,list
					Endif
					'
					list.AddLast fdecl
					'
					'move decl to Kludge object...
					'
					fdecl.scope=Null
					idecl.InsertDecl fdecl
					fdecl.attrs&=~DECL_ABSTRACT
					If Not VoidType( fdecl.retType )
						Local expr:=New ConstExpr
						expr.exprType=fdecl.retType
						fdecl.AddStmt New ReturnStmt( expr )
					Endif
					'
				Endif
			Next
		Endif
	Next

	'update method overrides
	'
	For Local decl:=Eachin app.Semanted

		Local cdecl:=ClassDecl( decl )

		If cdecl And Not cdecl.IsInterface()

			'change super class to kludge class
			'
			If cdecl.superClass=odecl
				cdecl.superClass=idecl
			Endif

			'create cast ops for implemented interfaces
			'
			Local mdone:=New StringSet
			For Local iface:=Eachin cdecl.implmentsAll
				If mdone.Contains( iface.ident ) Continue
				mdone.Insert iface.ident
				Local fdecl:=New FuncDecl
				fdecl.ident="_To"+iface.ident
				fdecl.munged="_To"+iface.ident
				fdecl.attrs=DECL_SEMANTED|FUNC_METHOD
				fdecl.retType=idecl.objectType
				fdecl.overrides=icasts.Get( fdecl.munged )
				cdecl.InsertDecl fdecl
				Local expr:=New SelfExpr
				expr.exprType=cdecl.objectType
				fdecl.AddStmt New ReturnStmt( expr )
			Next

			'fix method overrides
			'
			For Local decl:=Eachin cdecl.Semanted
				Local fdecl:=FuncDecl( decl )
				If fdecl And fdecl.IsMethod() And Not fdecl.overrides
					Local list:=imethods.Get( fdecl.ident )
					If list
						For Local fdecl2:=Eachin list
							If fdecl.EqualsFunc( fdecl2 )
								fdecl.overrides=fdecl2
								Exit
							Endif
						Next
					Endif
				Endif
			Next
		Endif
	Next

	app.mainModule.InsertDecl idecl

	app.Semanted.AddFirst idecl
	app.allSemantedDecls.AddFirst idecl

End

Class BmxTranslator Extends CTranslator

	Method TransType$( ty:Type )
		If VoidType( ty ) Return "Int" ' no Void type in BlitzMax
		If BoolType( ty ) Return "Int"
		If IntType( ty ) Return "Int"
		If FloatType( ty ) Return "Float"
		If StringType( ty ) Return "String"
		If ArrayType( ty ) Return TransType( ArrayType(ty).elemType )+"[]"
		If ObjectType( ty )
			Local cdecl:=ty.GetClass()
			If KLUDGE_INTERFACES
				If cdecl.IsInterface() Or cdecl.munged="Object" Return "_Object"
			Endif
			Return cdecl.munged
		Endif
		InternalErr
	End

	Method TransValue$( ty:Type,value$ )
'		Print "value = "+value
		If value
			If IntType( ty ) And value.StartsWith( "$" ) Return "0x"+value[1..]
			If BoolType( ty ) Return "true"
			If NumericType( ty ) Return value
			If StringType( ty ) Return Enquote( value )
		Else
			If BoolType( ty ) Return "false"
			If NumericType( ty ) Return "0"
			If StringType( ty ) Return "~q~q"
			If ArrayType( ty )
				Local elemTy:=ArrayType( ty ).elemType
				Local t$="[0]"
				Local arrayOfArrays?=False
				Local count%=0
				While ArrayType( elemTy )
					count+=1
					elemTy=ArrayType( elemTy ).elemType
					t+=",[0]"
					arrayOfArrays=True
				Wend
				If arrayOfArrays
					'Return "["+t+"]"
					t = "["+t+"]"
				Else
					'Return t
					t = t
				End
'				Print "elemTy = "+elemTy
				If elemTy="Int" Or elemTy="Bool" Then
					Return t
				Else
					Return "New "+TransType( elemTy )+t
				Endif

			Endif
'			If ObjectType( ty ) Return "null"
			If ObjectType( ty ) Return TransType( ty ) + "(null)"
		Endif
		InternalErr
	End

	Method TransValDecl$( decl:ValDecl )
		Return decl.munged+":"+TransType( decl.type )
	End

	Method TransArgs$( args:Expr[] )
		Local t$
		For Local arg:=Eachin args
			If t t+=","
			t+=arg.Trans()
		Next
		Return Bra(t)
	End

	'***** Utility *****

	Method TransLocalDecl$( munged$,init:Expr )
		Return "local "+munged+":"+TransType( init.exprType )+"="+init.Trans()
	End

	Method EmitEnter( func$ )
		Emit "pushErr();"
	End

	Method EmitSetErr( info$ )
		Emit "_errInfo=~q"+info.Replace( "\","/" )+"~q;"
	End

	Method EmitLeave()
		Emit "popErr();"
	End

	'***** Declarations *****

	Method TransStatic$( decl:Decl )
		If decl.IsExtern()
			Return decl.munged
		Else If _env And decl.scope And decl.scope=_env.ClassScope
			Return decl.munged
		Else If ClassDecl( decl.scope )
			Return decl.scope.munged+"."+decl.munged
		Else If ModuleDecl( decl.scope )
			Return decl.munged
		Endif
		InternalErr
	End

	Method TransTemplateCast$( ty:Type,src:Type,expr$ )
		If ty.ActualType().EqualsType( src.ActualType() ) Return expr

		If Not ObjectType( src ) Err "Can't convert from "+src.ToString()+" to "+ty.ToString()

		'Return Bra( expr+" as "+TransType(ty) )
		Return TransType(ty)+Bra(expr)
	End

	Method TransGlobal$( decl:GlobalDecl )
		Return TransStatic( decl )
	End

	Method TransField$( decl:FieldDecl,lhs:Expr )
		Local t_lhs$="self"
		If lhs
			t_lhs=TransSubExpr( lhs )
		Endif
		Return t_lhs+"."+decl.munged
	End

	Method TransFunc$( decl:FuncDecl,args:Expr[],lhs:Expr )
		If decl.IsMethod()
			Local t_lhs$="self"
			If lhs
				t_lhs=TransSubExpr( lhs )
			Endif
			Return t_lhs+"."+decl.munged+TransArgs( args )
		Endif
		Return TransStatic( decl )+TransArgs( args )
	End

	Method TransSuperFunc$( decl:FuncDecl,args:Expr[] )
		Return "super."+decl.munged+TransArgs( args )
	End

	'***** Expressions *****

	Method TransConstExpr$( expr:ConstExpr )
		Return TransValue( expr.exprType,expr.value )
	End

	Method TransNewObjectExpr$( expr:NewObjectExpr )
		Local t$
		If expr.classDecl.munged<>"Object"
			t="(new "+expr.classDecl.munged+")"
		Else
			t="(new "+expr.classDecl.munged+"[0])"
		End
		If expr.ctor t+="."+expr.ctor.munged+TransArgs( expr.args )
		Return t

	End

	Method TransNewArrayExpr$( expr:NewArrayExpr )
		Local texpr$=expr.expr.Trans()
'		Print "TransNewArrayExpr texpr="+texpr
		Local elemTy:=ArrayType( expr.exprType ).elemType
		'
	'	If StringType( elemTy ) Return "bb_std_lang.stringArray"+Bra(texpr)
		'
		Local t$="["+texpr+"]"
		Local ma?=False
		While ArrayType( elemTy )
			elemTy=ArrayType( elemTy ).elemType
			t+=",new "+TransType( elemTy )+"[0]"
			ma = True
		Wend
		' TEST THIS BIT LATER!!!!!!!!!!!!!!!!!!!!!!!!<!<!>!<!><!

		If ma
			Return "["+"new "+TransType( elemTy )+t+"]"
		Else
			Return "new "+TransType( elemTy )+t
		End

	End

	Method TransSelfExpr$( expr:SelfExpr )
		Return "self"
	End

	Method TransCastExpr$( expr:CastExpr )
		Local dst:=expr.exprType
		Local src:=expr.expr.exprType
		Local texpr$=Bra( expr.expr.Trans() )

		If BoolType( dst )
			If BoolType( src ) Return texpr
			If IntType( src ) Return Bra( texpr )
			If FloatType( src ) Return Bra( texpr )
			If StringType( src ) Return Bra( texpr )
			If ArrayType( src ) Return Bra( texpr)
			If ObjectType( src ) Return Bra( texpr )
		Else If IntType( dst )
			If BoolType( src ) Return Bra( texpr )
			If IntType( src ) Return texpr
			If FloatType( src ) Return "Int("+Bra( texpr )+")"
'			If StringType( src ) Return Bra( texpr )
			If StringType( src ) Return "Int("+Bra( texpr )+")"
		Else If FloatType( dst )
'			If NumericType( src ) Return texpr
			If NumericType( src ) Return "Float("+texpr+")"
			'If StringType( src ) 	Return texpr
			If StringType( src ) Return "Float("+Bra( texpr )+")"
		Else If StringType( dst )
			If NumericType( src ) Return "String("+texpr+")"
			If StringType( src )  Return texpr
		Else If ObjectType( dst ) And ObjectType( src )
			If src.GetClass().ExtendsClass( dst.GetClass() )
				Return texpr
			Else If KLUDGE_INTERFACES And dst.GetClass().IsInterface()
				Return texpr+"._To"+dst.GetClass().ident+"()"
			Else
				Return Bra( "(" + TransType( dst ) + ")(" + texpr + ")" )
			Endif

		Endif
#rem

		If src.GetClass().ExtendsClass( dst.GetClass() )
			Return texpr
		Else If dst.GetClass().ExtendsClass( src.GetClass() )
 			'
			If KLUDGE_INTERFACES And dst.GetClass().IsInterface()
				Return texpr+"._To"+dst.GetClass().ident+"()"
			Endif
			'

'			Return Bra( texpr + " as "+TransType( dst ) )
			Return Bra( "(" + TransType( dst ) + ")(" + texpr + ")" )
		Endif
#end
		Err "BMax translator can't convert "+src.ToString()+" to "+dst.ToString()
	End

	Method TransUnaryExpr$( expr:UnaryExpr )
		Local pri=ExprPri( expr )
		Local t_expr$=TransSubExpr( expr.expr,pri )
'		Return TransUnaryOp( expr.op )+t_expr
		If( expr.op = "not" )
			Return "(" + TransUnaryOp( expr.op )+t_expr + ")"
		Else
			Return TransUnaryOp( expr.op )+t_expr
		Endif
	End

	Method TransBinaryExpr$( expr:BinaryExpr )
		Local pri=ExprPri( expr )
		Local t_lhs$=TransSubExpr( expr.lhs,pri )
		Local t_rhs$=TransSubExpr( expr.rhs,pri-1 )
		Local t_expr$=t_lhs+TransBinaryOp( expr.op,t_rhs )+t_rhs
		If expr.op="/" And IntType( expr.exprType ) t_expr=Bra( Bra(t_expr)+"|0" )
'		Return t_expr
		If( expr.op="and" Or expr.op="or" )
			Return "(" + t_expr + ")"
		Else
			Return t_expr
		Endif
	End

	Method TransIndexExpr$( expr:IndexExpr )
		Local t_expr:=TransSubExpr( expr.expr )
		If StringType( expr.expr.exprType )
			Local t_index:=expr.index.Trans()
			'Return t_expr+".charCodeAt("+t_index+")"
			'Return t_expr+".Find("+t_expr+","+t_index+")"
			Return t_expr+"["+t_index+"]"
'			Return "Int("+t_expr+"["+t_index+"])"
		Else If ENV_CONFIG="debug"
			Local t_index:=TransExprNS( expr.index )
			Return t_expr+"["+t_index+"]"
		Else
			Local t_index:=expr.index.Trans()
			Return t_expr+"["+t_index+"]"
		Endif
	End
#Rem
	Method TransSliceExpr$( expr:SliceExpr )
		Local t_expr$=TransSubExpr( expr.expr )
		Local t_args$="0"
		If Not expr.from And Not expr.term
			Return t_expr+"[..]"
		Endif
		If expr.from t_args=expr.from.Trans()
'		If expr.term t_args+=","+expr.term.Trans()
		t_args+=".."
		If expr.term t_args+="("+expr.term.Trans()+")"
'		Return t_expr+".slice("+t_args+")"
		If StringType( expr.exprType )

			Return "bb_std_lang.slice("+expr.exprType+","+expr.from+","+expr.term+")"
		Endif
		Return t_expr+"["+t_args+"]"
		InternalErr
	End

	Method TransSliceExpr$( expr:SliceExpr )
		Local texpr$=expr.expr.Trans()
		Local from$=",0",term$
		If expr.from from=","+expr.from.Trans()
		If expr.term term=","+expr.term.Trans()
		If ArrayType( expr.exprType )
			Return "(("+TransType( expr.exprType )+")bb_std_lang.sliceArray"+Bra( texpr+from+term )+")"
		Else If StringType( expr.exprType )
			Return "bb_std_lang.slice("+texpr+from+term+")"
		Endif
		InternalErr
	End
#End
	Method TransSliceExpr$( expr:SliceExpr )
		If ArrayType( expr.exprType )
			Local t_expr$=TransSubExpr( expr.expr )
			Local t_args$="0"
			If Not expr.from And Not expr.term
				Return t_expr+"[..]"
			Endif
			If expr.from t_args=expr.from.Trans()
	'		If expr.term t_args+=","+expr.term.Trans()
			t_args+=".."
			If expr.term t_args+="("+expr.term.Trans()+")"
	'		Return t_expr+".slice("+t_args+")"
			Return t_expr+"["+t_args+"]"
		Else If StringType( expr.exprType )
			Local texpr$=expr.expr.Trans()
			Local from$=",0",term$
			If expr.from from=","+expr.from.Trans()
			If expr.term term=","+expr.term.Trans()

			Return "slice_string("+texpr+from+term+")"
		Endif
		InternalErr
	End

	Method TransArrayExpr$( expr:ArrayExpr )
		Local t$
		For Local elem:=Eachin expr.exprs
			If t t+=","
			t+=elem.Trans()
		Next
		Return "["+t+"]"
	End

	Method TransIntrinsicExpr$( decl:Decl,expr:Expr,args:Expr[] )

		Local texpr$,arg0$,arg1$,arg2$

		If expr texpr=TransSubExpr( expr )

		If args.Length>0 And args[0] arg0=args[0].Trans()
		If args.Length>1 And args[1] arg1=args[1].Trans()
		If args.Length>2 And args[2] arg2=args[2].Trans()

		Local id$=decl.munged[1..]

		Select id

		'global functions
		Case "print" Return "print("+arg0+")" ' done
		Case "error" Return "error("+arg0+")"

		'string/array methods
		Case "length" Return texpr+".length" ' tested and works

		'array methods ' TODO!!!
		Case "resize"
			Local ty:=ArrayType( expr.exprType ).elemType
			If BoolType( ty ) Return "resize_int_array"+Bra( texpr+","+arg0 ) ' bools are ints in BlitzMax!
			If IntType( ty ) Return "resize_int_array"+Bra( texpr+","+arg0 ) ' done
			If FloatType( ty ) Return "resize_float_array"+Bra( texpr+","+arg0 ) ' done
			If StringType( ty ) Return "resize_string_array"+Bra( texpr+","+arg0 ) ' done
			If ArrayType( ty ) Return "resize_array_array_"+ArrayType( ty ).elemType+Bra( texpr+","+arg0 )
'			If ObjectType( ty ) Return "resize_object_array"+Bra( TransType(ty )+Bra (texpr)+","+arg0 )
			If ObjectType( ty ) Return texpr+"[.."+arg0+"]"
			InternalErr

		'string methods
		' Done all for BMax
		Case "compare" Return texpr+".Compare"+Bra( arg0 )
		Case "find" Return texpr+".Find"+Bra( arg0+","+arg1 )
		Case "findlast" Return texpr+".FindLast"+Bra( arg0 )
		Case "findlast2" Return texpr+".FindLast"+Bra( arg0+","+arg1 )
		Case "trim" Return texpr+".Trim()"
		Case "join" Return texpr+".Join"+Bra(arg0)
		Case "split" Return texpr+".Split"+Bra( arg0 )
		Case "replace" Return texpr+".Replace"+Bra(arg0+","+arg1)
		Case "tolower" Return texpr+".ToLower()"
		Case "toupper" Return texpr+".ToUpper()"
		Case "contains" Return texpr+".Contains"+Bra( arg0 )
		Case "startswith" Return texpr+".StartsWith"+Bra( arg0 )
		Case "endswith" Return texpr+".EndsWith"+Bra( arg0 )

		'string functions
'		Case "fromchar" Return "String.fromCharCode"+Bra( arg0 )
		Case "fromchar" Return "Chr"+Bra( arg0 )

		' ** TO-DO **
		' BlitzMax angle stuff isnt proper, need to minus 90 I think from the angle!

		'trig functions - degrees
		' Done all for BMax
		Case "sin","cos","tan" Return id+Bra(arg0)' "Math."+id+Bra( Bra( arg0 )+"*D2R" )
		Case "asin","acos","atan" Return id+Bra(arg0)' Bra( "Math."+id+Bra( arg0 )+"*R2D" )
		Case "atan2" Return id+Bra(arg0+","+arg1) 'Bra( "Math."+id+Bra( arg0+","+arg1 )+"*R2D" )

		'trig functions - radians
		' Done all for BMax
		Case "sinr" Return id[..-1]+Bra( Bra( arg0 +"*R2D") )
		Case "cosr" Return id[..-1]+Bra( Bra( arg0 +"*R2D") )
		Case "tanr" Return id[..-1]+Bra( Bra( arg0 +"*R2D") )
		Case "asinr" Return id[..-1]+Bra( arg0 )+"*D2R"
		Case "acosr" Return id[..-1]+Bra( arg0 )+"*D2R"
		Case "atanr" Return id[..-1]+Bra( arg0 )+"*D2R"
		Case "atan2r" Return id[..-1]+Bra(arg0+","+arg1)+"*D2R"

		'misc math functions
		' Done all for BMax
		Case "floor","ceil","log","exp" Return id+Bra( arg0 )
		Case "sqrt" Return "Sqr"+Bra(arg0)
		Case "pow" Return Bra(arg0)+"^"+arg1

		End Select

		InternalErr
	End

	'***** Statements *****

	Method TransAssignStmt$( stmt:AssignStmt )
	#rem
		If ENV_CONFIG="debug"
			Local ie:=IndexExpr( stmt.lhs )
			If ie
				Local t_rhs:=stmt.rhs.Trans()
				Local t_expr:=ie.expr.Trans()
				Local t_index:=TransExprNS( ie.index )
				Emit "dbg_array("+t_expr+","+t_index+")["+t_index+"]"+stmt.op+t_rhs
				Return
			Endif
		Endif
	#End
		Return Super.TransAssignStmt( stmt )
	End

	'***** Declarations *****

	Method EmitFuncDecl( decl:FuncDecl )
		BeginLocalScope
'		PushMungScope

		'Find decl we override
		Local odecl:=decl
		While odecl.overrides
			odecl=odecl.overrides
		Wend

		'Generate 'args' string and arg casts
		Local args$
		Local argCasts:=New StringStack
		For Local i=0 Until decl.argDecls.Length
			Local arg:=decl.argDecls[i]
			Local oarg:=odecl.argDecls[i]
			MungDecl arg
			If args args+=","
			args+=arg.munged+":"+TransType( oarg.type )
			If arg.type.EqualsType( oarg.type ) Continue
			Local t$=arg.munged
			arg.munged=""
			MungDecl arg
			'argCasts.Push "Local "+arg.munged+":"+TransType(arg.ty)+"="+t+" new "+TransType(arg.ty)+";"
			argCasts.Push "Local "+arg.munged+":"+TransType(arg.type)+"="+TransType(arg.type)+Bra(t)
		Next

'		Local t$=" "+decl.munged+":"+TransType( odecl.retType )+Bra( args )
		Local t$
		If VoidType( odecl.retType )
			t=" "+decl.munged+Bra( args )
		Else
			t=" "+decl.munged+":"+TransType( odecl.retType )+Bra( args )
		Endif
		Local funcType$ = "Function"
		Local cdecl:=decl.ClassScope()
		If cdecl And cdecl.IsInterface()
'			Emit funcType+" "+t+";"

			Local q$
			funcType = "Method"
			q+=funcType+" "

			If decl.IsAbstract()
				Emit q+t+" Abstract"
			Else
				Emit q+t+""
			End

			If decl.IsAbstract()
				If VoidType( decl.retType )
				'	Emit "return 0;" ' return 0 as Void = Int for BlitzMax ;)
				Else
				'	Emit "return "+TransValue( decl.retType,"" )+";"
				Endif
			Else
				For Local t$=Eachin argCasts
					Emit t
				Next
				EmitBlock decl
			Endif
			If decl.IsAbstract()
				indent=indent[..indent.Length-1]
			Else
				Emit "End"+funcType
			End

		Else
			Local q$'="internal "
			If cdecl
			'	q="public "
				If decl.IsStatic()
					q+=funcType+" "
				Else
					funcType = "Method"
					q+=funcType+" "
				Endif
			'	If decl.overrides q+="override "
			Else
				q+=funcType+" "
			Endif
			If decl.IsAbstract()
				Emit q+t+" Abstract"
			Else
				Emit q+t+""
			End

			If decl.IsAbstract()
				If VoidType( decl.retType )
				'	Emit "return 0;" ' return 0 as Void = Int for BlitzMax ;)
				Else
				'	Emit "return "+TransValue( decl.retType,"" )+";"
				Endif
			Else
				For Local t$=Eachin argCasts
					Emit t
				Next
				EmitBlock decl
			Endif
			If decl.IsAbstract()
				indent=indent[..indent.Length-1]
			Else
				Emit "End"+funcType
			End

		Endif

		EndLocalScope
'		PopMungScope
	End

	'returns unreachable status!
	Method EmitBlock( block:BlockDecl )

		PushEnv block

		Local func:=FuncDecl( block )

		If func
			If func.IsAbstract() InternalErr
			If ENV_CONFIG<>"release" EmitEnter func.scope.ident+"."+func.ident
		Endif

		For Local stmt:Stmt=Eachin block.stmts

			_errInfo=stmt.errInfo

			If unreachable	' And ENV_LANG<>"as"
				'If stmt.errInfo Print "Unreachable:"+stmt.errInfo
				Exit
			Endif

			If ENV_CONFIG<>"release"
				Local rs:=ReturnStmt( stmt )
				If rs
					If rs.expr
						EmitSetErr stmt.errInfo
						Local t_expr:=TransExprNS( rs.expr )
						EmitLeave
						Emit "return "+t_expr+";"
					Else
						EmitLeave
						Emit "return;"
					Endif
					unreachable=True
					Continue
				Endif
				EmitSetErr stmt.errInfo
			Endif

			Local t$=stmt.Trans()
			If t Emit t+";"

		Next

		Local r=unreachable
		unreachable=False

		If func And Not r

			If ENV_CONFIG<>"release" EmitLeave

			If Not VoidType( func.retType )
				If func.IsCtor()
					Emit "return self;"
				Else
					If func.ModuleScope().IsStrict()
						_errInfo=func.errInfo
						Err "Missing return statement."
					Endif
					Emit "return "+TransValue( func.retType,"" )+";"
				Endif
			Endif

		Endif

		PopEnv

		Return r
	End

Method Enquote$( str$ )
	str=str.Replace( "~~","~~~~" )
	str=str.Replace( "~q","~~q" )
	str=str.Replace( "~n","~~n" )
	str=str.Replace( "~r","~~r" )
	str=str.Replace( "~t","~~t" )

	For Local i=0 Until str.Length
		If str[i]>=32 And str[i]<128 Continue
		Local t$,n=str[i]
		While n
			Local c=(n&15)+48
			If c>=58 c+=97-58
			t=String.FromChar( c )+t
			n=(n Shr 4) & $0fffffff
		Wend
		If Not t t="0"
		Select ENV_LANG
		Case "cpp"
			t="~qL~q\x"+t+"~qL~q"
		Default
			t="\u"+("0000"+t)[-4..]
		End
		str=str[..i]+t+str[i+1..]
		i+=t.Length-1
	Next
	Select ENV_LANG
	Case "cpp"
		str="L~q"+str+"~q"
	Default
		str="~q"+str+"~q"
	End
	Return str
End

	Method Emit( t$ )
		If Not t Return

		't=t.Replace( "\n","~~n" )

		If t.StartsWith( "EndIf" ) Or t.StartsWith( "EndFunction" ) Or t.StartsWith( "EndMethod" ) Or t.StartsWith( "EndType" ) Or t.StartsWith("Next") Or t.StartsWith("Else") Or t.StartsWith( "Wend" )
			indent=indent[..indent.Length-1]
		Endif
		lines.AddLast indent+t
		'code+=indent+t+"~n"
		If t.EndsWith( "Then" ) Or t.StartsWith( "Function" ) Or t.StartsWith( "Method" ) Or t.StartsWith( "Type" ) Or t.StartsWith("For") Or t.StartsWith("Else") Or t.StartsWith("While")
			indent+="~t"
		Endif
	End

	Method TransUnaryOp$( op$ )
'		Print "TransUnaryOp op="+op
		Select op
		Case "+" Return "+"
		Case "-" Return "-"
		Case "~~" Return op
		Case "not" Return op+" "
		End Select
		InternalErr
	End

	Method TransAssignOp$( op$ )
'		Print "TransAssignOp op="+op
		Select op
			Case "mod=" Return " :Mod "
			Case "shl=" Return " :shl "
			Case "shr=" Return " :shr "
			Case "+=" Return " :+"
			Case "-=" Return " :-"
			Case "*=" Return " :*"
			Case "/=" Return " :/"
			Case "|=" Return " :|"
			Case "&=" Return " :&"
		End
		Return op
	End

	Method TransBinaryOp$( op$,rhs$ )
	#rem
		Select op
		Case "+","-"
			If rhs.StartsWith( op ) Return op+" "
			Return op
		Case "*","/" Return op
		Case "shl" Return op
		Case "shr" Return op
		Case "mod" Return op
		Case "and" Return op
		Case "or" Return op
		Case "=" Return op
		Case "<>" Return op
		Case "<","<=",">",">=" Return op
		Case "&","|" Return op
		Case "~~" Return "^"
		End Select
	#end
	Return " " + op + " "
		InternalErr
	End

	Method TransIfStmt$( stmt:IfStmt )

		If ConstExpr( stmt.expr )
			If ConstExpr( stmt.expr ).value
				If EmitBlock( stmt.thenBlock ) unreachable=True
			Else If Not stmt.elseBlock.stmts.IsEmpty()
				If EmitBlock( stmt.elseBlock ) unreachable=True
			Endif
		Else If Not stmt.elseBlock.stmts.IsEmpty()
			Emit "If"+Bra( stmt.expr.Trans() )+" Then"
			Local unr=EmitBlock( stmt.thenBlock )
			Emit "Else"
			Local unr2=EmitBlock( stmt.elseBlock )
			Emit "EndIf"
			If unr And unr2 unreachable=True
		Else
			Emit "If"+Bra( stmt.expr.Trans() )+" Then"
			Local unr=EmitBlock( stmt.thenBlock )
			Emit "EndIf"
		Endif
	End

	Method EmitClassDecl( classDecl:ClassDecl )

		If KLUDGE_INTERFACES
			If classDecl.IsInterface() Return
		Endif

'		If classDecl.IsTemplateInst()
'			InternalErr
'		Endif

		Local classid$=classDecl.munged
		Local superid$=classDecl.superClass.munged

'		Print "superid = "+superid + " " + classid

		If classDecl.IsInterface()

			Local bases$

			If Not KLUDGE_INTERFACES
				For Local iface:=Eachin classDecl.implments
					If bases bases+="," Else bases=" extends "
					bases+=iface.munged
				Next
			Endif

			Local ab$=""
			If classDecl.IsAbstract()
				ab="Abstract"
			End

			If superid<>"Object"
				Emit "Type "+classid+" extends "+superid+bases + " " + ab
			Else
				Emit "Type "+classid + " " + ab
			Endif
'			Emit "interface "+classid+bases+"{"

			For Local decl:=Eachin classDecl.Semanted
				Local fdecl:=FuncDecl( decl )
				If Not fdecl Continue
				EmitFuncDecl fdecl
			Next
			Emit "EndType"
'			Emit "}"
			Return
		Endif

		Local bases$

		If Not KLUDGE_INTERFACES
			For Local iface:=Eachin classDecl.implments
  '			If bases bases+="," Else bases=" implements "
				If bases bases+="," Else bases=" extends "
				bases+=iface.munged
			Next
		Endif

		Local ab$=""
		If classDecl.IsAbstract()
			ab="Abstract"
		End

		If superid<>"Object"
			Emit "Type "+classid+" extends "+superid+bases + " " + ab
		Elseif bases<>""
			Emit "Type "+classid+bases + " " + ab
		Else
			Emit "Type "+classid + " " + ab
		Endif

		'members...
		For Local decl:=Eachin classDecl.Semanted
			Local tdecl:=FieldDecl( decl )
			If tdecl
				Emit "Field "+TransValDecl( tdecl )+"="+tdecl.init.Trans()+";"
				Continue
			Endif

			Local gdecl:=GlobalDecl( decl )
			If gdecl
				Emit "Global "+TransValDecl( gdecl )+";"
				Continue
			Endif

			Local fdecl:=FuncDecl( decl )
			If fdecl
				EmitFuncDecl fdecl
				Continue
			Endif
		Next

		Emit "EndType"
	End

	Method TransWhileStmt$( stmt:WhileStmt )
		Local nbroken=broken

		Emit "While"+Bra( stmt.expr.Trans() )+""
		Local unr=EmitBlock( stmt.block )
		Emit "Wend"

		If broken=nbroken And ConstExpr( stmt.expr ) And ConstExpr( stmt.expr ).value unreachable=True
		broken=nbroken
	End

	Method TransRepeatStmt$( stmt:RepeatStmt )
		Local nbroken=broken

		Emit "Repeat"
		Local unr=EmitBlock( stmt.block )
		Emit "Until ("+Bra( stmt.expr.Trans() )+");"

		If broken=nbroken And ConstExpr( stmt.expr ) And Not ConstExpr( stmt.expr ).value unreachable=True
		broken=nbroken
	End

	Method TransForStmt$( stmt:ForStmt )
		Local nbroken=broken

		Local init$=stmt.init.Trans()
		Local expr$=stmt.expr.Trans()
		Local incr$=stmt.incr.Trans()

		Local splitExpr:= expr.Split(" ")
		Local splitIncr:= incr.Split(" ")
		Local bmaxExpr$ = splitExpr[1]
		Local bmaxIncr$ = splitIncr[2]

		If bmaxExpr="<=" Or bmaxExpr=">="
			bmaxExpr = "To"
		Else If bmaxExpr="<" Or bmaxExpr=">"
			bmaxExpr = "Until"
		End

'		If( splitExpr.Length > 3 )
			Local out$="For "+init+" "+bmaxExpr +" "
			Local sc:Int=2
			Local first:Bool = True
			While sc < splitExpr.Length
				If first
					first=False
				Else
					out+=" "
				Endif
				out+=splitExpr[sc]
				sc+=1
			Wend
			out+=" Step "+ bmaxIncr
			Emit out
'		Else
'			Emit "For "+init+" "+bmaxExpr +" "+splitExpr[2]+ " Step "+ bmaxIncr
'		Endif
		Local unr=EmitBlock( stmt.block )
		Emit "Next"

		If broken=nbroken And ConstExpr( stmt.expr ) And ConstExpr( stmt.expr ).value unreachable=True
		broken=nbroken
	End

	Method TransBreakStmt$( stmt:BreakStmt )
		unreachable=True
		broken+=1
		Return "Exit"
	End

	Method TransApp$( app:AppDecl )

		If KLUDGE_INTERFACES
			KludgeInterfaces app
		Endif

'		app.mainFunc.munged="bbMain"
		app.mainFunc.munged="bbMain2"

		For Local decl:=Eachin app.imported.Values()
			MungDecl decl
		Next

		For Local decl:=Eachin app.Semanted

			MungDecl decl

			Local cdecl:=ClassDecl( decl )
			If Not cdecl Continue

			BeginLocalScope
'			PushMungScope

			For Local decl:=Eachin cdecl.Semanted
				If FuncDecl( decl ) And FuncDecl( decl ).IsCtor()
					decl.ident=cdecl.ident+"_"+decl.ident
				Endif
				MungDecl decl
			Next

			EndLocalScope
'			PopMungScope
		Next

		'decls
		'
		For Local decl:=Eachin app.Semanted

			Local gdecl:=GlobalDecl( decl )
			If gdecl
				Emit "Global "+TransValDecl( gdecl )+";"
				Continue
			Endif

			Local fdecl:=FuncDecl( decl )
			If fdecl
				EmitFuncDecl fdecl
				Continue
			Endif

			Local cdecl:=ClassDecl( decl )
			If cdecl
				EmitClassDecl cdecl
				Continue
			Endif
		Next

		Emit "Function bbInit()"
		For Local decl:=Eachin app.semantedGlobals
			Emit TransGlobal( decl )+"="+decl.init.Trans()+";"
		Next
		Emit "EndFunction"

		Emit "Function bbMain:Int()"
		Emit "~tLocal r:Int=bbMain2();"
		Local found:Bool = False
		For Local s:String = Eachin lines
			If s.Contains( "bb_app_device" )
				found = True
				Exit
			Endif
		Next
		If found
			Emit "~tbb_app_device.Setup();"
		Endif
		Emit "~treturn r;"
		Emit "EndFunction"

		Return JoinLines()
	End

	Method MungDecl( decl:Decl )

		If decl.munged Return

		Local fdecl:FuncDecl=FuncDecl( decl )
		If fdecl And fdecl.IsMethod() Return MungMethodDecl( fdecl )

		Local mscope$,cscope$
		If decl.ClassScope() cscope=decl.ClassScope().munged
		If decl.ModuleScope() mscope=decl.ModuleScope().munged

		Local id:=decl.ident,munged$,scope$

		If LocalDecl( decl )
			scope="$"
			munged="t_"+id
		Else If FieldDecl( decl )
			scope=cscope
			munged="f_"+id
		Else If GlobalDecl( decl ) Or FuncDecl( decl )
			If cscope And ENV_LANG<>"js"
				scope=cscope
				munged="g_"+id
			Else If cscope
				munged=cscope+"_"+id
			Else
				munged=mscope+"_"+id
			Endif
		Else If ClassDecl( decl )
			munged=mscope+"_"+id
		Else If ModuleDecl( decl )
			munged="bb_"+id
		Else
			Print "OOPS1"
			InternalErr
		Endif

		''' Modify the "munged" variable:
		''' change uppercase characters to _1

		Local newmunged:String
		For Local i:Int = 0 Until munged.Length
			Local c:Int = munged[i]
			If c = "_1" Then
				newmunged += "_1" + "_1"
			Elseif c>=65 And c<=90 Then
				newmunged += "_1" + String.FromChar(c)
			Else
				newmunged += String.FromChar(c)
			End
		Next
		munged = newmunged

		Local set:=mungedScopes.Get( scope )
		If set
			If set.Contains( munged )
				Local id=1
				Repeat
					id+=1
					Local t$=munged+String(id)
					If set.Contains(t) Continue
					munged=t
					Exit
				Forever
			Endif
		Else
			If scope="$"
				Print "OOPS2"
				InternalErr
			Endif
			set=New StringSet
			mungedScopes.Set scope,set
		Endif
		set.Insert munged
		decl.munged=munged
	End

End


Added 'IOUTIL_ENDIANSTREAM_LEGACY_BIG_ENDIAN' behavior.

Strict

Public

' Preprocessor related:
#IOUTIL_ENDIANSTREAM_LEGACY_BIG_ENDIAN = True

' Imports (Public):
Import brl.stream

' Imports (Private):
Private

Import wrapperstream

Import regal.byteorder

Import brl.databuffer

Public

' Classes:

' Automatic byte-swapping for 'Streams'.
Class EndianStreamManager<StreamType> Extends WrapperStream<StreamType>
	' Constructor(s):
	Method New(S:StreamType, BigEndianStorage:Bool=False)
		Super.New(S)

		Self.BigEndianStorage = BigEndianStorage
	End

	' Methods:
	Method ReadShort:Int()
		' Local variable(s):
		Local Data:= Super.ReadShort()

		If (BigEndianStorage) Then
			#If IOUTIL_ENDIANSTREAM_LEGACY_BIG_ENDIAN
				Return NToHS(Data)
			#Else
				Return NToHS_S(Data)
			#End
		Endif

		Return Data
	End

	Method ReadInt:Int()
		' Local variable(s):
		Local Data:= Super.ReadInt()

		If (BigEndianStorage) Then
			Return NToHL(Data)
		Endif

		Return Data
	End

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

		Return Super.ReadFloat()
	End

	Method WriteShort:Void(Value:Int)
		If (BigEndianStorage) Then
			Value = HToNS(Value)
		Endif

		' Call the super-class's implementation.
		Super.WriteShort(Value)

		Return
	End

	Method WriteInt:Void(Value:Int)
		If (BigEndianStorage) Then
			Value = HToNL(Value)
		Endif

		' Call the super-class's implementation.
		Super.WriteInt(Value)

		Return
	End

	Method WriteFloat:Void(Value:Float)
		' Call the evaluated write command.
		If (BigEndianStorage) Then
			Super.WriteInt(HToNF(Value))
		Else
			Super.WriteFloat(Value)
		Endif

		Return
	End

	' Fields:
	Field BigEndianStorage:Bool
End

Class BasicEndianStreamManager Extends EndianStreamManager<Stream> Final
	' Constructor(s):
	Method New(S:Stream, BigEndianStorage:Bool=False)
		' Call the super-class's implementation.
		Super.New(S, BigEndianStorage)
	End
End

Strict

Public

' Imports (Public):
Import brl.stream

' Imports (Private):
Private

Import wrapperstream

Import regal.byteorder

Import brl.databuffer

Public

' Classes:

' Automatic byte-swapping for 'Streams'.
Class EndianStreamManager<StreamType> Extends WrapperStream<StreamType>
	' Constructor(s):
	Method New(S:StreamType, BigEndianStorage:Bool=False)
		Super.New(S)

		Self.BigEndianStorage = BigEndianStorage
	End

	' Methods:
	Method ReadShort:Int()
		' Local variable(s):
		Local Data:= Super.ReadShort()

		If (BigEndianStorage) Then
			Return NToHS(Data)
		Endif

		Return Data
	End

	Method ReadInt:Int()
		' Local variable(s):
		Local Data:= Super.ReadInt()

		If (BigEndianStorage) Then
			Return NToHL(Data)
		Endif

		Return Data
	End

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

		Return Super.ReadFloat()
	End

	Method WriteShort:Void(Value:Int)
		If (BigEndianStorage) Then
			Value = HToNS(Value)
		Endif

		' Call the super-class's implementation.
		Super.WriteShort(Value)

		Return
	End

	Method WriteInt:Void(Value:Int)
		If (BigEndianStorage) Then
			Value = HToNL(Value)
		Endif

		' Call the super-class's implementation.
		Super.WriteInt(Value)

		Return
	End

	Method WriteFloat:Void(Value:Float)
		' Call the evaluated write command.
		If (BigEndianStorage) Then
			Super.WriteInt(HToNF(Value))
		Else
			Super.WriteFloat(Value)
		Endif

		Return
	End

	' Fields:
	Field BigEndianStorage:Bool
End

Class BasicEndianStreamManager Extends EndianStreamManager<Stream> Final
	' Constructor(s):
	Method New(S:Stream, BigEndianStorage:Bool=False)
		' Call the super-class's implementation.
		Super.New(S, BigEndianStorage)
	End
End