MonkeyMax - Added OnSuspend/OnResume for gxtkAudio

--HG--
extra : convert_revision : svn%3Ae934d3cd-0d57-f34a-94d0-9e8d31ae1c29/trunk%40412

' ***** Start mojo.bmax.bmx ******

Global app:gxtkApp

Type gxtkApp
	Field ginput:gxtkInput
	Field gaudio:gxtkAudio
	Field ggraphics:gxtkGraphics

	Field dead:Int=0
	Field suspended:Int=0
	Field vloading:Int=0
	Field maxloading:Int=0
	Field updateRate:Int=0
	Field nextUpdate:Float=0
	Field updatePeriod:Float=0
	Field startMillis:Float=0

	Method New()' gxtkApp()
		app=Self
		ggraphics=New gxtkGraphics
	EndMethod

	Method Setup()
		ginput=New gxtkInput
		gaudio=New gxtkAudio

		bb_input__1Set_1Input_1Device(ginput)
		bb_audio__1Set_1Audio_1Device(gaudio)

		startMillis=BlitzMaxMillisecs()

		SetFrameRate( 0 )

		InvokeOnCreate()
		InvokeOnRender()
		Update()
	EndMethod

	Method Update()
		While Not AppTerminate()
			If Not updatePeriod return
			Local updates:Int = 0

			Repeat
				nextUpdate:+updatePeriod
				InvokeOnUpdate()
				If Not updatePeriod Then Exit
				If nextUpdate>BlitzMaxMillisecs() Then Exit
				updates:+1
				If updates = 7 Then
					nextUpdate = BlitzMaxMillisecs()
					Exit
				EndIf
			Forever
			InvokeOnRender()
			Local del:Int = nextUpdate - BlitzMaxMillisecs()
			If del < 1 Then del = 1
			Delay(del)
		Wend
	EndMethod

	Method InvokeOnCreate()
		If dead Return
		dead = 1
		OnCreate()
		dead = 0
	EndMethod

	Method InvokeOnUpdate()
		If dead Or suspended Or Not updateRate Or vloading Return
		OnUpdate()
	EndMethod

	Method InvokeOnRender()
		If dead Or suspended Return
		ggraphics.BeginRender()
		If vloading
			OnLoading()
		Else
			OnRender()
		EndIf
		ggraphics.EndRender()
	EndMethod

	Method SetFrameRate( fps:Int )
		If fps
			updatePeriod=1000.0/fps
			nextUpdate=BlitzMaxMillisecs() +updatePeriod
		Else
			updatePeriod=0
		EndIf
	EndMethod

	Method LoadState:String()
'		var file:SharedObject=SharedObject.getLocal( "gxtkapp" );
'		var state:String=file.data.state;
'		file.close();
'		if( state ) return state;
		Return ""
	EndMethod

	Method SaveState:Int( state:String )
'		var file:SharedObject=SharedObject.getLocal( "gxtkapp" );
'		file.data.state=state;
'		file.close();
		Return 0
	EndMethod

	Method LoadString:String( path:String )
		path = "data/" + path
		Try
			Return LoadText( path )
		Catch ReadFail:Object
			Return Null
		EndTry
	EndMethod

	' ***** GXTK API *****

	Method GraphicsDevice:gxtkGraphics()
		Return ggraphics
	EndMethod

	Method InputDevice:gxtkInput()
		Return ginput
	EndMethod

	Method AudioDevice:gxtkAudio()
		Return gaudio
	EndMethod

	Method SetUpdateRate:Int(hertz:Int)
		updateRate = hertz
		If Not vloading Then SetFrameRate(updateRate)
		Return 0
	EndMethod

	Method MilliSecs:Int()
		Return BlitzMaxMillisecs() - startMillis
	EndMethod

	Method Loading:Int()
		Return vloading
	EndMethod

	Method OnCreate:Int()
		Return 0
	EndMethod

	Method OnUpdate:Int()
		Return 0
	EndMethod

	Method OnSuspend:Int()
		Return 0
	EndMethod

	Method OnResume:Int()
		Return 0
	EndMethod

	Method OnRender:Int()
		Return 0
	EndMethod

	Method OnLoading:Int()
		Return 0
	EndMethod
EndType

Type gxtkGraphics
	Field gmode:Int = 1
	Field ix:Float=1,iy:Float,jx:Float,jy:Float=1,tx:Float,ty:Float
	Field sx:Float=1,sy:Float=1,rot:Float=0

	Method Mode:Int()
		Return gmode
	EndMethod

	Method Cls:Int(r:Int = 0, g:Int = 0, b:Int = 0)
		BlitzMaxCls(r, g, b)
		Return 0
	EndMethod

	Method DrawPoint:Int(x:Float, y:Float)
		Local nx:Float = TransX(x,y)
		Local ny:Float = TransY(x,y)
		Plot nx, ny
	EndMethod

	Method LoadSurface:gxtkSurface(path:String)
		Local image:TImage = LoadImage("data/"+path)
		If image Then
			Local gs:gxtkSurface = New gxtkSurface
			gs.setImage(image)
			Return gs
		EndIf
		Return Null
	EndMethod

	Method BeginRender()
	EndMethod

	Method EndRender()
		Flip
	EndMethod

	Method SetColor:Int(r:Int, g:Int, b:Int)
		BlitzMaxSetColor(r, g, b)
		Return 0
	EndMethod

	Method SetAlpha:Int(a:Float)
		BlitzMaxSetAlpha(a)
		Return 0
	EndMethod

	Method SetBlend:Int(blend:Int)
		BlitzMaxSetBlend(blend)
		Return 0
	EndMethod

	Method Width:Int()
		Return GraphicsWidth()
	EndMethod

	Method Height:Int()
		Return GraphicsHeight()
	EndMethod

	Method SetScissor:Int(x:Int, y:Int, w:Int, h:Int)
		SetViewport(x, y, w, h) ' NOT TESTED!
		Return 0
	EndMethod

	Method TransX:Float(x:Float, y:Float)
		Return ix*x + jx*y + tx
	EndMethod

	Method TransY:Float(x:Float, y:Float)
		Return iy*x + jy*y + ty
	EndMethod

	Method SetMatrix:Int(ix:Float,iy:Float,jx:Float,jy:Float,tx:Float,ty:Float)
		Self.ix = ix ; Self.iy = iy
		Self.jx = jx ; Self.jy = jy
		Self.tx = tx ; Self.ty = ty
		sx = Sqr(ix*ix+iy*iy)
		sy = Sqr(jx*jx+jy*jy)
		rot = Atan2( iy, ix )
		If ix < 0 Then
			sx = -sx
			rot :+ 180
		EndIf
		If jy < 0 Then sy = -sy
		SetTransform( rot, sx, sy )
		Return 0
	EndMethod

	Method DrawSurface:Int(surface:gxtkSurface,x:Float,y:Float)
		Local nx:Float = TransX(x,y)
		Local ny:Float = TransY(x,y)
		DrawImage(surface.image, nx, ny, 0)
		Return 0
	EndMethod

	Method DrawSurface2:Int(surface:gxtkSurface,x:Float,y:Float, srcx:Int, srcy:Int, srcw:Int, srch:Int )
		Local nx:Float = TransX(x,y)
		Local ny:Float = TransY(x,y)
		DrawSubImageRect(surface.image, nx, ny, srcw, srch, srcx, srcy, srcw, srch)
		Return 0
	EndMethod

	Method DrawLine:Int( x1:Float,y1:Float,x2:Float,y2:Float )
		Local nx1:Float = TransX(x1,y1)
		Local ny1:Float = TransY(x1,y1)
		Local nx2:Float = TransX(x2,y2)
		Local ny2:Float = TransY(x2,y2)
		' Need to reset transform so that BlitzMax doesn't try to apply rotation
		SetTransform( 0, 1, 1 )
		BlitzMaxDrawLine(nx1, ny1, nx2, ny2)
		SetTransform( rot, sx, sy )
		Return 0
	EndMethod

	Method DrawOval:Int( x:Float, y:Float, w:Float, h:Float )
		Local nx:Float = TransX(x,y)
		Local ny:Float = TransY(x,y)
		BlitzMaxDrawOval(nx, ny, w, h)
		Return 0
	EndMethod

	Method DrawPoly:Int(vertices:Float[])
		' setting the origin to use the current rotation translation
		SetOrigin(TransX(0,0), TransY(0,0))
		BlitzMaxDrawPoly( vertices )
		SetOrigin(0, 0)
		Return 0
	EndMethod

	Method DrawRect:Int( x:Float, y:Float, w:Float, h:Float )
		Local nx:Float = TransX(x,y)
		Local ny:Float = TransY(x,y)
		BlitzMaxDrawRect(nx, ny, w, h)
		Return 0
	EndMethod
EndType

Type gxtkInput
	Method MouseX:Float()
		Return BRL.PolledInput.MouseX()
	EndMethod

	Method MouseY:Float()
		Return BRL.PolledInput.MouseY()
	EndMethod

	Method KeyDown:Int( key:Int )
		if( key = 384 ) key = 1 ' change TOUCH0 to MOUSE_LMB

		If( key >= 1 And key <= 3 )
			Return BRL.PolledInput.MouseDown( key )
		EndIf
		If key < 256
			Return BRL.PolledInput.KeyDown( key )
		Else
			Return 0
		EndIf
	EndMethod

	Method KeyHit:Int( key:Int )
		if( key = 384 ) key = 1 ' change TOUCH0 to MOUSE_LMB
		If( key >= 1 And key <= 3 )
			Return BRL.PolledInput.MouseHit( key )
		EndIf
		If key < 256
			Return BRL.PolledInput.KeyHit( key )
		Else
			Return 0
		EndIf
	EndMethod

	Method GetChar:Int()
		Return BRL.PolledInput.GetChar()
	EndMethod

	Method JoyX:Int( index:Int )
		Return Pub.FreeJoy.JoyX( index )
	EndMethod

	Method JoyY:Int( index:Int )
		Return Pub.FreeJoy.JoyY( index )
	EndMethod

	Method JoyZ:Int( index:Int )
		Return Pub.FreeJoy.JoyZ( index )
	EndMethod

	Method TouchX:Float( index:Int )
		Return BRL.PolledInput.MouseX()
	EndMethod

	Method TouchY:Float( index:Int )
		Return BRL.PolledInput.MouseY()
	EndMethod

	Method AccelX:Int()
		return 0
	EndMethod

	Method AccelY:Int()
		return 0
	EndMethod

	Method AccelZ:Int()
		return 0
	EndMethod

	Method SetKeyboardEnabled:Int( enabled:int )
		Return 0
	EndMethod
EndType

Type gxtkChannel
	Field channel:TChannel	' null then not playing
	Field sample:gxtkSample
	Field loops:int
	'Field transform:SoundTransform=new SoundTransform()
	'Field pausepos:Number
	Field state:int

	Method New()
		channel = New TChannel
	EndMethod
EndType

Type gxtkAudio
	Field amusicState:Int = 0
	Field channels:gxtkChannel[] = New gxtkChannel[33]
	Const MUSIC_CHANNEL:Int = 32
	Field music:gxtkSample

	Method New()
		For local i:Int = 0 To 33 - 1
			channels[i] = New gxtkChannel
			channels[i].channel = AllocChannel()
		Next
	EndMethod

	Method OnSuspend()
		For Local i:Int = 0 To 33 - 1
			Local chan:gxtkChannel = channels[i]
			If chan.state = 1 Then
				chan.channel.SetPaused(True)
			EndIf
		Next
	End Method

	Method OnResume()
		For Local i:Int = 0 To 33 - 1
			Local chan:gxtkChannel = channels[i]
			If chan.state = 1 Then
				chan.channel.SetPaused(False)
			EndIf
		Next
	End Method

	Method MusicState:Int()
		' Monkey Docs: 	0 if the music is currently stopped
		'				1 if the music is currently playing
		'				-1 if the music state cannot be determined

		Local chan:gxtkChannel = channels[MUSIC_CHANNEL]
		If chan.channel <> Null Then
			If ChannelPlaying(chan.channel) Then Return 1 Else Return 0
		EndIf

		Return -1
	EndMethod

	Method PlayMusic:Int( path:String, flags:Int )
		StopMusic()
		music = LoadSample( path )
		If Not music Then Return -1

		PlaySample(music, MUSIC_CHANNEL, flags)
		Return 0
	EndMethod

	Method StopMusic:Int()
		StopChannel( MUSIC_CHANNEL )

		If music Then
			music.Discard()
			music = null
		EndIf
		Return 0
	EndMethod

	Method ChannelState:int( channel:int )
		' Monkey Docs: 	0 if the channel is currently stopped
		'				1 if the channel is currently playing
		'				2 if the channel is currently paused
		'				-1 if the channel state cannot be determined
		Local chan:gxtkChannel = channels[channel]
		If chan.channel <> Null Then
			If ChannelPlaying(chan.channel) Then Return 1 Else Return 0
		EndIf

		Return -1
	EndMethod

	Method StopChannel( channel:Int )
		Local chan:gxtkChannel = channels[channel]

		If chan.state <> 0
			chan.channel.Stop()
			chan.channel=null
			chan.sample=null
			chan.state=0
		EndIf
	EndMethod

	Method PauseChannel:Int( channel:Int)
		Local chan:gxtkChannel = channels[channel]
		chan.channel.SetPaused(True)
		Return 0
	EndMethod

	Method ResumeChannel:Int( channel:Int)
		Local chan:gxtkChannel = channels[channel]
		chan.channel.SetPaused(False)
		Return 0
	EndMethod

	Method PlaySample( sound:gxtkSample, channel:Int, flags:Int )
		Local chan:gxtkChannel = channels[channel]
		If chan.state <> 0 Then chan.channel.SetPaused(True)

		chan.sample = sound
		chan.loops = flags
		chan.state = 1

		' if looping, we need to reload the sound with the looping flag
		If flags <> sound.loop
			Local smp:TSound = LoadSound(sound.path, flags)
			sound.setSound(smp)
			sound.loop = flags
		EndIf

		PlaySound( sound.sound, chan.channel )
	EndMethod

	Method SetPan( channel:Int, pan:Float )
		Local chan:gxtkChannel = channels[channel]
		chan.channel.SetPan(pan)
	EndMethod

	Method SetRate( channel:Int, rate:Float )
		Local chan:gxtkChannel = channels[channel]
		chan.channel.SetRate(rate)
	EndMethod

	Method PauseMusic:Int()
		Local chan:gxtkChannel = channels[MUSIC_CHANNEL]
		chan.channel.SetPaused(True)
		Return 0
	EndMethod

	Method ResumeMusic:Int()
		Local chan:gxtkChannel = channels[MUSIC_CHANNEL]
		chan.channel.SetPaused(False)
		Return 0
	EndMethod

	Method SetMusicVolume:Int( volume:Float )
		SetVolume( MUSIC_CHANNEL, volume )
		Return 0
	EndMethod

	Method SetVolume:Int( channel:Int, volume:Float )
		Local chan:gxtkChannel = channels[channel]
		chan.channel.SetVolume(volume)
		Return 0
	EndMethod

	Method LoadSample:gxtkSample( path:String )
		Local extension:String = ExtractExt( path)
		If extension = "ogg" Or extension = "wav" Then
			Local sound:TSound = LoadSound("data/"+path)
			If sound Then
				Local gs:gxtkSample = New gxtkSample
				gs.setSound(sound)
				gs.path = "data/"+path
				Return gs
			EndIf
		Else
			RuntimeError "BlitzMax can only use ogg and wav file formats"
		EndIf
		Return Null
	EndMethod
EndType

Type gxtkSample
	Field sound:TSound
	Field path:String
	Field loop:Int

	Method setSound(sound:TSound)
		Self.sound = sound
	EndMethod

	Method Discard()
		Self.sound = null
	EndMethod
EndType

Function BlitzMaxDrawPoly:Int(vertices:Float[])
	DrawPoly vertices
	Return 0
EndFunction

Function BlitzMaxDrawRect:Int( x:Float, y:Float, w:Float, h:Float )
	DrawRect x, y, w, h
	Return 0
EndFunction

Function BlitzMaxDrawOval:Int( x:Float, y:Float, w:Float, h:Float )
	DrawOval x, y, w, h
	Return 0
EndFunction

Function BlitzMaxDrawLine:Int( x1:Float,y1:Float,x2:Float,y2:Float )
	DrawLine x1, y1, x2, y2
	Return 0
EndFunction

Function BlitzMaxMillisecs:Int()
	Return MilliSecs()
EndFunction

Function BlitzMaxSetColor(r:Int, g:Int, b:Int)
	SetColor(r, g, b)
EndFunction

Function BlitzMaxSetBlend(blend:Int)
	Select blend
		Case 0
			SetBlend( ALPHABLEND )
		Case 1
			SetBlend( LIGHTBLEND )
	End Select
EndFunction

Function BlitzMaxSetAlpha(a:Float)
	SetAlpha(a)
EndFunction

Function BlitzMaxCls(r:Int = 0, g:Int = 0, b:Int = 0)
	SetClsColor(r, g, b)
	Cls
EndFunction

Type gxtkSurface
	Field w:Int, h:Int
	Field image:TImage

	Method setImage(image:TImage)
		Self.image = image
	EndMethod

	Method Width:Int()
		Return image.Width
	EndMethod

	Method Height:Int()
		Return image.Height
	EndMethod

	Method Discard()
	EndMethod
EndType

' ***** End mojo.bmax.bmx ******

' ***** Start mojo.bmax.bmx ******

Global app:gxtkApp

Type gxtkApp
	Field ginput:gxtkInput
	Field gaudio:gxtkAudio
	Field ggraphics:gxtkGraphics

	Field dead:Int=0
	Field suspended:Int=0
	Field vloading:Int=0
	Field maxloading:Int=0
	Field updateRate:Int=0
	Field nextUpdate:Float=0
	Field updatePeriod:Float=0
	Field startMillis:Float=0

	Method New()' gxtkApp()
		app=Self
		ggraphics=New gxtkGraphics
	EndMethod

	Method Setup()
		ginput=New gxtkInput
		gaudio=New gxtkAudio

		bb_input__1Set_1Input_1Device(ginput)
		bb_audio__1Set_1Audio_1Device(gaudio)

		startMillis=BlitzMaxMillisecs()

		SetFrameRate( 0 )

		InvokeOnCreate()
		InvokeOnRender()
		Update()
	EndMethod

	Method Update()
		While Not AppTerminate()
			If Not updatePeriod return
			Local updates:Int = 0

			Repeat
				nextUpdate:+updatePeriod
				InvokeOnUpdate()
				If Not updatePeriod Then Exit
				If nextUpdate>BlitzMaxMillisecs() Then Exit
				updates:+1
				If updates = 7 Then
					nextUpdate = BlitzMaxMillisecs()
					Exit
				EndIf
			Forever
			InvokeOnRender()
			Local del:Int = nextUpdate - BlitzMaxMillisecs()
			If del < 1 Then del = 1
			Delay(del)
		Wend
	EndMethod

	Method InvokeOnCreate()
		If dead Return
		dead = 1
		OnCreate()
		dead = 0
	EndMethod

	Method InvokeOnUpdate()
		If dead Or suspended Or Not updateRate Or vloading Return
		OnUpdate()
	EndMethod

	Method InvokeOnRender()
		If dead Or suspended Return
		ggraphics.BeginRender()
		If vloading
			OnLoading()
		Else
			OnRender()
		EndIf
		ggraphics.EndRender()
	EndMethod

	Method SetFrameRate( fps:Int )
		If fps
			updatePeriod=1000.0/fps
			nextUpdate=BlitzMaxMillisecs() +updatePeriod
		Else
			updatePeriod=0
		EndIf
	EndMethod

	Method LoadState:String()
'		var file:SharedObject=SharedObject.getLocal( "gxtkapp" );
'		var state:String=file.data.state;
'		file.close();
'		if( state ) return state;
		Return ""
	EndMethod

	Method SaveState:Int( state:String )
'		var file:SharedObject=SharedObject.getLocal( "gxtkapp" );
'		file.data.state=state;
'		file.close();
		Return 0
	EndMethod

	Method LoadString:String( path:String )
		path = "data/" + path
		Try
			Return LoadText( path )
		Catch ReadFail:Object
			Return Null
		EndTry
	EndMethod

	' ***** GXTK API *****

	Method GraphicsDevice:gxtkGraphics()
		Return ggraphics
	EndMethod

	Method InputDevice:gxtkInput()
		Return ginput
	EndMethod

	Method AudioDevice:gxtkAudio()
		Return gaudio
	EndMethod

	Method SetUpdateRate:Int(hertz:Int)
		updateRate = hertz
		If Not vloading Then SetFrameRate(updateRate)
		Return 0
	EndMethod

	Method MilliSecs:Int()
		Return BlitzMaxMillisecs() - startMillis
	EndMethod

	Method Loading:Int()
		Return vloading
	EndMethod

	Method OnCreate:Int()
		Return 0
	EndMethod

	Method OnUpdate:Int()
		Return 0
	EndMethod

	Method OnSuspend:Int()
		Return 0
	EndMethod

	Method OnResume:Int()
		Return 0
	EndMethod

	Method OnRender:Int()
		Return 0
	EndMethod

	Method OnLoading:Int()
		Return 0
	EndMethod
EndType

Type gxtkGraphics
	Field gmode:Int = 1
	Field ix:Float=1,iy:Float,jx:Float,jy:Float=1,tx:Float,ty:Float
	Field sx:Float=1,sy:Float=1,rot:Float=0

	Method Mode:Int()
		Return gmode
	EndMethod

	Method Cls:Int(r:Int = 0, g:Int = 0, b:Int = 0)
		BlitzMaxCls(r, g, b)
		Return 0
	EndMethod

	Method DrawPoint:Int(x:Float, y:Float)
		Local nx:Float = TransX(x,y)
		Local ny:Float = TransY(x,y)
		Plot nx, ny
	EndMethod

	Method LoadSurface:gxtkSurface(path:String)
		Local image:TImage = LoadImage("data/"+path)
		If image Then
			Local gs:gxtkSurface = New gxtkSurface
			gs.setImage(image)
			Return gs
		EndIf
		Return Null
	EndMethod

	Method BeginRender()
	EndMethod

	Method EndRender()
		Flip
	EndMethod

	Method SetColor:Int(r:Int, g:Int, b:Int)
		BlitzMaxSetColor(r, g, b)
		Return 0
	EndMethod

	Method SetAlpha:Int(a:Float)
		BlitzMaxSetAlpha(a)
		Return 0
	EndMethod

	Method SetBlend:Int(blend:Int)
		BlitzMaxSetBlend(blend)
		Return 0
	EndMethod

	Method Width:Int()
		Return GraphicsWidth()
	EndMethod

	Method Height:Int()
		Return GraphicsHeight()
	EndMethod

	Method SetScissor:Int(x:Int, y:Int, w:Int, h:Int)
		SetViewport(x, y, w, h) ' NOT TESTED!
		Return 0
	EndMethod

	Method TransX:Float(x:Float, y:Float)
		Return ix*x + jx*y + tx
	EndMethod

	Method TransY:Float(x:Float, y:Float)
		Return iy*x + jy*y + ty
	EndMethod

	Method SetMatrix:Int(ix:Float,iy:Float,jx:Float,jy:Float,tx:Float,ty:Float)
		Self.ix = ix ; Self.iy = iy
		Self.jx = jx ; Self.jy = jy
		Self.tx = tx ; Self.ty = ty
		sx = Sqr(ix*ix+iy*iy)
		sy = Sqr(jx*jx+jy*jy)
		rot = Atan2( iy, ix )
		If ix < 0 Then
			sx = -sx
			rot :+ 180
		EndIf
		If jy < 0 Then sy = -sy
		SetTransform( rot, sx, sy )
		Return 0
	EndMethod

	Method DrawSurface:Int(surface:gxtkSurface,x:Float,y:Float)
		Local nx:Float = TransX(x,y)
		Local ny:Float = TransY(x,y)
		DrawImage(surface.image, nx, ny, 0)
		Return 0
	EndMethod

	Method DrawSurface2:Int(surface:gxtkSurface,x:Float,y:Float, srcx:Int, srcy:Int, srcw:Int, srch:Int )
		Local nx:Float = TransX(x,y)
		Local ny:Float = TransY(x,y)
		DrawSubImageRect(surface.image, nx, ny, srcw, srch, srcx, srcy, srcw, srch)
		Return 0
	EndMethod

	Method DrawLine:Int( x1:Float,y1:Float,x2:Float,y2:Float )
		Local nx1:Float = TransX(x1,y1)
		Local ny1:Float = TransY(x1,y1)
		Local nx2:Float = TransX(x2,y2)
		Local ny2:Float = TransY(x2,y2)
		' Need to reset transform so that BlitzMax doesn't try to apply rotation
		SetTransform( 0, 1, 1 )
		BlitzMaxDrawLine(nx1, ny1, nx2, ny2)
		SetTransform( rot, sx, sy )
		Return 0
	EndMethod

	Method DrawOval:Int( x:Float, y:Float, w:Float, h:Float )
		Local nx:Float = TransX(x,y)
		Local ny:Float = TransY(x,y)
		BlitzMaxDrawOval(nx, ny, w, h)
		Return 0
	EndMethod

	Method DrawPoly:Int(vertices:Float[])
		' setting the origin to use the current rotation translation
		SetOrigin(TransX(0,0), TransY(0,0))
		BlitzMaxDrawPoly( vertices )
		SetOrigin(0, 0)
		Return 0
	EndMethod

	Method DrawRect:Int( x:Float, y:Float, w:Float, h:Float )
		Local nx:Float = TransX(x,y)
		Local ny:Float = TransY(x,y)
		BlitzMaxDrawRect(nx, ny, w, h)
		Return 0
	EndMethod
EndType

Type gxtkInput
	Method MouseX:Float()
		Return BRL.PolledInput.MouseX()
	EndMethod

	Method MouseY:Float()
		Return BRL.PolledInput.MouseY()
	EndMethod

	Method KeyDown:Int( key:Int )
		if( key = 384 ) key = 1 ' change TOUCH0 to MOUSE_LMB

		If( key >= 1 And key <= 3 )
			Return BRL.PolledInput.MouseDown( key )
		EndIf
		If key < 256
			Return BRL.PolledInput.KeyDown( key )
		Else
			Return 0
		EndIf
	EndMethod

	Method KeyHit:Int( key:Int )
		if( key = 384 ) key = 1 ' change TOUCH0 to MOUSE_LMB
		If( key >= 1 And key <= 3 )
			Return BRL.PolledInput.MouseHit( key )
		EndIf
		If key < 256
			Return BRL.PolledInput.KeyHit( key )
		Else
			Return 0
		EndIf
	EndMethod

	Method GetChar:Int()
		Return BRL.PolledInput.GetChar()
	EndMethod

	Method JoyX:Int( index:Int )
		Return Pub.FreeJoy.JoyX( index )
	EndMethod

	Method JoyY:Int( index:Int )
		Return Pub.FreeJoy.JoyY( index )
	EndMethod

	Method JoyZ:Int( index:Int )
		Return Pub.FreeJoy.JoyZ( index )
	EndMethod

	Method TouchX:Float( index:Int )
		Return BRL.PolledInput.MouseX()
	EndMethod

	Method TouchY:Float( index:Int )
		Return BRL.PolledInput.MouseY()
	EndMethod

	Method AccelX:Int()
		return 0
	EndMethod

	Method AccelY:Int()
		return 0
	EndMethod

	Method AccelZ:Int()
		return 0
	EndMethod

	Method SetKeyboardEnabled:Int( enabled:int )
		Return 0
	EndMethod
EndType

Type gxtkChannel
	Field channel:TChannel	' null then not playing
	Field sample:gxtkSample
	Field loops:int
	'Field transform:SoundTransform=new SoundTransform()
	'Field pausepos:Number
	Field state:int

	Method New()
		channel = New TChannel
	EndMethod
EndType

Type gxtkAudio
	Field amusicState:Int = 0
	Field channels:gxtkChannel[] = New gxtkChannel[33]
	Const MUSIC_CHANNEL:Int = 32
	Field music:gxtkSample

	Method New()
		For local i:Int = 0 To 33 - 1
			channels[i] = New gxtkChannel
			channels[i].channel = AllocChannel()
		Next
	EndMethod

	Method MusicState:Int()
		' Monkey Docs: 	0 if the music is currently stopped
		'				1 if the music is currently playing
		'				-1 if the music state cannot be determined

		Local chan:gxtkChannel = channels[MUSIC_CHANNEL]
		If chan.channel <> Null Then
			If ChannelPlaying(chan.channel) Then Return 1 Else Return 0
		EndIf

		Return -1
	EndMethod

	Method PlayMusic:Int( path:String, flags:Int )
		StopMusic()
		music = LoadSample( path )
		If Not music Then Return -1

		PlaySample(music, MUSIC_CHANNEL, flags)
		Return 0
	EndMethod

	Method StopMusic:Int()
		StopChannel( MUSIC_CHANNEL )

		If music Then
			music.Discard()
			music = null
		EndIf
		Return 0
	EndMethod

	Method ChannelState:int( channel:int )
		' Monkey Docs: 	0 if the channel is currently stopped
		'				1 if the channel is currently playing
		'				2 if the channel is currently paused
		'				-1 if the channel state cannot be determined
		Local chan:gxtkChannel = channels[channel]
		If chan.channel <> Null Then
			If ChannelPlaying(chan.channel) Then Return 1 Else Return 0
		EndIf

		Return -1
	EndMethod

	Method StopChannel( channel:Int )
		Local chan:gxtkChannel = channels[channel]

		If chan.state <> 0
			chan.channel.Stop()
			chan.channel=null
			chan.sample=null
			chan.state=0
		EndIf
	EndMethod

	Method PauseChannel:Int( channel:Int)
		Local chan:gxtkChannel = channels[channel]
		chan.channel.SetPaused(True)
		Return 0
	EndMethod

	Method ResumeChannel:Int( channel:Int)
		Local chan:gxtkChannel = channels[channel]
		chan.channel.SetPaused(False)
		Return 0
	EndMethod

	Method PlaySample( sound:gxtkSample, channel:Int, flags:Int )
		Local chan:gxtkChannel = channels[channel]
		If chan.state <> 0 Then chan.channel.SetPaused(True)

		chan.sample = sound
		chan.loops = flags
		chan.state = 1

		' if looping, we need to reload the sound with the looping flag
		If flags <> sound.loop
			Local smp:TSound = LoadSound(sound.path, flags)
			sound.setSound(smp)
			sound.loop = flags
		EndIf

		PlaySound( sound.sound, chan.channel )
	EndMethod

	Method SetPan( channel:Int, pan:Float )
		Local chan:gxtkChannel = channels[channel]
		chan.channel.SetPan(pan)
	EndMethod

	Method SetRate( channel:Int, rate:Float )
		Local chan:gxtkChannel = channels[channel]
		chan.channel.SetRate(rate)
	EndMethod

	Method PauseMusic:Int()
		Local chan:gxtkChannel = channels[MUSIC_CHANNEL]
		chan.channel.SetPaused(True)
		Return 0
	EndMethod

	Method ResumeMusic:Int()
		Local chan:gxtkChannel = channels[MUSIC_CHANNEL]
		chan.channel.SetPaused(False)
		Return 0
	EndMethod

	Method SetMusicVolume:Int( volume:Float )
		SetVolume( MUSIC_CHANNEL, volume )
		Return 0
	EndMethod

	Method SetVolume:Int( channel:Int, volume:Float )
		Local chan:gxtkChannel = channels[channel]
		chan.channel.SetVolume(volume)
		Return 0
	EndMethod

	Method LoadSample:gxtkSample( path:String )
		Local extension:String = ExtractExt( path)
		If extension = "ogg" Or extension = "wav" Then
			Local sound:TSound = LoadSound("data/"+path)
			If sound Then
				Local gs:gxtkSample = New gxtkSample
				gs.setSound(sound)
				gs.path = "data/"+path
				Return gs
			EndIf
		Else
			RuntimeError "BlitzMax can only use ogg and wav file formats"
		EndIf
		Return Null
	EndMethod
EndType

Type gxtkSample
	Field sound:TSound
	Field path:String
	Field loop:Int

	Method setSound(sound:TSound)
		Self.sound = sound
	EndMethod

	Method Discard()
		Self.sound = null
	EndMethod
EndType

Function BlitzMaxDrawPoly:Int(vertices:Float[])
	DrawPoly vertices
	Return 0
EndFunction

Function BlitzMaxDrawRect:Int( x:Float, y:Float, w:Float, h:Float )
	DrawRect x, y, w, h
	Return 0
EndFunction

Function BlitzMaxDrawOval:Int( x:Float, y:Float, w:Float, h:Float )
	DrawOval x, y, w, h
	Return 0
EndFunction

Function BlitzMaxDrawLine:Int( x1:Float,y1:Float,x2:Float,y2:Float )
	DrawLine x1, y1, x2, y2
	Return 0
EndFunction

Function BlitzMaxMillisecs:Int()
	Return MilliSecs()
EndFunction

Function BlitzMaxSetColor(r:Int, g:Int, b:Int)
	SetColor(r, g, b)
EndFunction

Function BlitzMaxSetBlend(blend:Int)
	Select blend
		Case 0
			SetBlend( ALPHABLEND )
		Case 1
			SetBlend( LIGHTBLEND )
	End Select
EndFunction

Function BlitzMaxSetAlpha(a:Float)
	SetAlpha(a)
EndFunction

Function BlitzMaxCls(r:Int = 0, g:Int = 0, b:Int = 0)
	SetClsColor(r, g, b)
	Cls
EndFunction

Type gxtkSurface
	Field w:Int, h:Int
	Field image:TImage

	Method setImage(image:TImage)
		Self.image = image
	EndMethod

	Method Width:Int()
		Return image.Width
	EndMethod

	Method Height:Int()
		Return image.Height
	EndMethod

	Method Discard()
	EndMethod
EndType

' ***** End mojo.bmax.bmx ******


reinsert right number of items

reinsert right number of items

' Blue Moon
' Lua-table implementation
' uses simple linear probing for collision resolution and a shockingly naive reallocator

SuperStrict

Import "blueallocator.bmx"

Private
Extern
	Function frexp:Double(d:Double, Exp:Int Ptr) = "frexp"
End Extern
Public

Type BlueTable Final
	Function Get:Long(tbl:Byte Ptr, key:Long)
		Local tag:Int = Int Ptr(Varptr(key))[1], idx:Int

		If tag = BlueTypeTag.NANBOX | BlueTypeTag.STR	'string - common case
			idx = Int Ptr(Int(key))[1]
		ElseIf tag & BlueTypeTag.NANBOX_CHK <> BlueTypeTag.NANBOX	'number
			Local d:Double ; Long Ptr(Varptr(d))[0] = key ; idx = Abs Int(d)
			If d = idx	'int key
				Local arr:Byte Ptr = Byte Ptr Ptr(tbl)[3]
				If arr And idx < Int Ptr(arr)[-1] Then Return Long Ptr(arr)[idx]	'if this is nil, it won't be in the hash part anyway
			Else
				d = frexp(d, Varptr(idx)) * ($7fffffff - 1024)	'INT_MAX - DBL_MAX_EXP
				idx = Abs(idx) + Int(d)
			EndIf
		ElseIf tag = BlueTypeTag.NANBOX | BlueTypeTag.NIL	'nil -> nil
			Return key
		Else	'pointer (needs improvement)
			idx = Int(key) Shr 3
		EndIf

		Local hashpart:Byte Ptr = Byte Ptr Ptr(tbl)[2]
		If hashpart
			Local hsize:Int = 1 Shl Int Ptr(hashpart)[-1]
			idx = idx & (hsize - 1)	'apparently this is faster than Mod
			For Local i:Int = idx Until hsize	'naive linear probe
				If Long Ptr(hashpart)[2 * i] = key Then Return Long Ptr(hashpart)[2 * i + 1]
			Next
			For Local i:Int = 0 Until idx	'yep
				If Long Ptr(hashpart)[2 * i] = key Then Return Long Ptr(hashpart)[2 * i + 1]
			Next
		EndIf

		Local ret:Long ; Int Ptr(Varptr(ret))[1] = BlueTypeTag.NANBOX | BlueTypeTag.NIL	'why can't i shift longs?
		Return ret
	End Function

	Function Set(mem:BlueVMMemory, tbl:Byte Ptr, key:Long, val:Long)
		Local tag:Int = Int Ptr(Varptr(key))[1], idx:Int, slot:Long Ptr = Null, writeKey:Int = False
		Const NILTAG:Int = BlueTypeTag.NANBOX | BlueTypeTag.NIL

		If tag = NILTAG Then Return	'nil is not a valid key

		If tag & BlueTypeTag.NANBOX_CHK <> BlueTypeTag.NANBOX	'if key is an int and less than arraylength
			Local d:Double ; Long Ptr(Varptr(d))[0] = key ; idx = Abs Int(d)
			If d = idx
				Local arraypart:Byte Ptr = Byte Ptr Ptr(tbl)[3]
				If arraypart <> Null And idx < Int Ptr(arraypart)[-1] Then slot = Long Ptr(arraypart) + idx
			EndIf
		EndIf
		If slot = Null	'elsewise if hashcount < hashsize
			Local hashpart:Byte Ptr = Byte Ptr Ptr(tbl)[2]
			If hashpart <> Null
				Local hsize:Int = 1 Shl Int Ptr(hashpart)[-1]
				If Int Ptr(hashpart)[-2] < hsize	'there's a slot free somewhere

					If tag = BlueTypeTag.NANBOX | BlueTypeTag.STR	'string - common case
						idx = Int Ptr(Int(key))[1]
					ElseIf tag & BlueTypeTag.NANBOX_CHK <> BlueTypeTag.NANBOX	'non-integer
						Local d:Double ; Long Ptr(Varptr(d))[0] = key
						d = frexp(d, Varptr(idx)) * ($7fffffff - 1024)	'INT_MAX - DBL_MAX_EXP
						idx = Abs(idx) + Int(d)
					Else	'pointer
						idx = Int(key) Shr 3
					EndIf

					idx = idx & (hsize - 1)	'fastmod
					For Local i:Int = idx Until hsize
						If Long Ptr(hashpart)[2 * i] = key Or Int Ptr(hashpart)[4 * i + 1] = NILTAG Then slot = Long Ptr(hashpart) + (2 * i + 1) ; Exit
					Next
					If Not slot
						For Local i:Int = 0 Until idx
							If Long Ptr(hashpart)[2 * i] = key Or Int Ptr(hashpart)[4 * i + 1] = NILTAG Then slot = Long Ptr(hashpart) + (2 * i + 1) ; Exit
						Next
					EndIf

				EndIf
			EndIf
			If slot Then Int Ptr(hashpart)[-2] :+ 1	'no write barrier needed to increment use count (not pointer)
			writeKey = True
		EndIf

		If slot = Null
			Resize(mem, tbl, key) ; Set mem, tbl, key, val
		Else
			mem.Write(slot, val)
			If writeKey Then mem.Write(slot - 1, key)
		EndIf
	End Function

	Function Resize(mem:BlueVMMemory, tbl:Byte Ptr, key:Long)
		Local hashpart:Byte Ptr = Byte Ptr Ptr(tbl)[2], arraypart:Byte Ptr = Byte Ptr Ptr(tbl)[3]
		Const NILTAG:Int = BlueTypeTag.NANBOX | BlueTypeTag.NIL

		Local asize:Int = 0, tsize:Int = 0, numcount:Int[32]
		If arraypart	'compute new array size
			If Int Ptr(arraypart)[1] <> NILTAG Then numcount[0] = 1
			Local cell:Int = 1, cellp2:Int = 2 ^ cell
			For Local i:Int = 1 Until Int Ptr(arraypart)[-1]
				If i >= cellp2 Then cell :+ 1 ; cellp2 = 2 ^ cell
				If Int Ptr(arraypart)[i * 2 + 1] <> NILTAG Then numcount[cell] :+ 1
			Next
		EndIf
		If hashpart
			For Local i:Int = 0 Until Int Ptr(hashpart)[-2]
				Local tag2:Int = Int Ptr(hashpart)[i * 4 + 1]
				If tag2 & BlueTypeTag.NANBOX_CHK <> BlueTypeTag.NANBOX
					Local d:Double = Double Ptr(hashpart)[i * 2]
					If d = Abs Int(d) Then numcount[Ceil(Log(d + 1) / Log(2))] :+ 1 Else tsize :+ 1
				Else
					tsize :+ 1	'get started on new table size
				EndIf
			Next
		EndIf

		Local tag:Int = Int Ptr(Varptr(key))[1]	'add key to the appropriate one
		If tag & BlueTypeTag.NANBOX_CHK <> BlueTypeTag.NANBOX
			Local d:Double = Double Ptr(Varptr(key))[0]
			If d = Abs Int(d) Then numcount[Ceil(Log(d + 1) / Log(2))] :+ 1 Else tsize :+ 1
		Else
			tsize :+ 1
		EndIf
		For Local i:Int = 0 Until 32	'tally up
			If i Then numcount[i] :+ numcount[i - 1]
			If numcount[i] > 2 ^ i / 2 Then asize = 2 ^ i
		Next
		If arraypart <> Null	'complete new table size with any discarded array elements
			For Local i:Int = asize Until Int Ptr(arraypart)[-1]
				If Int Ptr(arraypart)[i * 2 + 1] <> NILTAG Then tsize :+ 1
			Next
		EndIf

		Local newarray:Byte Ptr = Null, newtable:Byte Ptr = Null	'allocate and copy
		Local oldasize:Int = 0 ; If arraypart Then oldasize = Int Ptr(arraypart)[-1]
		Local oldtsize:Int = 0 ; If hashpart Then oldtsize = Int Ptr(hashpart)[-1]

		If asize <> oldasize
			newarray = mem.AllocObject(asize * 8 + 8, BlueTypeTag.ARR) + 8
			For Local i:Int = 0 Until asize
				Int Ptr(newarray)[i * 2 + 1] = NILTAG
			Next
			Int Ptr(newarray)[-1] = asize ; Byte Ptr Ptr(tbl)[3] = newarray
		ElseIf asize = 0
			Int Ptr(tbl)[3] = 0
		Else
			newarray = arraypart ; arraypart = Null
		EndIf
		If tsize <> oldtsize
			newtable = mem.AllocObject(2 ^ tsize * 16 + 8, BlueTypeTag.HASH)
			For Local i:Int = 0 Until 2 ^ tsize * 2
				Int Ptr(newtable)[i * 2 + 1] = NILTAG
			Next
			Int Ptr(newtable)[-1] = tsize ; Int Ptr(newtable)[-2] = 0
			Byte Ptr Ptr(tbl)[2] = newtable
		ElseIf tsize = 0
			Int Ptr(tbl)[2] = 0
		Else
			newtable = hashpart ; hashpart = Null
		EndIf

		If arraypart
			For Local i:Int = 0 Until oldasize	'reinsert values
				Local key:Long ; Double Ptr(Varptr(key))[0] = i
				Set mem, tbl, key,Long Ptr(arraypart)[i]
			Next
		EndIf
		If hashpart
			For Local i:Int = 0 Until 2 ^ oldtsize
				Set mem, tbl, Long Ptr(hashpart)[i * 2], Long Ptr(hashpart)[i * 2 + 1]
			Next
		EndIf
	End Function
End Type

' Blue Moon
' Lua-table implementation
' uses simple linear probing for collision resolution and a shockingly naive reallocator

SuperStrict

Import "blueallocator.bmx"

Private
Extern
	Function frexp:Double(d:Double, Exp:Int Ptr) = "frexp"
End Extern
Public

Type BlueTable Final
	Function Get:Long(tbl:Byte Ptr, key:Long)
		Local tag:Int = Int Ptr(Varptr(key))[1], idx:Int

		If tag = BlueTypeTag.NANBOX | BlueTypeTag.STR	'string - common case
			idx = Int Ptr(Int(key))[1]
		ElseIf tag & BlueTypeTag.NANBOX_CHK <> BlueTypeTag.NANBOX	'number
			Local d:Double ; Long Ptr(Varptr(d))[0] = key ; idx = Abs Int(d)
			If d = idx	'int key
				Local arr:Byte Ptr = Byte Ptr Ptr(tbl)[3]
				If arr And idx < Int Ptr(arr)[-1] Then Return Long Ptr(arr)[idx]	'if this is nil, it won't be in the hash part anyway
			Else
				d = frexp(d, Varptr(idx)) * ($7fffffff - 1024)	'INT_MAX - DBL_MAX_EXP
				idx = Abs(idx) + Int(d)
			EndIf
		ElseIf tag = BlueTypeTag.NANBOX | BlueTypeTag.NIL	'nil -> nil
			Return key
		Else	'pointer (needs improvement)
			idx = Int(key) Shr 3
		EndIf

		Local hashpart:Byte Ptr = Byte Ptr Ptr(tbl)[2]
		If hashpart
			Local hsize:Int = 1 Shl Int Ptr(hashpart)[-1]
			idx = idx & (hsize - 1)	'apparently this is faster than Mod
			For Local i:Int = idx Until hsize	'naive linear probe
				If Long Ptr(hashpart)[2 * i] = key Then Return Long Ptr(hashpart)[2 * i + 1]
			Next
			For Local i:Int = 0 Until idx	'yep
				If Long Ptr(hashpart)[2 * i] = key Then Return Long Ptr(hashpart)[2 * i + 1]
			Next
		EndIf

		Local ret:Long ; Int Ptr(Varptr(ret))[1] = BlueTypeTag.NANBOX | BlueTypeTag.NIL	'why can't i shift longs?
		Return ret
	End Function

	Function Set(mem:BlueVMMemory, tbl:Byte Ptr, key:Long, val:Long)
		Local tag:Int = Int Ptr(Varptr(key))[1], idx:Int, slot:Long Ptr = Null, writeKey:Int = False
		Const NILTAG:Int = BlueTypeTag.NANBOX | BlueTypeTag.NIL

		If tag = NILTAG Then Return	'nil is not a valid key

		If tag & BlueTypeTag.NANBOX_CHK <> BlueTypeTag.NANBOX	'if key is an int and less than arraylength
			Local d:Double ; Long Ptr(Varptr(d))[0] = key ; idx = Abs Int(d)
			If d = idx
				Local arraypart:Byte Ptr = Byte Ptr Ptr(tbl)[3]
				If arraypart <> Null And idx < Int Ptr(arraypart)[-1] Then slot = Long Ptr(arraypart) + idx
			EndIf
		EndIf
		If slot = Null	'elsewise if hashcount < hashsize
			Local hashpart:Byte Ptr = Byte Ptr Ptr(tbl)[2]
			If hashpart <> Null
				Local hsize:Int = 1 Shl Int Ptr(hashpart)[-1]
				If Int Ptr(hashpart)[-2] < hsize	'there's a slot free somewhere

					If tag = BlueTypeTag.NANBOX | BlueTypeTag.STR	'string - common case
						idx = Int Ptr(Int(key))[1]
					ElseIf tag & BlueTypeTag.NANBOX_CHK <> BlueTypeTag.NANBOX	'non-integer
						Local d:Double ; Long Ptr(Varptr(d))[0] = key
						d = frexp(d, Varptr(idx)) * ($7fffffff - 1024)	'INT_MAX - DBL_MAX_EXP
						idx = Abs(idx) + Int(d)
					Else	'pointer
						idx = Int(key) Shr 3
					EndIf

					idx = idx & (hsize - 1)	'fastmod
					For Local i:Int = idx Until hsize
						If Long Ptr(hashpart)[2 * i] = key Or Int Ptr(hashpart)[4 * i + 1] = NILTAG Then slot = Long Ptr(hashpart) + (2 * i + 1) ; Exit
					Next
					If Not slot
						For Local i:Int = 0 Until idx
							If Long Ptr(hashpart)[2 * i] = key Or Int Ptr(hashpart)[4 * i + 1] = NILTAG Then slot = Long Ptr(hashpart) + (2 * i + 1) ; Exit
						Next
					EndIf

				EndIf
			EndIf
			If slot Then Int Ptr(hashpart)[-2] :+ 1	'no write barrier needed to increment use count (not pointer)
			writeKey = True
		EndIf

		If slot = Null
			Resize(mem, tbl, key) ; Set mem, tbl, key, val
		Else
			mem.Write(slot, val)
			If writeKey Then mem.Write(slot - 1, key)
		EndIf
	End Function

	Function Resize(mem:BlueVMMemory, tbl:Byte Ptr, key:Long)
		Local hashpart:Byte Ptr = Byte Ptr Ptr(tbl)[2], arraypart:Byte Ptr = Byte Ptr Ptr(tbl)[3]
		Const NILTAG:Int = BlueTypeTag.NANBOX | BlueTypeTag.NIL

		Local asize:Int = 0, tsize:Int = 0, numcount:Int[32]
		If arraypart	'compute new array size
			If Int Ptr(arraypart)[1] <> NILTAG Then numcount[0] = 1
			Local cell:Int = 1, cellp2:Int = 2 ^ cell
			For Local i:Int = 1 Until Int Ptr(arraypart)[-1]
				If i >= cellp2 Then cell :+ 1 ; cellp2 = 2 ^ cell
				If Int Ptr(arraypart)[i * 2 + 1] <> NILTAG Then numcount[cell] :+ 1
			Next
		EndIf
		If hashpart
			For Local i:Int = 0 Until Int Ptr(hashpart)[-2]
				Local tag2:Int = Int Ptr(hashpart)[i * 4 + 1]
				If tag2 & BlueTypeTag.NANBOX_CHK <> BlueTypeTag.NANBOX
					Local d:Double = Double Ptr(hashpart)[i * 2]
					If d = Abs Int(d) Then numcount[Ceil(Log(d + 1) / Log(2))] :+ 1 Else tsize :+ 1
				Else
					tsize :+ 1	'get started on new table size
				EndIf
			Next
		EndIf

		Local tag:Int = Int Ptr(Varptr(key))[1]	'add key to the appropriate one
		If tag & BlueTypeTag.NANBOX_CHK <> BlueTypeTag.NANBOX
			Local d:Double = Double Ptr(Varptr(key))[0]
			If d = Abs Int(d) Then numcount[Ceil(Log(d + 1) / Log(2))] :+ 1 Else tsize :+ 1
		Else
			tsize :+ 1
		EndIf
		For Local i:Int = 0 Until 32	'tally up
			If i Then numcount[i] :+ numcount[i - 1]
			If numcount[i] > 2 ^ i / 2 Then asize = 2 ^ i
		Next
		If arraypart <> Null	'complete new table size with any discarded array elements
			For Local i:Int = asize Until Int Ptr(arraypart)[-1]
				If Int Ptr(arraypart)[i * 2 + 1] <> NILTAG Then tsize :+ 1
			Next
		EndIf

		Local newarray:Byte Ptr = Null, newtable:Byte Ptr = Null	'allocate and copy
		Local oldasize:Int = 0 ; If arraypart Then oldasize = Int Ptr(arraypart)[-1]
		Local oldtsize:Int = 0 ; If hashpart Then oldtsize = Int Ptr(hashpart)[-1]

		If asize <> oldasize
			newarray = mem.AllocObject(asize * 8 + 8, BlueTypeTag.ARR) + 8
			For Local i:Int = 0 Until asize
				Int Ptr(newarray)[i * 2 + 1] = NILTAG
			Next
			Int Ptr(newarray)[-1] = asize ; Byte Ptr Ptr(tbl)[3] = newarray
		ElseIf asize = 0
			Int Ptr(tbl)[3] = 0
		Else
			newarray = arraypart ; arraypart = Null
		EndIf
		If tsize <> oldtsize
			newtable = mem.AllocObject(2 ^ tsize * 16 + 8, BlueTypeTag.HASH)
			For Local i:Int = 0 Until 2 ^ tsize * 2
				Int Ptr(newtable)[i * 2 + 1] = NILTAG
			Next
			Int Ptr(newtable)[-1] = tsize ; Int Ptr(newtable)[-2] = 0
			Byte Ptr Ptr(tbl)[2] = newtable
		ElseIf tsize = 0
			Int Ptr(tbl)[2] = 0
		Else
			newtable = hashpart ; hashpart = Null
		EndIf

		If arraypart
			For Local i:Int = 0 Until oldasize	'reinsert values
				Local key:Long ; Double Ptr(Varptr(key))[0] = i
				Set mem, tbl, key,Long Ptr(arraypart)[i]
			Next
		EndIf
		If hashpart
			For Local i:Int = 0 Until oldtsize
				Set mem, tbl, Long Ptr(hashpart)[i * 2], Long Ptr(hashpart)[i * 2 + 1]
			Next
		EndIf
	End Function
End Type


Fixed userAgent string to match module name

Rem
	bbdoc: Transport interface. Use this as a blueprint for any other transport layers
End Rem
Type TXMLRPC_Transport_Interface Abstract
	Rem
		bbdoc: Send request to XML-RPC server
	End Rem
	Method DoRequest:String(message:String) Abstract
End Type

Rem
	bbdoc: A Dummy transport type. Do not use, deprecated
End Rem
Type TXMLRPC_Transport_Dummy Extends TXMLRPC_Transport_Interface
	Method DoRequest:String(message:String)
		Return message
	End Method
End Type

Rem
	bbdoc: Exception for TXMLRPC_Transport_Http
End Rem
Type TXMLRPC_Transport_Http_Exception Extends TXMLRPC_Exception
End Type

Rem
	bbdoc: Simple HTTP transport
	about: Needs HTTP error handling. Implementation is very simple at the moment. Only a simple HTTP request is possible. Authenticated pages or HTTPS isn't supported. For HTTPS, write your own.
End Rem
Type TXMLRPC_Transport_Http Extends TXMLRPC_Transport_Interface
	Field host:String
	Field path:String
	Field port:Int

	Rem
		bbdoc: Set useragent for HTTP request.
		about: This string will be used to identify the client with the XML-RPC server
	End rem
	Field userAgent:String = "htbaapub.mod/xmlrpc.mod"

	Rem
		bbdoc: Create TXMLRPC_Transport_Http object
	End Rem
	Method Create:TXMLRPC_Transport_Http(host:String, path:String, port:Int = 80)
		Self.host = host
		Self.path = path
		Self.port = port
		Return Self
	End Method

	Rem
		bbdoc: Send request over HTTP
	End Rem
	Method DoRequest:String(message:String)
		Local socket:TSocket = CreateTCPSocket()

		If Not ConnectSocket(socket, HostIp(Self.host), Self.port)
			Throw New TXMLRPC_Transport_Http_Exception.Create("Couldn't open socket to " + Self.host)
		End If

		Local stream:TSocketStream = CreateSocketStream(socket)

		WriteLine(stream, "POST " + Self.path + " HTTP/1.0")
		WriteLine(stream, "Accept: */*")
		WriteLine(stream, "Host: " + Self.host)
		WriteLine(stream, "Content-type: application/x-www-form-urlencoded")
		WriteLine(stream, "User-agent: " + Self.userAgent)
		WriteLine(stream, "Pragma: no-cache")
		WriteLine(stream, "Connection: keep-alive")
		WriteLine(stream, "Content-length: " + message.Length + "~n")

		WriteLine(stream, message + "~n~n")

		FlushStream(stream)

		Local buffer:String
		While Not Eof(stream)
			Local line:String = ReadLine(stream)
			buffer:+line + "~n"
		Wend

		CloseSocket(socket)
		Return buffer
	End Method
End Type

Rem
	bbdoc: Transport interface. Use this as a blueprint for any other transport layers
End Rem
Type TXMLRPC_Transport_Interface Abstract
	Rem
		bbdoc: Send request to XML-RPC server
	End Rem
	Method DoRequest:String(message:String) Abstract
End Type

Rem
	bbdoc: A Dummy transport type. Do not use, deprecated
End Rem
Type TXMLRPC_Transport_Dummy Extends TXMLRPC_Transport_Interface
	Method DoRequest:String(message:String)
		Return message
	End Method
End Type

Rem
	bbdoc: Exception for TXMLRPC_Transport_Http
End Rem
Type TXMLRPC_Transport_Http_Exception Extends TXMLRPC_Exception
End Type

Rem
	bbdoc: Simple HTTP transport
	about: Needs HTTP error handling, as well as a set time out. Implementation is very simple at the moment. Only a simple HTTP request is possible. Authenticated pages or HTTPS isn't supported. For HTTPS, write your own.
End Rem
Type TXMLRPC_Transport_Http Extends TXMLRPC_Transport_Interface
	Field host:String
	Field path:String
	Field port:Int

	Rem
		bbdoc: Set useragent for HTTP request.
		about: This string will be used to identify the client with the XML-RPC server
	End rem
	Field userAgent:String = "htbaa.mod/xmlrpc.mod"

	Rem
		bbdoc: Create TXMLRPC_Transport_Http object
	End Rem
	Method Create:TXMLRPC_Transport_Http(host:String, path:String, port:Int = 80)
		Self.host = host
		Self.path = path
		Self.port = port
		Return Self
	End Method

	Rem
		bbdoc: Send request over HTTP
	End Rem
	Method DoRequest:String(message:String)
		Local socket:TSocket = CreateTCPSocket()

		If Not ConnectSocket(socket, HostIp(Self.host), Self.port)
			Throw New TXMLRPC_Transport_Http_Exception.Create("Couldn't open socket to " + Self.host)
		End If

		Local stream:TSocketStream = CreateSocketStream(socket)

		WriteLine(stream, "POST " + Self.path + " HTTP/1.0")
		WriteLine(stream, "Accept: */*")
		WriteLine(stream, "Host: " + Self.host)
		WriteLine(stream, "Content-type: application/x-www-form-urlencoded")
		WriteLine(stream, "User-agent: " + Self.userAgent)
		WriteLine(stream, "Pragma: no-cache")
		WriteLine(stream, "Connection: keep-alive")
		WriteLine(stream, "Content-length: " + message.Length + "~n")

		WriteLine(stream, message + "~n~n")

		FlushStream(stream)

		Local buffer:String
		While Not Eof(stream)
			Local line:String = ReadLine(stream)
			buffer:+line + "~n"
		Wend

		CloseSocket(socket)
		Return buffer
	End Method
End Type


Fixed b3dloader texture coordinate set issues.

Strict

Rem
	bbdoc: Blitz3D model loader for MaxB3D
End Rem
Module MaxB3D.B3DLoader
ModuleInfo "Author: Kevin Primm"
ModuleInfo "License: MIT"

Import MaxB3D.Core
Import MaxB3D.BoneAnimator
Import Prime.libB3D

Type TMeshLoaderB3D Extends TMeshLoader
	Field _mesh:TMesh

	Method Run(mesh:TMesh,stream:TStream,url:Object)
		Local model:TBB3DChunk=TBB3DChunk.Load(url)
		If model=Null Return False

		Local olddir$=CurrentDir()
		If String(url) ChangeDir(ExtractDir(String(url)))

		Local texture:TTexture[model.texs.length]
		Local brush:TBrush[model.brus.length]

		For Local i=0 To texture.length-1
			Local chunk:TTEXSChunk=model.texs[i]
			texture[i]=_currentworld.AddTexture(chunk.file,chunk.flags)
			If texture[i]
				texture[i].SetBlend chunk.blend
				texture[i].SetPosition chunk.x_pos,chunk.y_pos
				texture[i].SetScale chunk.x_scale,chunk.y_scale
				texture[i].SetRotation chunk.rotation*(180.0/Pi)
				If chunk.flags&65536 texture[i].SetCoords 1
			EndIf
		Next

		For Local i=0 To brush.length-1
			Local chunk:TBRUSChunk=model.brus[i]
			brush[i]=_currentworld.AddBrush()
			brush[i].SetName chunk.name
			brush[i].SetColor chunk.red*255,chunk.green*255,chunk.blue*255;brush[i].SetAlpha chunk.alpha
			brush[i].SetShine chunk.shininess
			brush[i].SetBlend chunk.blend;brush[i].SetFX chunk.fx
			For Local j=0 To chunk.n_texs-1
				If chunk.texture_id[j]>-1 brush[i].SetTexture texture[chunk.texture_id[j]],j
			Next
		Next
		ChangeDir olddir

		' model.dump StandardIOStream

		If model.node
			ParseNode model.node,mesh,brush,mesh
			Return True
		EndIf
		Return False
	End Method

	Method ParseNode(node:TNODEChunk,parent:TEntity,brush:TBrush[],entity:TEntity=Null)
		Local meshchunk:TMESHChunk=TMESHChunk(node.kind),bonechunk:TBONEChunk=TBONEChunk(node.kind)

		Select node.kind
		Case Null
			entity=_currentworld.AddPivot(parent)
		Case meshchunk
			If entity=Null entity=_currentworld.AddMesh("*null*",parent)
			Local mesh:TMesh=TMesh(entity)
			mesh._animator=New TBoneAnimator
			_mesh=mesh

			If meshchunk.brush_id>-1 entity.SetBrush brush[meshchunk.brush_id]

			Local vrts:TVRTSChunk=meshchunk.vrts
			Local vertsurface:TSurface=New TSurface
			vertsurface.Resize(vrts.xyz.length/3,0)

			For Local i=0 To vertsurface.CountVertices()-1
				vertsurface.SetCoords i,vrts.xyz[i*3+0],vrts.xyz[i*3+1],vrts.xyz[i*3+2]
				If vrts.nxyz vertsurface.SetNormal i,vrts.nxyz[i*3+0],vrts.nxyz[i*3+1],vrts.nxyz[i*3+2]
				If vrts.rgba vertsurface.SetColor i,vrts.rgba[i*4+0]*255,vrts.rgba[i*4+1]*255,vrts.rgba[i*4+2]*255,vrts.rgba[i*4+3]
				For Local j=0 To vrts.SetCount()-1
					Local u#,v#
					If vrts.SetSize()>1 u=vrts.tex_coords[i][j,0];v=vrts.tex_coords[i][j,1]
					vertsurface.SetTexCoords i,1-u,v,j
				Next
			Next

			For Local i=0 To meshchunk.tris.length-1
				Local tri:TTRISChunk=meshchunk.tris[i]
				Local surface:TSurface=vertsurface.Copy()
				surface.Resize(-1,tri.vertex_id.length/3)
				If tri.brush_id>-1 surface.SetBrush brush[tri.brush_id]
				For Local t=0 To surface.CountTriangles()-1
					surface.SetTriangle t,tri.vertex_id[t*3+0],tri.vertex_id[t*3+1],tri.vertex_id[t*3+2]
				Next
				If vrts.nxyz=Null surface.UpdateNormals
				mesh.AppendSurface surface
			Next
		Case bonechunk
			entity=_currentworld.AddBone(parent)
			Local bone:TBone=TBone(entity)

			For Local surface:TSurface=EachIn _mesh._surfaces
				bone.AddSurface surface
				For Local i=0 To bonechunk.vertex_id.length-1
					bone.AddVertex surface,bonechunk.vertex_id[i],bonechunk.weight[i]
				Next
			Next

			Local ident_matrix:TMatrix=TMatrix.Identity()
			For Local chunk:TKEYSChunk=EachIn node.keys
				Local keys:TAnimKey[chunk.frame.length]
				Local pos#[]=chunk.position,rot#[]=chunk.rotation,scl#[]=chunk.scale
				For Local i=0 To chunk.frame.length-1
					Local bonekey:TBoneKey=New TBoneKey

					If pos.length>0 bonekey._px=pos[i*3+0];bonekey._py=pos[i*3+1];bonekey._pz=pos[i*3+2]
					If rot.length>0 bonekey._rw=rot[i*4+0];bonekey._rx=rot[i*4+1];bonekey._ry=rot[i*4+2];bonekey._rz=rot[i*4+3]
					If scl.length>0 bonekey._sx=scl[i*3+0];bonekey._sy=scl[i*3+1];bonekey._sz=scl[i*3+2]

					Local key:TAnimKey=New TAnimKey
					key._frame=chunk.frame[i]
					key._object=bonekey
					keys[i]=key
				Next
				TBoneAnimator(_mesh._animator).AddBone bone,keys
			Next
		Default
			entity=_currentworld.AddPivot(parent)
		End Select

		entity.SetName node.name
		entity.SetPosition node.position[0],node.position[1],node.position[2]
		Local pitch#,yaw#,roll#
		TQuaternion.Euler node.rotation[0],node.rotation[1],node.rotation[2],node.rotation[3],pitch,yaw,roll
		entity.SetRotation pitch,yaw,roll
		entity.SetScale node.scale[0],node.scale[1],node.scale[2]

		For Local child:TNODEChunk=EachIn node.node
			ParseNode child,entity,brush
		Next
		If TMesh(entity) If TBoneAnimator(TMesh(entity)._animator)._root=Null TMesh(entity)._animator=Null
		If TBone(entity) TBone(entity)._start_matrix=entity.GetMatrix()
	End Method

	Method Info$()
		Return "Blitz3D|b3d"
	End Method
	Method ModuleName$()
		Return "b3dloader"
	End Method
End Type
New TMeshLoaderB3D

Strict

Rem
	bbdoc: Blitz3D model loader for MaxB3D
End Rem
Module MaxB3D.B3DLoader
ModuleInfo "Author: Kevin Primm"
ModuleInfo "License: MIT"

Import MaxB3D.Core
Import MaxB3D.BoneAnimator
Import Prime.libB3D

Type TMeshLoaderB3D Extends TMeshLoader
	Field _mesh:TMesh

	Method Run(mesh:TMesh,stream:TStream,url:Object)
		Local model:TBB3DChunk=TBB3DChunk.Load(url)
		If model=Null Return False

		Local olddir$=CurrentDir()
		If String(url) ChangeDir(ExtractDir(String(url)))

		Local texture:TTexture[model.texs.length]
		Local brush:TBrush[model.brus.length]

		For Local i=0 To texture.length-1
			Local chunk:TTEXSChunk=model.texs[i]
			texture[i]=_currentworld.AddTexture(chunk.file,chunk.flags)
			If texture[i]
				texture[i].SetBlend chunk.blend
				texture[i].SetPosition chunk.x_pos,chunk.y_pos
				texture[i].SetScale chunk.x_scale,chunk.y_scale
				texture[i].SetRotation chunk.rotation*(180.0/Pi)
			EndIf
		Next

		For Local i=0 To brush.length-1
			Local chunk:TBRUSChunk=model.brus[i]
			brush[i]=_currentworld.AddBrush()
			brush[i].SetName chunk.name
			brush[i].SetColor chunk.red*255,chunk.green*255,chunk.blue*255;brush[i].SetAlpha chunk.alpha
			brush[i].SetShine chunk.shininess
			brush[i].SetBlend chunk.blend;brush[i].SetFX chunk.fx
			For Local j=0 To chunk.n_texs-1
				If chunk.texture_id[j]>-1 brush[i].SetTexture texture[chunk.texture_id[j]],j
			Next
		Next
		ChangeDir olddir

		' model.dump StandardIOStream

		If model.node
			ParseNode model.node,mesh,brush,mesh
			Return True
		EndIf
		Return False
	End Method

	Method ParseNode(node:TNODEChunk,parent:TEntity,brush:TBrush[],entity:TEntity=Null)
		Local meshchunk:TMESHChunk=TMESHChunk(node.kind),bonechunk:TBONEChunk=TBONEChunk(node.kind)

		Select node.kind
		Case Null
			entity=_currentworld.AddPivot(parent)
		Case meshchunk
			If entity=Null entity=_currentworld.AddMesh("*null*",parent)
			Local mesh:TMesh=TMesh(entity)
			mesh._animator=New TBoneAnimator
			_mesh=mesh

			If meshchunk.brush_id>-1 entity.SetBrush brush[meshchunk.brush_id]

			Local vrts:TVRTSChunk=meshchunk.vrts
			Local vertsurface:TSurface=New TSurface
			vertsurface.Resize(vrts.xyz.length/3,0)

			For Local i=0 To vertsurface.CountVertices()-1
				vertsurface.SetCoords i,vrts.xyz[i*3+0],vrts.xyz[i*3+1],vrts.xyz[i*3+2]
				If vrts.nxyz vertsurface.SetNormal i,vrts.nxyz[i*3+0],vrts.nxyz[i*3+1],vrts.nxyz[i*3+2]
				If vrts.rgba vertsurface.SetColor i,vrts.rgba[i*4+0]*255,vrts.rgba[i*4+1]*255,vrts.rgba[i*4+2]*255,vrts.rgba[i*4+3]
				For Local j=0 To vrts.SetCount()-1
					Local u#,v#
					If vrts.SetSize()>1 u=vrts.tex_coords[i][j,0];v=vrts.tex_coords[i][j,1]
					vertsurface.SetTexCoords i,1-u,v
				Next
			Next

			For Local i=0 To meshchunk.tris.length-1
				Local tri:TTRISChunk=meshchunk.tris[i]
				Local surface:TSurface=vertsurface.Copy()
				surface.Resize(-1,tri.vertex_id.length/3)
				If tri.brush_id>-1 surface.SetBrush brush[tri.brush_id]
				For Local t=0 To surface.CountTriangles()-1
					surface.SetTriangle t,tri.vertex_id[t*3+0],tri.vertex_id[t*3+1],tri.vertex_id[t*3+2]
				Next
				If vrts.nxyz=Null surface.UpdateNormals
				mesh.AppendSurface surface
			Next
		Case bonechunk
			entity=_currentworld.AddBone(parent)
			Local bone:TBone=TBone(entity)

			For Local surface:TSurface=EachIn _mesh._surfaces
				bone.AddSurface surface
				For Local i=0 To bonechunk.vertex_id.length-1
					bone.AddVertex surface,bonechunk.vertex_id[i],bonechunk.weight[i]
				Next
			Next

			Local ident_matrix:TMatrix=TMatrix.Identity()
			For Local chunk:TKEYSChunk=EachIn node.keys
				Local keys:TAnimKey[chunk.frame.length]
				Local pos#[]=chunk.position,rot#[]=chunk.rotation,scl#[]=chunk.scale
				For Local i=0 To chunk.frame.length-1
					Local bonekey:TBoneKey=New TBoneKey

					If pos.length>0 bonekey._px=pos[i*3+0];bonekey._py=pos[i*3+1];bonekey._pz=pos[i*3+2]
					If rot.length>0 bonekey._rw=rot[i*4+0];bonekey._rx=rot[i*4+1];bonekey._ry=rot[i*4+2];bonekey._rz=rot[i*4+3]
					If scl.length>0 bonekey._sx=scl[i*3+0];bonekey._sy=scl[i*3+1];bonekey._sz=scl[i*3+2]

					Local key:TAnimKey=New TAnimKey
					key._frame=chunk.frame[i]
					key._object=bonekey
					keys[i]=key
				Next
				TBoneAnimator(_mesh._animator).AddBone bone,keys
			Next
		Default
			entity=_currentworld.AddPivot(parent)
		End Select

		entity.SetName node.name
		entity.SetPosition node.position[0],node.position[1],node.position[2]
		Local pitch#,yaw#,roll#
		TQuaternion.Euler node.rotation[0],node.rotation[1],node.rotation[2],node.rotation[3],pitch,yaw,roll
		entity.SetRotation pitch,yaw,roll
		entity.SetScale node.scale[0],node.scale[1],node.scale[2]

		For Local child:TNODEChunk=EachIn node.node
			ParseNode child,entity,brush
		Next
		If TMesh(entity) If TBoneAnimator(TMesh(entity)._animator)._root=Null TMesh(entity)._animator=Null
		If TBone(entity) TBone(entity)._start_matrix=entity.GetMatrix()
	End Method

	Method Info$()
		Return "Blitz3D|b3d"
	End Method
	Method ModuleName$()
		Return "b3dloader"
	End Method
End Type
New TMeshLoaderB3D


remove redundant test

remove redundant test

' Blue Moon
' an implementation of Lua in pure BlitzMax

SuperStrict

'Framework Brl.Blitz
'Import Brl.LinkedList
'Import Brl.Map
'Import Brl.Reflection

Import "bluecompiler.bmx"
Import "bluevm.bmx"

'Const file:String = "tests/checktable.lua"
'Const file:String = "tests/mandelbrot.lua"
'Const file:String = "tests/sieve.lua"
'Const file:String = "tests/attrib.lua"
Const file:String = "test1.lua"

Const outFile:String = "out.lua.so"

Print BlueCompiler.ShowBytecode(file)

Local code:BlueBinary = BlueCompiler.CompileFileForLoad(file)
Local vm:BlueVM = New BlueVM
Local tl:BlueLuaVal = vm.LoadObjectCode(code)

Local stk:Stack = BlueJIT.BPtoS(vm.mem.stack)
stk.retIP = Null ; stk.prevBase = Null
Local vc:Int = 10, upvars:Int = 1
stk.varp = Long Ptr(Byte Ptr(stk) + BlueJIT.STACKFRAME_INC) + upvars
stk.func = vm.funIndex[0]
stk.argv = Null	'may want to add space?
stk.retv = Null
stk.argc = 0
stk.retc = 0

Print "running..."
Local t:Int = MilliSecs()
Local test:Int(_:Byte Ptr) = stk.func.mcode - BlueJIT.PROLOGUESZ ; test(stk)
t = MilliSecs() - t
Print t
Print "run complete"

Print "done."
End

Rem
Local files:TList = CreateList()
Local as:String, ld:String, showHelp:Int, output:String = "a.out", doAssemble:Int = 1
Local keepAsm:Int, makeExe:Int = 1, asOpts:String, ldOpts:String, showAST:Int, showVersion:Int

?MacOS
as = "clang -m32 -c " ; ld = "clang -Wl,-no_pie -m32 -read_only_relocs suppress "
?Not MacOS
as = "gcc -m32 -c " ; ld = "gcc -m32 "
?

For Local a:Int = 1 Until AppArgs.Length
	Select AppArgs[a]
		Case "-?", "--help"
			showHelp = 1
		Case "-v"
			showVersion = 1
		Case "-o"
			If makeExe = 0
				Print "warning: -c and -o are mutually exclusive; -c is overruling -o"
			Else
				a :+ 1 ; output = AppArgs[a] ; makeExe = 2
			EndIf
		Case "-c"
			If makeExe = 2
				Print "warning: -o and -c are mutually exclusive; -o is overruling -c"
			Else
				doAssemble = 1 ; makeExe = 0
			EndIf
		Case "-s"
			keepAsm = 1
		Case "-S"
			keepAsm = 1 ; doAssemble = 0 ; makeExe = 0
		Case "--as"
			a :+ 1 ; as = AppArgs[a] + " "
		Case "--ld"
			a :+ 1 ; ld = AppArgs[a] + " "
		Case "--as-opt"
			a :+ 1 ; asOpts :+ AppArgs[a] + " "
		Case "--ld-opt"
			a :+ 1 ; ldOpts :+ AppArgs[a] + " "
		Case "--tree"
			showAST = 1 ; makeExe = 0
		Case "-w"     ; YBCodeGen.SetWarningLevel 0
		Case "--werr" ; YBCodeGen.SetWarningLevel 2
		Case "--warn" ; YBCodeGen.SetWarningLevel 1
		Default
			files.AddLast AppArgs[a]
	End Select
Next
If AppArgs.Length = 1 Then Print "ybc: no input files" ; End

If showVersion Then DisplayVersion
If showHelp Then DisplayHelp

?Win32
Local rm:String = "del /Q "
?Not Win32
Local rm:String = "rm "
?

Local allOFiles:String = ""
For Local file:String = EachIn files
	Try
		Local tree:TParseNode = YBParseFile(file)
		If showAST
			Print tree.ToString()
		Else
			YBCodeGen.Build tree
			YBAssembler.Emit file + ".s", YBCodeGen.syms, YBCodeGen.funs, YBCodeGen.vars, YBCodeGen.strs
			If doAssemble
				system_(as + asOpts + file + ".s -o " + file + ".o")
				allOFiles :+ file + ".o "
			EndIf
			If Not keepAsm
				system_ rm + file + ".s"
			EndIf
		EndIf
	Catch e:Object
		Print "Compile error:~n    " + e.ToString()
		Print "Compilation halted."
		?Debug
		Throw e
		?
		End
	End Try
Next

?Linux
Local bLib:String = "b-lib-linux"
?Not Linux
Local bLib:String = "b-lib"
?
If makeExe
	If Not FileType("b-lib.o") Then system_ as + bLib + ".s -o b-lib.o"
	system_(ld + ldOpts + "-o " + output + " " + allOFiles + " b-lib.o")
	system_(rm + allOFiles)
EndIf

Print "done."
End
End Rem
Rem
Function DisplayVersion()
	Print "Shadow SIMD Compiler: version 0.0"
End Function

Function DisplayHelp()
	Print "OVERVIEW: ybc compiler for B~n"
	Print "USAGE: ybc [options] <files>~n"
	Print "OPTIONS:~n"
	Print "  -?, --help  Display this message"
	Print "  -v          Show the compiler version"
	Print "  -o          Set the name of the output executable (default 'a.out')"
	Print "  -c          Produce separate .o files instead of an executable"
	Print "  -s          Keep text assembly .s files"
	Print "  -S          Only produce text assembly, do not assemble binaries"
	Print "  --as        Set the command to use as the assembler"
	Print "  --ld        Set the command to use as the linker"
	Print "  --as-opt    Add an option to pass to the assembler (can repeat)"
	Print "  --ld-opt    Add an option to pass to the linker (can repeat)"
	Print "  --tree      Display the AST of the program source instead of compiling"
	Print "  -w          Silence warnings"
	Print "  --werr      Convert warnings to errors"
	Print "  --warn      Notify but do not halt on warnings (default)"
End Function
End Rem

' Blue Moon
' an implementation of Lua in pure BlitzMax

SuperStrict

'Framework Brl.Blitz
'Import Brl.LinkedList
'Import Brl.Map
'Import Brl.Reflection

Import "bluecompiler.bmx"
Import "bluevm.bmx"

'Const file:String = "tests/checktable.lua"
'Const file:String = "tests/mandelbrot.lua"
'Const file:String = "tests/sieve.lua"
'Const file:String = "tests/attrib.lua"
Const file:String = "test1.lua"

Const outFile:String = "out.lua.so"

Print BlueCompiler.ShowBytecode(file)

Local code:BlueBinary = BlueCompiler.CompileFileForLoad(file)
Local vm:BlueVM = New BlueVM
Local tl:BlueLuaVal = vm.LoadObjectCode(code)

Local stk:Stack = BlueJIT.BPtoS(vm.mem.stack)
stk.retIP = Null ; stk.prevBase = Null
Local vc:Int = 10, upvars:Int = 1
stk.varp = Long Ptr(Byte Ptr(stk) + BlueJIT.STACKFRAME_INC) + upvars
stk.func = vm.funIndex[0]
stk.argv = Null	'may want to add space?
stk.retv = Null
stk.argc = 0
stk.retc = 0

Function lpr:Int(vm:BlueVM, argc:Int, argv:Long Ptr, retv:Long Ptr)
	Print vm.mem.ValToMaxString(argv[0])
	Return 0
End Function
Function addtri:Int(vm:BlueVM, argc:Int, argv:Long Ptr, retv:Long Ptr)
	Double Ptr(retv)[0] = Double Ptr(argv)[0] + Double Ptr(argv)[1] + Double Ptr(argv)[2]
	Return 1
End Function
Function ret3:Int(vm:BlueVM, argc:Int, argv:Long Ptr, retv:Long Ptr)
	Double Ptr(retv)[0] = 21
	Double Ptr(retv)[1] = 23
	Double Ptr(retv)[2] = 25
	Return 3
End Function
vm._ENV.Set("pr", vm.ValueFromFunction(lpr))
vm._ENV.Set("quux", vm.ValueFromNumber(7.5))
vm._ENV.Set("addtriple", vm.ValueFromFunction(addtri))
vm._ENV.Set("ret3", vm.ValueFromFunction(ret3))

Print "running..."
Local t:Int = MilliSecs()
Local test:Int(_:Byte Ptr) = stk.func.mcode - BlueJIT.PROLOGUESZ ; test(stk)
t = MilliSecs() - t
Print t
Print "run complete"

Print "done."
End

Rem
Local files:TList = CreateList()
Local as:String, ld:String, showHelp:Int, output:String = "a.out", doAssemble:Int = 1
Local keepAsm:Int, makeExe:Int = 1, asOpts:String, ldOpts:String, showAST:Int, showVersion:Int

?MacOS
as = "clang -m32 -c " ; ld = "clang -Wl,-no_pie -m32 -read_only_relocs suppress "
?Not MacOS
as = "gcc -m32 -c " ; ld = "gcc -m32 "
?

For Local a:Int = 1 Until AppArgs.Length
	Select AppArgs[a]
		Case "-?", "--help"
			showHelp = 1
		Case "-v"
			showVersion = 1
		Case "-o"
			If makeExe = 0
				Print "warning: -c and -o are mutually exclusive; -c is overruling -o"
			Else
				a :+ 1 ; output = AppArgs[a] ; makeExe = 2
			EndIf
		Case "-c"
			If makeExe = 2
				Print "warning: -o and -c are mutually exclusive; -o is overruling -c"
			Else
				doAssemble = 1 ; makeExe = 0
			EndIf
		Case "-s"
			keepAsm = 1
		Case "-S"
			keepAsm = 1 ; doAssemble = 0 ; makeExe = 0
		Case "--as"
			a :+ 1 ; as = AppArgs[a] + " "
		Case "--ld"
			a :+ 1 ; ld = AppArgs[a] + " "
		Case "--as-opt"
			a :+ 1 ; asOpts :+ AppArgs[a] + " "
		Case "--ld-opt"
			a :+ 1 ; ldOpts :+ AppArgs[a] + " "
		Case "--tree"
			showAST = 1 ; makeExe = 0
		Case "-w"     ; YBCodeGen.SetWarningLevel 0
		Case "--werr" ; YBCodeGen.SetWarningLevel 2
		Case "--warn" ; YBCodeGen.SetWarningLevel 1
		Default
			files.AddLast AppArgs[a]
	End Select
Next
If AppArgs.Length = 1 Then Print "ybc: no input files" ; End

If showVersion Then DisplayVersion
If showHelp Then DisplayHelp

?Win32
Local rm:String = "del /Q "
?Not Win32
Local rm:String = "rm "
?

Local allOFiles:String = ""
For Local file:String = EachIn files
	Try
		Local tree:TParseNode = YBParseFile(file)
		If showAST
			Print tree.ToString()
		Else
			YBCodeGen.Build tree
			YBAssembler.Emit file + ".s", YBCodeGen.syms, YBCodeGen.funs, YBCodeGen.vars, YBCodeGen.strs
			If doAssemble
				system_(as + asOpts + file + ".s -o " + file + ".o")
				allOFiles :+ file + ".o "
			EndIf
			If Not keepAsm
				system_ rm + file + ".s"
			EndIf
		EndIf
	Catch e:Object
		Print "Compile error:~n    " + e.ToString()
		Print "Compilation halted."
		?Debug
		Throw e
		?
		End
	End Try
Next

?Linux
Local bLib:String = "b-lib-linux"
?Not Linux
Local bLib:String = "b-lib"
?
If makeExe
	If Not FileType("b-lib.o") Then system_ as + bLib + ".s -o b-lib.o"
	system_(ld + ldOpts + "-o " + output + " " + allOFiles + " b-lib.o")
	system_(rm + allOFiles)
EndIf

Print "done."
End
End Rem
Rem
Function DisplayVersion()
	Print "Shadow SIMD Compiler: version 0.0"
End Function

Function DisplayHelp()
	Print "OVERVIEW: ybc compiler for B~n"
	Print "USAGE: ybc [options] <files>~n"
	Print "OPTIONS:~n"
	Print "  -?, --help  Display this message"
	Print "  -v          Show the compiler version"
	Print "  -o          Set the name of the output executable (default 'a.out')"
	Print "  -c          Produce separate .o files instead of an executable"
	Print "  -s          Keep text assembly .s files"
	Print "  -S          Only produce text assembly, do not assemble binaries"
	Print "  --as        Set the command to use as the assembler"
	Print "  --ld        Set the command to use as the linker"
	Print "  --as-opt    Add an option to pass to the assembler (can repeat)"
	Print "  --ld-opt    Add an option to pass to the linker (can repeat)"
	Print "  --tree      Display the AST of the program source instead of compiling"
	Print "  -w          Silence warnings"
	Print "  --werr      Convert warnings to errors"
	Print "  --warn      Notify but do not halt on warnings (default)"
End Function
End Rem


Changed default resolution to 640x480 to match the other targets (HTML5, Flash and GLFW)

--HG--
extra : convert_revision : svn%3Ae934d3cd-0d57-f34a-94d0-9e8d31ae1c29/trunk%40388

SuperStrict

Global _errStack:TList = New TList;
Global _errInfo:String="";

Graphics 640, 480

bbInit();
bbMain();

'${TRANSCODE_BEGIN}
'${TRANSCODE_END}

SuperStrict

Global _errStack:TList = New TList;
Global _errInfo:String="";

Graphics 800, 600

bbInit();
bbMain();

'${TRANSCODE_BEGIN}
'${TRANSCODE_END}


Removed output clutter

Removed output clutter

refs gh-17

Rem
	bbdoc: Maximus basic logger.
End Rem
Type mxLogger

	Field m_observers:TList = New TList

	Const c_message:String = "message"
	Const c_warning:String = "warning"
	Const c_error:String = "error"

	Rem
		bbdoc: Log a message.
		returns: Nothing.
		about: If @newline is True, a new line will be started, if it is False, a new line will not be started.
	End Rem
	Method LogMessage(message:String, newline:Int = True)
		If newline Then message:+ "~n"
		MessageObservers(message, c_message)
	End Method

	Rem
		bbdoc: Log a warning message.
		returns: Nothing.
		about: If @newline is True, a new line will be started, if it is False, a new line will not be started.
	End Rem
	Method LogWarning(warning:String, newline:Int = True)
		warning = _s("message.warning", [warning])
		If newline Then warning:+ "~n"
		MessageObservers(warning, c_warning)
	End Method

	Rem
		bbdoc: Log an error message.
		returns: Nothing.
		about: If @newline is True, a new line will be started, if it is False, a new line will not be started.
	End Rem
	Method LogError(error:String, newline:Int = True)
		error = _s("message.error", [error])
		If newline Then error:+ "~n"
		MessageObservers(error, c_error)
	End Method

	Rem
		bbdoc: Add an observer
		Returns: Nothing.
	End Rem
	Method AddObserver(observer:Object)
		m_observers.AddLast(observer)
	End Method

	Rem
		bbdoc: Send messages to observers
		returns: Nothing.
		about: This helper method messages all registered observers with the SendMessage method
	End Rem
	Method MessageObservers(message:String, context:String)
		For Local observer:Object = EachIn m_observers
			observer.SendMessage(message, context)
		Next
	End Method
End Type

Rem
	bbdoc: This observer for mxLogger will write received messages to StandardIOStream
End Rem
Type mxLoggerObserverIOStream
	Method SendMessage:Object(message:Object, context:Object)
		StandardIOStream.WriteString(String(message))
	End Method
End Type

Rem
	bbdoc: This observer for mxLogger will print received messages with DebugLog
End Rem
Type mxLoggerObserverDebuglog
	Method SendMessage:Object(message:Object, context:Object)
		DebugLog "[" + String(context) + "] " + String(message)
	End Method
End Type

Rem
	bbdoc: Maximus basic logger.
End Rem
Type mxLogger

	Field m_observers:TList = New TList

	Const c_message:String = "message"
	Const c_warning:String = "warning"
	Const c_error:String = "error"

	Rem
		bbdoc: Log a message.
		returns: Nothing.
		about: If @newline is True, a new line will be started, if it is False, a new line will not be started.
	End Rem
	Method LogMessage(message:String, newline:Int = True)
		If newline Then message:+ "~n"
		MessageObservers(message, c_message)
	End Method

	Rem
		bbdoc: Log a warning message.
		returns: Nothing.
		about: If @newline is True, a new line will be started, if it is False, a new line will not be started.
	End Rem
	Method LogWarning(warning:String, newline:Int = True)
		warning = _s("message.warning", [warning])
		If newline Then warning:+ "~n"
		MessageObservers(warning, c_warning)
	End Method

	Rem
		bbdoc: Log an error message.
		returns: Nothing.
		about: If @newline is True, a new line will be started, if it is False, a new line will not be started.
	End Rem
	Method LogError(error:String, newline:Int = True)
		error = _s("message.error", [error])
		If newline Then error:+ "~n"
		MessageObservers(error, c_error)
	End Method

	Rem
		bbdoc: Add an observer
		Returns: Nothing.
	End Rem
	Method AddObserver(observer:Object)
		m_observers.AddLast(observer)
	End Method

	Rem
		bbdoc: Send messages to observers
		returns: Nothing.
		about: This helper method messages all registered observers with the SendMessage method
	End Rem
	Method MessageObservers(message:String, context:String)
		For Local observer:Object = EachIn m_observers
			observer.SendMessage(message, context)
		Next
	End Method
End Type

Rem
	bbdoc: This observer for mxLogger will write received messages to StandardIOStream
End Rem
Type mxLoggerObserverIOStream
	Method SendMessage:Object(message:Object, context:Object)
		StandardIOStream.WriteString("iostream:" + String(message))
	End Method
End Type

Rem
	bbdoc: This observer for mxLogger will print received messages with DebugLog
End Rem
Type mxLoggerObserverDebuglog
	Method SendMessage:Object(message:Object, context:Object)
		DebugLog "[" + String(context) + "] " + String(message)
	End Method
End Type


Version 0.3

Version 0.3

Rem
	Copyright (c) 2012 Christiaan Kras

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in
	all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	THE SOFTWARE.
End Rem

SuperStrict

Rem
	bbdoc: htbaapub.zmq
	about: This module is still an early work in progress. If you run into any
	bugs please report them at https://github.com/Htbaa/zmq.mod/issues.
EndRem
Module htbaapub.zmq
ModuleInfo "Name: htbaapub.zmq"
ModuleInfo "Description: A wrapper for ZeroMQ"
ModuleInfo "Version: 0.03"
ModuleInfo "License: MIT"
ModuleInfo "Author: Christiaan Kras"
ModuleInfo "ZeroMQ: http://www.zeromq.org"
ModuleInfo "ZeroMQ License: LGPL (see contents of ./zeromq)"
ModuleInfo "Git repository: https://github.com/Htbaa/zmq.mod/"
ModuleInfo "Issues: https://github.com/Htbaa/zmq.mod/issues"
ModuleInfo "History: 0.03"
ModuleInfo "History: Fixed message data corruption for first sent message (gh-3)"
ModuleInfo "History: Added TZMQ_Message.CreateFromString to create messages from a String. The TZMQ_Message.Create signature has also changed to accept a Byte Ptr and a length"
ModuleInfo "History: Fixed potential memory leak in TZMQ_Socket.Send when an exception would be raised"
ModuleInfo "History: Added TZMQ_Socket_Exception and TZMQ_Message_Exception"
ModuleInfo "History: Added a couple of unit tests (bah.maxunit required)"
ModuleInfo "History: 0.02"
ModuleInfo "History: Added more examples; Hello World server and client"
ModuleInfo "History: Added more examples; Weather Update server and client"
ModuleInfo "History: TZMQ_Socket.SetSockOpt() now properly sets options"
ModuleInfo "History: TZMQ_Message.Close() now properly frees up memory"
ModuleInfo "History: 0.01"
ModuleInfo "History: First release of htbaapub.zmq using ZMQ 2.1.11. No support yet for input/output multiplexing with zmq_poll()"

?Linux
	Import "-lzmq"
?Win32
	Import "zeromq/lib/libzmq.dll.a"
?

Import "glue.c"
Include "exception.bmx"
Include "constants.bmx"
Include "context.bmx"
Include "socket.bmx"
Include "message.bmx"

'Glue/Helper functions
Extern "C"

	Rem
		bbdoc: Create an empty zmq_message_t struct
		returns: Returns a pointer to a new zmq_message_t struct
	End Rem
	Function bmx_zmq_message_t:Byte Ptr()

	Rem
		bbdoc: Create a zmq_message_t struct with preset data
		returns: Returns a pointer to a new zmq_message_t struct with given data
	End Rem
	Function bmx_zmq_new_message:Byte Ptr(str$z)

	Rem
		bbdoc: Alias for free(), for cleaning up data structures
	End Rem
	Function bmx_zmq_free(msg:Byte Ptr)
End Extern

'ZeroMQ functions
Extern
	Function zmq_version(major:Int Var, minor:Int Var, patch:Int Var)

	Function zmq_init:Byte Ptr(io_threads:Int)
	Function zmq_term:Int(context:Byte Ptr)

	Function zmq_errno:Int()
	Function zmq_strerror$z(errnum:Int)

	Function zmq_socket:Byte Ptr(context:Byte Ptr, socket_type:Int)
	Function zmq_close:Int(s:Byte Ptr)
	Function zmq_setsockopt:Int(s:Byte Ptr, option:Int, optval$z, length:Int)
	Function zmq_getsockopt:Int(s:Byte Ptr, option:Int, optval:Byte Ptr, length:Int Var)
	'ZMQ_EXPORT Int zmq_getsockopt (void *s, Int option, void *optval, size_t *optvallen);
	Function zmq_bind(s:Byte Ptr, addr$z)
	Function zmq_connect:Int(s:Byte Ptr, addr$z)
	Function zmq_send:Int(s:Byte Ptr, msg:Byte Ptr, flags:Int)
	Function zmq_recv:Int(s:Byte Ptr, msg:Byte Ptr, flags:Int)

	Function zmq_msg_init:Int(msg:Byte Ptr)
	Function zmq_msg_init_size:Int(msg:Byte Ptr, size:Long)
	Function zmq_msg_init_data:Int(msg:Byte Ptr, data:Byte Ptr, size:Long, ffn:Byte Ptr, hint:Byte Ptr)
	Function zmq_msg_close:Int(msg:Byte Ptr)
	Function zmq_msg_move:Int(dest:Byte Ptr, src:Byte Ptr)
	Function zmq_msg_copy:Int(dest:Byte Ptr, src:Byte Ptr)
	Function zmq_msg_data:Byte Ptr(msg:Byte Ptr)
	Function zmq_msg_size:Int(msg:Byte Ptr)

	Function zmq_poll:Int(items:Byte Ptr, nitems:Int, timeout:Long)

	Function zmq_device:Int(device:Int, insocket:Byte Ptr, outsocket:Byte Ptr)
End Extern

Rem
	bbdoc: General ZMQ functions
End Rem
Type TZMQ

	Rem
		bbdoc: Get ZMQ Version
		returns: String
	End Rem
	Function Version:String()
		Local major:Int, minor:Int, patch:Int
		zmq_version(major, minor, patch)
		Return major + "." + minor + "." + patch
	End Function

	Rem
		bbdoc: Get current ZMQ error descriptions
		returns: String
	End Rem
	Function Error:String()
		Return zmq_strerror( TZMQ.ErrorNumber() )
	End Function

	Rem
		bbdoc: Get current ZMQ error number
		returns: Int
	End Rem
	Function ErrorNumber:Int()
		Return zmq_errno()
	End Function
End Type

Rem
	Copyright (c) 2012 Christiaan Kras

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in
	all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	THE SOFTWARE.
End Rem

SuperStrict

Rem
	bbdoc: htbaapub.zmq
	about: This module is still an early work in progress. If you run into any
	bugs please report them at https://github.com/Htbaa/zmq.mod/issues.
EndRem
Module htbaapub.zmq
ModuleInfo "Name: htbaapub.zmq"
ModuleInfo "Description: A wrapper for ZeroMQ"
ModuleInfo "Version: 0.02"
ModuleInfo "License: MIT"
ModuleInfo "Author: Christiaan Kras"
ModuleInfo "ZeroMQ: http://www.zeromq.org"
ModuleInfo "ZeroMQ License: LGPL (see contents of ./zeromq)"
ModuleInfo "Git repository: https://github.com/Htbaa/zmq.mod/"
ModuleInfo "Issues: https://github.com/Htbaa/zmq.mod/issues"
ModuleInfo "History: Fixed message data corruption for first sent message (gh-3)"
ModuleInfo "History: Added TZMQ_Message.CreateFromString to create messages from a String. The TZMQ_Message.Create signature has also changed to accept a Byte Ptr and a length"
ModuleInfo "History: Fixed potential memory leak in TZMQ_Socket.Send when an exception would be raised"
ModuleInfo "History: Added TZMQ_Socket_Exception and TZMQ_Message_Exception"
ModuleInfo "History: Added a couple of unit tests (bah.maxunit required)"
ModuleInfo "History: 0.02"
ModuleInfo "History: Added more examples; Hello World server and client"
ModuleInfo "History: Added more examples; Weather Update server and client"
ModuleInfo "History: TZMQ_Socket.SetSockOpt() now properly sets options"
ModuleInfo "History: TZMQ_Message.Close() now properly frees up memory"
ModuleInfo "History: 0.01"
ModuleInfo "History: First release of htbaapub.zmq using ZMQ 2.1.11. No support yet for input/output multiplexing with zmq_poll()"

?Linux
	Import "-lzmq"
?Win32
	Import "zeromq/lib/libzmq.dll.a"
?

Import "glue.c"
Include "exception.bmx"
Include "constants.bmx"
Include "context.bmx"
Include "socket.bmx"
Include "message.bmx"

'Glue/Helper functions
Extern "C"

	Rem
		bbdoc: Create an empty zmq_message_t struct
		returns: Returns a pointer to a new zmq_message_t struct
	End Rem
	Function bmx_zmq_message_t:Byte Ptr()

	Rem
		bbdoc: Create a zmq_message_t struct with preset data
		returns: Returns a pointer to a new zmq_message_t struct with given data
	End Rem
	Function bmx_zmq_new_message:Byte Ptr(str$z)

	Rem
		bbdoc: Alias for free(), for cleaning up data structures
	End Rem
	Function bmx_zmq_free(msg:Byte Ptr)
End Extern

'ZeroMQ functions
Extern
	Function zmq_version(major:Int Var, minor:Int Var, patch:Int Var)

	Function zmq_init:Byte Ptr(io_threads:Int)
	Function zmq_term:Int(context:Byte Ptr)

	Function zmq_errno:Int()
	Function zmq_strerror$z(errnum:Int)

	Function zmq_socket:Byte Ptr(context:Byte Ptr, socket_type:Int)
	Function zmq_close:Int(s:Byte Ptr)
	Function zmq_setsockopt:Int(s:Byte Ptr, option:Int, optval$z, length:Int)
	Function zmq_getsockopt:Int(s:Byte Ptr, option:Int, optval:Byte Ptr, length:Int Var)
	'ZMQ_EXPORT Int zmq_getsockopt (void *s, Int option, void *optval, size_t *optvallen);
	Function zmq_bind(s:Byte Ptr, addr$z)
	Function zmq_connect:Int(s:Byte Ptr, addr$z)
	Function zmq_send:Int(s:Byte Ptr, msg:Byte Ptr, flags:Int)
	Function zmq_recv:Int(s:Byte Ptr, msg:Byte Ptr, flags:Int)

	Function zmq_msg_init:Int(msg:Byte Ptr)
	Function zmq_msg_init_size:Int(msg:Byte Ptr, size:Long)
	Function zmq_msg_init_data:Int(msg:Byte Ptr, data:Byte Ptr, size:Long, ffn:Byte Ptr, hint:Byte Ptr)
	Function zmq_msg_close:Int(msg:Byte Ptr)
	Function zmq_msg_move:Int(dest:Byte Ptr, src:Byte Ptr)
	Function zmq_msg_copy:Int(dest:Byte Ptr, src:Byte Ptr)
	Function zmq_msg_data:Byte Ptr(msg:Byte Ptr)
	Function zmq_msg_size:Int(msg:Byte Ptr)

	Function zmq_poll:Int(items:Byte Ptr, nitems:Int, timeout:Long)

	Function zmq_device:Int(device:Int, insocket:Byte Ptr, outsocket:Byte Ptr)
End Extern

Rem
	bbdoc: General ZMQ functions
End Rem
Type TZMQ

	Rem
		bbdoc: Get ZMQ Version
		returns: String
	End Rem
	Function Version:String()
		Local major:Int, minor:Int, patch:Int
		zmq_version(major, minor, patch)
		Return major + "." + minor + "." + patch
	End Function

	Rem
		bbdoc: Get current ZMQ error descriptions
		returns: String
	End Rem
	Function Error:String()
		Return zmq_strerror( TZMQ.ErrorNumber() )
	End Function

	Rem
		bbdoc: Get current ZMQ error number
		returns: Int
	End Rem
	Function ErrorNumber:Int()
		Return zmq_errno()
	End Function
End Type


Added stub SeekMusic to bmax

Added stub SeekMusic to bmax

' ***** Start diddy.bmax.bmx ******
Global diddy_mouseWheel:Float = 0.0

Type diddy
	Function systemMillisecs:Float()
		Return Millisecs()
	EndFunction

	Function setGraphics(w:int, h:int, fullScreen:Int = False)
		local d% = 0
		if fullScreen then d = 32
		Graphics w, h, d, 60
	EndFunction

	Function setMouse(x:Int, y:Int)
		MoveMouse(x, y)
	EndFunction

	Function showKeyboard()
	EndFunction

	Function launchBrowser(address:String, windowName:String)
	EndFunction

	Function launchEmail(email:String, subject:String, text:String)
	EndFunction

	Function realMod:Float( value:Float, amount:Float )
		Return value Mod amount
	EndFunction

	Function startVibrate(millisecs:int)
	EndFunction

	Function stopVibrate()
	EndFunction

	Function getDayOfMonth:Int()
		Local date$ = CurrentDate()
		Return Int(date[..2])
	EndFunction

	Function getDayOfWeek:Int()
		Return 0
	EndFunction

	Function getMonth:Int()
		Local date$ = CurrentDate()
		Return (Instr("JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC", date$[3..6].ToUpper(), 1) / 3) + 1
	EndFunction

	Function getYear:Int()
		Local date$ = CurrentDate()
		Return Int(date[date.length - 4..]);
	EndFunction

	Function getHours:Int()
		Local time$ = CurrentTime()
		Return Int(time[..2])
	EndFunction

	Function getMinutes:Int()
		Local time$ = CurrentTime()
		Return Int(time[3..5])
	EndFunction

	Function getSeconds:Int()
		Local time$ = CurrentTime()
		Return Int(time[6..8])
	EndFunction

	Function getMilliSeconds:Int()
		Return Millisecs()
	EndFunction

	Function startGps()
	EndFunction

	Function getLatitiude:String()
		Return ""
	EndFunction

	Function getLongitude:String()
		Return ""
	EndFunction

	Function showAlertDialog(title:String, message:String)
	EndFunction

	Function getInputString:String()
		Return "";
	EndFunction

	Function getPixel:Int( x:int, y:int )
'		unsigned char pix[4];
'		glReadPixels(x, app->graphics->height-y ,1 ,1 ,GL_RGBA ,GL_UNSIGNED_BYTE ,pix);
'		return (pix[3]<<24) | (pix[0]<<16) | (pix[1]<<8) |  pix[2];
		Return 0
	EndFunction

	Function mouseZInit()
	EndFunction

	Function mouseZ:Float()
		Local ret:Float = BlitzMaxMouseZ() - diddy_mouseWheel
		diddy_mouseWheel = BlitzMaxMouseZ()
		Return ret
	EndFunction

	Function SeekMusic:Int(timeMillis:Int)
		Return 0
	EndFunction
EndType

Function BlitzMaxMouseZ:Float()
	Return MouseZ()
EndFunction

' ***** End diddy.bmax.bmx ******

' ***** Start diddy.bmax.bmx ******
Global diddy_mouseWheel:Float = 0.0

Type diddy
	Function systemMillisecs:Float()
		Return Millisecs()
	EndFunction

	Function setGraphics(w:int, h:int, fullScreen:Int = False)
		local d% = 0
		if fullScreen then d = 32
		Graphics w, h, d, 60
	EndFunction

	Function setMouse(x:Int, y:Int)
		MoveMouse(x, y)
	EndFunction

	Function showKeyboard()
	EndFunction

	Function launchBrowser(address:String, windowName:String)
	EndFunction

	Function launchEmail(email:String, subject:String, text:String)
	EndFunction

	Function realMod:Float( value:Float, amount:Float )
		Return value Mod amount
	EndFunction

	Function startVibrate(millisecs:int)
	EndFunction

	Function stopVibrate()
	EndFunction

	Function getDayOfMonth:Int()
		Local date$ = CurrentDate()
		Return Int(date[..2])
	EndFunction

	Function getDayOfWeek:Int()
		Return 0
	EndFunction

	Function getMonth:Int()
		Local date$ = CurrentDate()
		Return (Instr("JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC", date$[3..6].ToUpper(), 1) / 3) + 1
	EndFunction

	Function getYear:Int()
		Local date$ = CurrentDate()
		Return Int(date[date.length - 4..]);
	EndFunction

	Function getHours:Int()
		Local time$ = CurrentTime()
		Return Int(time[..2])
	EndFunction

	Function getMinutes:Int()
		Local time$ = CurrentTime()
		Return Int(time[3..5])
	EndFunction

	Function getSeconds:Int()
		Local time$ = CurrentTime()
		Return Int(time[6..8])
	EndFunction

	Function getMilliSeconds:Int()
		Return Millisecs()
	EndFunction

	Function startGps()
	EndFunction

	Function getLatitiude:String()
		Return ""
	EndFunction

	Function getLongitude:String()
		Return ""
	EndFunction

	Function showAlertDialog(title:String, message:String)
	EndFunction

	Function getInputString:String()
		Return "";
	EndFunction

	Function getPixel:Int( x:int, y:int )
'		unsigned char pix[4];
'		glReadPixels(x, app->graphics->height-y ,1 ,1 ,GL_RGBA ,GL_UNSIGNED_BYTE ,pix);
'		return (pix[3]<<24) | (pix[0]<<16) | (pix[1]<<8) |  pix[2];
		Return 0
	EndFunction

	Function mouseZInit()
	EndFunction

	Function mouseZ:Float()
		Local ret:Float = BlitzMaxMouseZ() - diddy_mouseWheel
		diddy_mouseWheel = BlitzMaxMouseZ()
		Return ret
	EndFunction
EndType

Function BlitzMaxMouseZ:Float()
	Return MouseZ()
EndFunction

' ***** End diddy.bmax.bmx ******