type.bmx: * Implemented most of the code for building information for exposed types/methods/fields.

SuperStrict

Import "field.bmx"
Import "method.bmx"
Import "metadata.bmx"

Import Brl.LinkedList

Private

Global _exposedTypes:TList = New TList

Public

Type LExposedType
	Field exposed%
	Field static%
	Field noclass%
	Field hidefields%
	Field nonew%

	Field typeid:TTypeId
	Field methods:TList			' TList<LExposedMethod>
	Field fields:TList			' TList<LExposedField>
	Field constructor$
	Field name$

	' Returns an LExposedType for a typeid - recommended to use this instead of creating a new LExposedType and initializing it
	Function ForType:LExposedType(typeid:TTypeId)
		If typeid = ObjectTypeId Or typeid = StringTypeId Or typeid._class = ArrayTypeId._class Then
			Return Null
		EndIf

		Local link:TLink = _exposedTypes.FindLink(typeid)
		If link Then
			Return LExposedType(link.Value())
		EndIf
		Return New LExposedType.InitWithTypeID(typeid)
	End Function

	' Compares LExposedTypes based on the TTypeId associated with each LExposedType
	Method Compare:Int(other:Object)
		Local ot:LExposedType = LExposedType(other)
		If other = Null Then
			Return 1
		ElseIf TTypeId(other) Then
			Return typeid.Compare(other)
		ElseIf other And Not ot Then
			Throw "Invalid type to compare LExposedType against"
		Else
			Return typeid.Compare(ot.typeid)
		EndIf
	End Method

	' Returns a list of exposed types to iterate over
	Function EnumTypes:TList()
		Return _exposedTypes.Copy()
	End Function

	' Initializes an LExposedType with information for the type passed
	' The object returned may not be the one you originally sent the initialize message to
	' If there is already an instance for this type, that instance will be returned instead
	' of proceeding with intialization
	Method InitWithTypeID:LExposedType(tid:TTypeId)
		If tid = ObjectTypeId Or tid = StringTypeId Or tid._class = ArrayTypeId._class Then
			Return Null
		EndIf

		Local lnk:TLink = _exposedTypes.FindLink(tid)
		If lnk Then
			Return LExposedType(lnk.Value())
		EndIf

		typeid = tid

		exposed = typeid.Metadata(LUGI_META_EXPOSE).ToInt()>0

		If Not exposed Then
			Return Null
		EndIf

		DebugLog "Building type info for "+tid.Name()

		static = typeid.Metadata(LUGI_META_STATIC).ToInt()>0
		noclass = typeid.Metadata(LUGI_META_NOCLASS).ToInt()>0
		hidefields = typeid.Metadata(LUGI_META_HIDEFIELDS).ToInt()>0
		nonew = typeid.Metadata(LUGI_META_DISABLECONSTRUCTOR).ToInt()>0

		name = typeid.Metadata(LUGI_META_RENAME).Trim()
		If Not name Then
			name = typeid.Name()
		EndIf

		If Not (nonew Or (static and noclass)) Then
			constructor = typeid.Metadata(LUGI_META_CONSTRUCTOR).Trim()
			If Not constructor Then
				' Force New[A-Z_].* as default
				constructor = "New"+name[0..1].ToUpper()+name[1..]
			EndIf
		EndIf

		__initMethods
		__initFields

		_exposedTypes.AddLast(Self)

		Return Self
	End Method

	Method PreInitBlock:String()
		If Not exposed Then
			Return Null
		EndIf

		Local outs$=""

		DebugLog "Pre-init block for "+typeid.Name()

		If Not (static And noclass) Then
			DebugLog "Instance methods"
			For Local m:LExposedMethod = EachIn methods
				Local initString$ = m.PreInitBlock()
				If initString Then
					outs :+ "~t" + initString + "~n"
				EndIf
			Next
		EndIf

		If Not noclass Then
			DebugLog "Fields"
			For Local f:LExposedField = EachIn fields
				Local initString$ = f.PreInitBlock()
				If initString Then
					outs :+ "~t" + initString + "~n"
				EndIf
			Next
		EndIf

		Return outs
	End Method

	Method PostInitBlock:String()
		If Not exposed Then
			Return Null
		EndIf

		DebugLog "Post-init block for "+typeid.Name()

		If Not (nonew Or (static And noclass)) Then
			Return 	"~tlua_pushlightuserdata lua_vm, Byte Ptr(TTypeId.ForName(~q" + typeid.Name() + "~q)._class)~n" + ..
					"~tlua_pushcclosure lua_vm, p_lugi_new_object, 1~n"
		ElseIf static And Not noclass Then
			Return	"~t"
		EndIf
	End Method

	Method MethodImplementations:String()
		If Not exposed Then
			Return Null
		EndIf

		DebugLog "Method implementations for "+typeid.Name()

		Local m:LExposedMethod
		Local outs$
		Local instMethod% = Not (static And noclass)
		Local block$

		For m = EachIn methods
			Local parentImp:LExposedMethod = __methodExposedInParent(m)

			If m <> parentImp Then
				Continue
			EndIf

			block = m.Implementation(instMethod)
			If block Then
				outs :+ "~n"+block+"~n"
			EndIf
		Next

		Return outs
	End Method

	Method __methodExposedInParent:LExposedMethod(current:LExposedMethod)
		Local name$ = current.methodid.Name().ToLower()

		Local typ:TTypeId = typeid.SuperType()
		Local parentImp:LExposedMethod
		While typ
			Local exp:LExposedType = ForType(typ)

			If exp Then
				For Local m:LExposedMethod = EachIn exp.methods
					If m.methodid.Name().ToLower() = name Then
						parentImp = m
						Exit	' go onto next parent
					EndIf
				Next
			EndIf

			typ = typ.SuperType()
		Wend

		If Not parentImp Then
			Return current
		Else
			Return parentImp
		EndIf
	End Method

	Method __initMethods()
		methods = New TList

		If Not exposed Then
			Return
		EndIf

		' Build list of exposed methods
		For Local m:TMethod = EachIn typeid.Methods()
			If "sendmessage^compare^new^delete^tostring".Find(m.Name().ToLower()) = -1 Then
				methods.AddLast(New LExposedMethod.InitWithMethod(m, typeid))
			EndIf
		Next
	End Method

	Method __initFields()
		fields = New TList

		If Not exposed Or hidefields Then
			Return
		EndIf

		' Build list of exposed fields
		For Local f:TField = EachIn typeid.Fields()
			fields.AddLast(New LExposedField.InitWithField(f, typeid))
		Next
	End Method
End Type

' Builds up the information for all types
Function BuildTypeInfo()
	DebugLog "Building type info..."
	TTypeID._Update()
	_buildTypeInfo(ObjectTypeId.DerivedTypes())
End Function

Private

' Recursively creates the information for types
Function _buildTypeInfo(types:TList)
	' Iterate over types and load data for them
	For Local tid:TTypeId = EachIn types
		New LExposedType.InitWithTypeID(tid)
		_buildTypeInfo(tid.DerivedTypes())
	Next
End Function

SuperStrict

Import "field.bmx"
Import "method.bmx"
Import "metadata.bmx"

Import Brl.LinkedList

Private

Global _exposedTypes:TList = New TList

Public

Type LExposedType
	Field exposed%
	Field static%
	Field noclass%
	Field hidefields%
	Field nonew%

	Field typeid:TTypeId
	Field methods:TList			' TList<LExposedMethod>
	Field fields:TList			' TList<LExposedField>
	Field constructor$
	Field name$

	' Returns an LExposedType for a typeid - recommended to use this instead of creating a new LExposedType and initializing it
	Function ForType:LExposedType(typeid:TTypeId)
		If typeid = ObjectTypeId Or typeid = StringTypeId Or typeid._class = ArrayTypeId._class Then
			Return Null
		EndIf

		Local link:TLink = _exposedTypes.FindLink(typeid)
		If link Then
			Return LExposedType(link.Value())
		EndIf
		Return New LExposedType.InitWithTypeID(typeid)
	End Function

	' Compares LExposedTypes based on the TTypeId associated with each LExposedType
	Method Compare:Int(other:Object)
		Local ot:LExposedType = LExposedType(other)
		If other = Null Then
			Return 1
		ElseIf TTypeId(other) Then
			Return typeid.Compare(other)
		ElseIf other And Not ot Then
			Throw "Invalid type to compare LExposedType against"
		Else
			Return typeid.Compare(ot.typeid)
		EndIf
	End Method

	' Returns a list of exposed types to iterate over
	Function EnumTypes:TList()
		Return _exposedTypes.Copy()
	End Function

	' Initializes an LExposedType with information for the type passed
	' The object returned may not be the one you originally sent the initialize message to
	' If there is already an instance for this type, that instance will be returned instead
	' of proceeding with intialization
	Method InitWithTypeID:LExposedType(tid:TTypeId)
		If tid = ObjectTypeId Or tid = StringTypeId Or tid._class = ArrayTypeId._class Then
			Return Null
		EndIf

		Local lnk:TLink = _exposedTypes.FindLink(tid)
		If lnk Then
			Return LExposedType(lnk.Value())
		EndIf

		exposed = typeid.Metadata(LUGI_META_EXPOSE).ToInt()>0
		static = typeid.Metadata(LUGI_META_STATIC).ToInt()>0
		noclass = typeid.Metadata(LUGI_META_NOCLASS).ToInt()>0
		hidefields = typeid.Metadata(LUGI_META_HIDEFIELDS).ToInt()>0
		nonew = typeid.Metadata(LUGI_META_DISABLECONSTRUCTOR).ToInt()>0

		name = typeid.Metadata(LUGI_META_RENAME).Trim()
		If Not name Then
			name = typeid.Name()
		EndIf

		If Not (nonew Or (static and noclass)) Then
			constructor = typeid.Metadata(LUGI_META_CONSTRUCTOR).Trim()
			If Not constructor Then
				' Force New[A-Z_].* as default
				constructor = "New"+name[0..1].ToUpper()+name[1..]
			EndIf
		EndIf

		__initMethods
		__initFields

		_exposedTypes.AddLast(Self)

		Return Self
	End Method

	Method PreInitBlock:String()
		Local outs$=""

		If Not (static And noclass) Then
			For Local m:LExposedMethod = EachIn methods
				Local initString$ = m.PreInitBlock()
				If initString Then
					outs :+ "~t" + initString + "~n"
				EndIf
			Next
		EndIf

		If Not noclass Then
			For Local f:LExposedField = EachIn fields
				Local initString$ = f.PreInitBlock()
				If initString Then
					outs :+ "~t" + initString + "~n"
				EndIf
			Next
		EndIf

		Return outs
	End Method

	Method PostInitBlock:String()
		If Not (nonew Or (static And noclass)) Then
			Return 	"~tlua_pushlightuserdata lua_vm, Byte Ptr(TTypeId.ForName(~q" + typeid.Name() + "~q)._class)" + ..
					"~tlua_pushcclosure lua_vm, p_lugi_new_object, 1"
		ElseIf static And Not noclass Then
			Return	"~t"
		EndIf
	End Method

	Method MethodImplementations:String()
		Local m:LExposedMethod
		Local outs$
		Local instMethod% = Not (static And noclass)
		Local block$

		For m = EachIn methods
			block = m.Implementation(instMethod)
			If block Then
				outs :+ "~n~n"+block
			EndIf
		Next

		Return outs
	End Method

	Method _exposedInParent:Int(m:TMethod)
		Local name$ = m.Name().ToLower()

		Local typ:TTypeId = typeid.SuperType()
		While typ

		Wend
	End Method

	Method __initMethods()
		methods = New TList

		If Not exposed Then
			Return
		EndIf

		' Build list of exposed methods
		For Local m:TMethod = EachIn typeid.Methods()

		Next
	End Method

	Method __initFields()
		fields = New TList

		If Not exposed Or hidefields Then
			Return
		EndIf

		For Local f:TField = EachIn typeid.Fields()

		Next
	End Method
End Type

' Builds up the information for all types
Function BuildTypeInfo()
End Function

Private

' Recursively creates the information for types
Function _buildTypeInfo(types:TList)
	' Iterate over types and load data for them
	For Local tid:TTypeId = EachIn types
		New LExposedType.InitWithTypeID(tid)
		_buildTypeInfo(tid.DerivedTypes())
	Next
End Function


Changed sample to use FX constant instead of number.

Strict

Import MaxB3D.Drivers
Import MaxB3D.MD2Loader

Graphics 800,600

Local room_texture:TTexture=LoadTexture( "media/chorme-2.bmp" )
SetTextureScale room_texture,1.0/3,1.0/3

Local room:TMesh=CreateCube()
SetEntityTexture room,room_texture
SetEntityAlpha room,.4
SetEntityFX room,FX_FULLBRIGHT
FitMesh room,-250,0,-250,500,500,500
FlipMesh room

'Local mirror:TMirror=CreateMirror()

Local light:TLight=CreateLight()
TurnEntity light,45,45,0

Local camera:TCamera=CreateCamera()
Local cam_xr#=30,cam_yr#=0,cam_zr#=0,cam_z#=-100

Local dragon_texture:TTexture=LoadTexture( "media/dragon.bmp" )
Local dragon:TMesh=LoadMesh( "media/dragon.md2" )
SetEntityTexture dragon,dragon_texture
SetEntityPosition dragon,0,25,0
TurnEntity dragon,0,150,0

Local anim:TAnimSeq[8]
anim[0]=CreateAnimSeq(0,40,"Idle")
anim[1]=CreateAnimSeq(40,46,"Run")
anim[2]=CreateAnimSeq(46,54,"Attack")
anim[3]=CreateAnimSeq(54,58,"Pain A")
anim[4]=CreateAnimSeq(58,62,"Pain B")
anim[5]=CreateAnimSeq(62,66,"Pain C")
anim[6]=CreateAnimSeq(66,72,"Jump")
anim[7]=CreateAnimSeq(72,84,"Flip")

SetMeshAnim dragon,anim[0],ANIMATION_LOOP,.05
Local curr_anim

While Not KeyHit(KEY_ESCAPE) And Not AppTerminate()
	For Local i=0 To anim.length-1
		If KeyHit(KEY_1+i)
			SetMeshAnim dragon,anim[i],ANIMATION_LOOP,.05
			curr_anim=i
		EndIf
	Next

	If KeyDown(KEY_LEFT)
		cam_yr=cam_yr-2
	Else If KeyDown(KEY_RIGHT)
		cam_yr=cam_yr+2
	EndIf

	If KeyDown(KEY_UP)
		cam_xr=cam_xr+2
		If cam_xr>90 cam_xr=90
	Else If KeyDown(KEY_DOWN)
		cam_xr=cam_xr-2
		If cam_xr<5 cam_xr=5
	EndIf

	If KeyDown(KEY_S)
		cam_zr=cam_zr+2
	Else If KeyDown(KEY_X)
		cam_zr=cam_zr-2
	EndIf

	If KeyDown(KEY_A)
		cam_z=cam_z+1;If cam_z>-10 cam_z=-10
	Else If KeyDown(KEY_Z)
		cam_z=cam_z-1;If cam_z<-180 cam_z=-180
	EndIf

	SetEntityPosition camera,0,0,0
	SetEntityRotation camera,cam_xr,cam_yr,cam_zr
	MoveEntity camera,0,0,cam_z

	UpdateWorld
	Local info:TRenderInfo=RenderWorld()
	DoMax2D
	DrawText "Use arrows keys to pan, A/Z to zoom",0,0
	DrawText "FPS: "+info.FPS,0,15
	DrawText "Current animation: "+GetAnimSeqName(anim[curr_anim]),0,30

	Flip
Wend

Strict

Import MaxB3D.Drivers
Import MaxB3D.MD2Loader

Graphics 800,600

Local room_texture:TTexture=LoadTexture( "media/chorme-2.bmp" )
SetTextureScale room_texture,1.0/3,1.0/3

Local room:TMesh=CreateCube()
SetEntityTexture room,room_texture
SetEntityAlpha room,.4
SetEntityFX room,1
FitMesh room,-250,0,-250,500,500,500
FlipMesh room

'Local mirror:TMirror=CreateMirror()

Local light:TLight=CreateLight()
TurnEntity light,45,45,0

Local camera:TCamera=CreateCamera()
Local cam_xr#=30,cam_yr#=0,cam_zr#=0,cam_z#=-100

Local dragon_texture:TTexture=LoadTexture( "media/dragon.bmp" )
Local dragon:TMesh=LoadMesh( "media/dragon.md2" )
SetEntityTexture dragon,dragon_texture
SetEntityPosition dragon,0,25,0
TurnEntity dragon,0,150,0

Local anim:TAnimSeq[8]
anim[0]=CreateAnimSeq(0,40,"Idle")
anim[1]=CreateAnimSeq(40,46,"Run")
anim[2]=CreateAnimSeq(46,54,"Attack")
anim[3]=CreateAnimSeq(54,58,"Pain A")
anim[4]=CreateAnimSeq(58,62,"Pain B")
anim[5]=CreateAnimSeq(62,66,"Pain C")
anim[6]=CreateAnimSeq(66,72,"Jump")
anim[7]=CreateAnimSeq(72,84,"Flip")

SetMeshAnim dragon,anim[0],ANIMATION_LOOP,.05
Local curr_anim

While Not KeyHit(KEY_ESCAPE) And Not AppTerminate()
	For Local i=0 To anim.length-1
		If KeyHit(KEY_1+i)
			SetMeshAnim dragon,anim[i],ANIMATION_LOOP,.05
			curr_anim=i
		EndIf
	Next

	If KeyDown(KEY_LEFT)
		cam_yr=cam_yr-2
	Else If KeyDown(KEY_RIGHT)
		cam_yr=cam_yr+2
	EndIf

	If KeyDown(KEY_UP)
		cam_xr=cam_xr+2
		If cam_xr>90 cam_xr=90
	Else If KeyDown(KEY_DOWN)
		cam_xr=cam_xr-2
		If cam_xr<5 cam_xr=5
	EndIf

	If KeyDown(KEY_S)
		cam_zr=cam_zr+2
	Else If KeyDown(KEY_X)
		cam_zr=cam_zr-2
	EndIf

	If KeyDown(KEY_A)
		cam_z=cam_z+1;If cam_z>-10 cam_z=-10
	Else If KeyDown(KEY_Z)
		cam_z=cam_z-1;If cam_z<-180 cam_z=-180
	EndIf

	SetEntityPosition camera,0,0,0
	SetEntityRotation camera,cam_xr,cam_yr,cam_zr
	MoveEntity camera,0,0,cam_z

	UpdateWorld
	Local info:TRenderInfo=RenderWorld()
	DoMax2D
	DrawText "Use arrows keys to pan, A/Z to zoom",0,0
	DrawText "FPS: "+info.FPS,0,15
	DrawText "Current animation: "+GetAnimSeqName(anim[curr_anim]),0,30

	Flip
Wend


Small TCamera.Unproject mod.

Small TCamera.Unproject mod.

Strict

Import "entity.bmx"
Import "worldconfig.bmx"

Const CAMMODE_NONE	= 0
Const CAMMODE_PERSP	= 1
Const CAMMODE_ORTHO	= 2

Const CLSMODE_COLOR	= 1
Const CLSMODE_DEPTH	= 2

Const FOGMODE_NONE		= 0
Const FOGMODE_LINEAR	= 1

Type TCamera Extends TEntity
	Field _projmode
	Field _fogmode,_fogr#,_fogg#,_fogb#,_fognear#,_fogfar#
	Field _viewx,_viewy,_viewwidth,_viewheight
	Field _clsmode,_near#,_far#
	Field _zoom#

	Field _lastmodelview:TMatrix=New TMatrix
	Field _lastprojection:TMatrix=New TMatrix
	Field _lastviewport[4]
	Field _lastfrustum:TFrustum

	Method New()
		SetMode CAMMODE_PERSP
		SetFogMode FOGMODE_NONE
		SetFogRange 1,1000
		SetViewport 0,0,WorldConfig.Width,WorldConfig.Height
		SetClsMode CLSMODE_COLOR|CLSMODE_DEPTH
		SetColor 0,0,0
		SetRange 1,1000
		SetZoom 1.0
	End Method

	Method Copy:TCamera(parent:TEntity=Null)
		Local camera:TCamera=New TCamera
		camera.SetMode _projmode
		camera.SetFogMode _fogmode
		camera.SetFogColor _fogr*255.0,_fogg*255.0,_fogb*255.0
		camera.SetFogRange _fognear,_fogfar
		camera.SetViewport _viewx,_viewy,_viewwidth,_viewheight
		camera.SetClsMode _clsmode
		camera.SetRange _near,_far
		camera.SetZoom _zoom
		Return camera
	End Method

	Method GetMode()
		Return _projmode
	End Method
	Method SetMode(mode)
		_projmode=mode
	End Method

	Method GetFogMode()
		Return _fogmode
	End Method
	Method SetFogMode(mode)
		_fogmode=mode
	End Method

	Method GetFogColor(red Var,green Var,blue Var)
		red=_fogr*255.0;green=_fogg*255.0;blue=_fogb*255.0
	End Method
	Method SetFogColor(red,green,blue)
		_fogr=red/255.0;_fogg=green/255.0;_fogb=blue/255.0
	End Method

	Method GetFogRange(near# Var,far# Var)
		near=_fognear;far=_fogfar
	End Method
	Method SetFogRange(near#,far#)
		_fognear=Max(near,0);_fogfar=Max(far,0.001)
	End Method

	Method GetViewport(x Var,y Var,width Var,height Var)
		x=_viewx;y=_viewy;width=_viewwidth;height=_viewheight
	End Method
	Method SetViewport(x,y,width,height)
		_viewx=x;_viewy=y;_viewwidth=width;_viewheight=height
	End Method

	Method GetClsMode()
		Return _clsmode
	End Method
	Method SetClsMode(mode)
		_clsmode=mode
	End Method

	Method GetRange(near# Var,far# Var)
		near=_near;far=_far
	End Method
	Method SetRange(near#,far#)
		_near=near;_far=far
	End Method

	Method GetZoom#()
		Return _zoom
	End Method
	Method SetZoom(zoom#)
		_zoom=zoom
	End Method

	Method GetEye:TRay()
		Local x#,y#,z#,dx#,dy#,dz#=1.0,o:TVector,d:TVector
		GetPosition x,y,z,True
		_matrix.TransformVec3 dx,dy,dz
		Return New TRay.Create(New TVector.Create3(x,y,z),New TVector.Create3(dx-x,dy-y,dz-x))
	End Method

	Method Project(target:Object,x# Var,y# Var, offset#[] = Null)
		Local z#
		TEntity.GetTargetPosition target,x,y,z

		If offset
		  x :+ offset[0]
		  y :+ offset[1]
		  z :+ offset[2]
		EndIf

		Local w#=1.0
	   _lastmodelview.TransformVec4 x,y,z,w
	   _lastprojection.TransformVec4 x,y,z,w
	   If w=0 Return False
	   x:/w;y:/w;z:/w

	   x=x*0.5+0.5;y=-y*0.5+0.5;z=z*0.5+0.5;

	   x=x*_lastviewport[2]+_lastviewport[0]
	   y=y*_lastviewport[3]+_lastviewport[1]
		Return True
	End Method

	Method Unproject(wx#,wy#,wz#,x# Var,y# Var,z# Var)
		Local matrix:TMatrix=_lastprojection.Multiply(_lastmodelview).Inverse()

		x=(wx-_lastviewport[0])*2/_lastviewport[2] - 1.0
		y=(wy-_lastviewport[1])*2/_lastviewport[3] - 1.0
		z=2*wz-1.0
		Local w#=1.0

		matrix.TransformVec4 x,y,z,w
		If w=0 Return False

		x:/w;y:/w;z:/w
		Return True
	End Method

	Method InView#(target:Object)
		Local x#,y#,z#,radius#
		Local entity:TEntity=TEntity(target),point#[]=Float[](target)
		If entity
			entity.GetCullParams x,y,z,radius
		Else
			x=point[0];y=point[1];z=point[2];radius=point[3]
		EndIf
		Return _lastfrustum.IntersectsPoint(x,y,z,radius)
	End Method
End Type

Strict

Import "entity.bmx"
Import "worldconfig.bmx"

Const CAMMODE_NONE	= 0
Const CAMMODE_PERSP	= 1
Const CAMMODE_ORTHO	= 2

Const CLSMODE_COLOR	= 1
Const CLSMODE_DEPTH	= 2

Const FOGMODE_NONE		= 0
Const FOGMODE_LINEAR	= 1

Type TCamera Extends TEntity
	Field _projmode
	Field _fogmode,_fogr#,_fogg#,_fogb#,_fognear#,_fogfar#
	Field _viewx,_viewy,_viewwidth,_viewheight
	Field _clsmode,_near#,_far#
	Field _zoom#

	Field _lastmodelview:TMatrix=New TMatrix
	Field _lastprojection:TMatrix=New TMatrix
	Field _lastviewport[4]
	Field _lastfrustum:TFrustum

	Method New()
		SetMode CAMMODE_PERSP
		SetFogMode FOGMODE_NONE
		SetFogRange 1,1000
		SetViewport 0,0,WorldConfig.Width,WorldConfig.Height
		SetClsMode CLSMODE_COLOR|CLSMODE_DEPTH
		SetColor 0,0,0
		SetRange 1,1000
		SetZoom 1.0
	End Method

	Method Copy:TCamera(parent:TEntity=Null)
		Local camera:TCamera=New TCamera
		camera.SetMode _projmode
		camera.SetFogMode _fogmode
		camera.SetFogColor _fogr*255.0,_fogg*255.0,_fogb*255.0
		camera.SetFogRange _fognear,_fogfar
		camera.SetViewport _viewx,_viewy,_viewwidth,_viewheight
		camera.SetClsMode _clsmode
		camera.SetRange _near,_far
		camera.SetZoom _zoom
		Return camera
	End Method

	Method GetMode()
		Return _projmode
	End Method
	Method SetMode(mode)
		_projmode=mode
	End Method

	Method GetFogMode()
		Return _fogmode
	End Method
	Method SetFogMode(mode)
		_fogmode=mode
	End Method

	Method GetFogColor(red Var,green Var,blue Var)
		red=_fogr*255.0;green=_fogg*255.0;blue=_fogb*255.0
	End Method
	Method SetFogColor(red,green,blue)
		_fogr=red/255.0;_fogg=green/255.0;_fogb=blue/255.0
	End Method

	Method GetFogRange(near# Var,far# Var)
		near=_fognear;far=_fogfar
	End Method
	Method SetFogRange(near#,far#)
		_fognear=Max(near,0);_fogfar=Max(far,0.001)
	End Method

	Method GetViewport(x Var,y Var,width Var,height Var)
		x=_viewx;y=_viewy;width=_viewwidth;height=_viewheight
	End Method
	Method SetViewport(x,y,width,height)
		_viewx=x;_viewy=y;_viewwidth=width;_viewheight=height
	End Method

	Method GetClsMode()
		Return _clsmode
	End Method
	Method SetClsMode(mode)
		_clsmode=mode
	End Method

	Method GetRange(near# Var,far# Var)
		near=_near;far=_far
	End Method
	Method SetRange(near#,far#)
		_near=near;_far=far
	End Method

	Method GetZoom#()
		Return _zoom
	End Method
	Method SetZoom(zoom#)
		_zoom=zoom
	End Method

	Method GetEye:TRay()
		Local x#,y#,z#,dx#,dy#,dz#=1.0,o:TVector,d:TVector
		GetPosition x,y,z,True
		_matrix.TransformVec3 dx,dy,dz
		Return New TRay.Create(New TVector.Create3(x,y,z),New TVector.Create3(dx-x,dy-y,dz-x))
	End Method

	Method Project(target:Object,x# Var,y# Var, offset#[] = Null)
		Local z#
		TEntity.GetTargetPosition target,x,y,z

		If offset
		  x :+ offset[0]
		  y :+ offset[1]
		  z :+ offset[2]
		EndIf

		Local w#=1.0
	   _lastmodelview.TransformVec4 x,y,z,w
	   _lastprojection.TransformVec4 x,y,z,w
	   If w=0 Return False
	   x:/w;y:/w;z:/w

	   x=x*0.5+0.5;y=-y*0.5+0.5;z=z*0.5+0.5;

	   x=x*_lastviewport[2]+_lastviewport[0]
	   y=y*_lastviewport[3]+_lastviewport[1]
		Return True
	End Method

	Method Unproject(wx#,wy#,wz#,x# Var,y# Var,z# Var)
		Local matrix:TMatrix=_lastmodelview.Multiply(_lastprojection).Inverse()

		Local w#=1.0
		x=wx;y=_lastviewport[3] - wy;z=wz

		x=(x-_lastviewport[0])/_lastviewport[2]
		y=(y-_lastviewport[1])/_lastviewport[3]

		x=x*2-1;y=y*2-1;z=z*2-1

		matrix.TransformVec4 x,y,z,w
		If w=0 Return False

		x:/w;y:/w;z:/w
		Return True
	End Method

	Method InView#(target:Object)
		Local x#,y#,z#,radius#
		Local entity:TEntity=TEntity(target),point#[]=Float[](target)
		If entity
			entity.GetCullParams x,y,z,radius
		Else
			x=point[0];y=point[1];z=point[2];radius=point[3]
		EndIf
		Return _lastfrustum.IntersectsPoint(x,y,z,radius)
	End Method
End Type


Pass flags parameter to TZMQ_Socket.Send when message is a String

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

Rem
	bbdoc: Type that represents a ZMQ socket
End Rem
Type TZMQ_Socket

	Rem
		bbdoc: Pointer to a ZMQ context
	End Rem
	Field context:Byte Ptr

	Rem
		bbdoc: Pointer to a ZMQ socket
		about: Use @Close() to free socket
	End Rem
	Field socket:Byte Ptr

	Rem
		bbdoc: Create a ZMQ Socket
		returns: TZMQ_Socket
		about: Throws a TZMQ_Exception on errors
	End Rem
	Method Create:TZMQ_Socket(context:Byte Ptr, socket_type:Int)
		If socket Then Throw "Socket already exists!"
		Self.context = context
		Self.socket = zmq_socket(Self.context, socket_type)
		If Self.socket = Null Then Throw New TZMQ_Exception
		Return Self
	End Method

	Rem
		bbdoc: Destructor
		about: Will call @Close() when collected
	End Rem
	Method Destroy()
		Self.Close()
	End Method

	Rem
		bbdoc: Bind to an address
		about: Throws a TZMQ_Exception on errors
	End Rem
	Method Bind(address:String)
		Local rc:Int = zmq_bind(Self.socket, address)
		If rc = -1 Then Throw New TZMQ_Exception
	End Method

	Rem
		bbdoc: Connect to a ZMQ socket
		about: Throws a TZMQ_Exception on errors
	End Rem
	Method Connect(address:String)
		Local rc:Int = zmq_connect(Self.socket, address)
		If rc = -1 Then Throw New TZMQ_Exception
	End Method

	Rem
		bbdoc: Close socket
		about: Throws a TZMQ_Exception on errors
	End Rem
	Method Close()
		Local rc:Int = zmq_close(Self.socket)
		If rc = -1 Then Throw New TZMQ_Exception
	End Method

	Rem
		bbdoc: Set a socket option
		about: Throws a TZMQ_Exception on errors
	End Rem
	Method SetSockOpt(socket_option:Int, value:String)
		Local rc:Int = zmq_setsockopt(Self.socket, socket_option, value, 0)
		If rc = -1 Then Throw New TZMQ_Exception
	End Method

	Rem
		bbdoc: Get a socket options
		about: Not yet implemented!
	End Rem
	Method GetSockOpt(socket_option:Int)
		Throw "Not yet implemented"
	End Method

	Rem
		bbdoc: Send message to socket
		about: Throws a TZMQ_Exception on errors
		message can either be a String, which will be converted to a TZMQ_Message,
		or you can pass a TZMQ_Message straight away
	End Rem
	Method Send(message:Object, flags:Int = 0)
		Local rc:Int
		If TZMQ_Message(message)
			rc = zmq_send(Self.socket, TZMQ_Message(message).message, flags)
		Else If String(message)
			Local content:String = String(message)
			Local msg:TZMQ_Message = New TZMQ_Message.Create(content)
			rc = Self.Send(msg, flags)
		End If

		If rc = -1 Then Throw New TZMQ_Exception
	End Method

	Rem
		bbdoc: Receive message from socket
		returns: TZMQ_Message
	End Rem
	Method Recv:TZMQ_Message(flags:Int = 0)
		Local msg:Byte Ptr = bmx_zmq_message_t()
		zmq_msg_init(msg)
		If zmq_recv(Self.socket, msg, flags) Then Return Null
		Return New TZMQ_Message.CreateFromMessage(msg)
	End Method
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

Rem
	bbdoc: Type that represents a ZMQ socket
End Rem
Type TZMQ_Socket

	Rem
		bbdoc: Pointer to a ZMQ context
	End Rem
	Field context:Byte Ptr

	Rem
		bbdoc: Pointer to a ZMQ socket
		about: Use @Close() to free socket
	End Rem
	Field socket:Byte Ptr

	Rem
		bbdoc: Create a ZMQ Socket
		returns: TZMQ_Socket
		about: Throws a TZMQ_Exception on errors
	End Rem
	Method Create:TZMQ_Socket(context:Byte Ptr, socket_type:Int)
		If socket Then Throw "Socket already exists!"
		Self.context = context
		Self.socket = zmq_socket(Self.context, socket_type)
		If Self.socket = Null Then Throw New TZMQ_Exception
		Return Self
	End Method

	Rem
		bbdoc: Destructor
		about: Will call @Close() when collected
	End Rem
	Method Destroy()
		Self.Close()
	End Method

	Rem
		bbdoc: Bind to an address
		about: Throws a TZMQ_Exception on errors
	End Rem
	Method Bind(address:String)
		Local rc:Int = zmq_bind(Self.socket, address)
		If rc = -1 Then Throw New TZMQ_Exception
	End Method

	Rem
		bbdoc: Connect to a ZMQ socket
		about: Throws a TZMQ_Exception on errors
	End Rem
	Method Connect(address:String)
		Local rc:Int = zmq_connect(Self.socket, address)
		If rc = -1 Then Throw New TZMQ_Exception
	End Method

	Rem
		bbdoc: Close socket
		about: Throws a TZMQ_Exception on errors
	End Rem
	Method Close()
		Local rc:Int = zmq_close(Self.socket)
		If rc = -1 Then Throw New TZMQ_Exception
	End Method

	Rem
		bbdoc: Set a socket option
		about: Throws a TZMQ_Exception on errors
	End Rem
	Method SetSockOpt(socket_option:Int, value:String)
		Local rc:Int = zmq_setsockopt(Self.socket, socket_option, value, 0)
		If rc = -1 Then Throw New TZMQ_Exception
	End Method

	Rem
		bbdoc: Get a socket options
		about: Not yet implemented!
	End Rem
	Method GetSockOpt(socket_option:Int)
		Throw "Not yet implemented"
	End Method

	Rem
		bbdoc: Send message to socket
		about: Throws a TZMQ_Exception on errors
		message can either be a String, which will be converted to a TZMQ_Message,
		or you can pass a TZMQ_Message straight away
	End Rem
	Method Send(message:Object, flags:Int = 0)
		Local rc:Int
		If TZMQ_Message(message)
			rc = zmq_send(Self.socket, TZMQ_Message(message).message, flags)
		Else If String(message)
			Local content:String = String(message)
			Local msg:TZMQ_Message = New TZMQ_Message.Create(content)
			rc = Self.Send(msg)
		End If

		If rc = -1 Then Throw New TZMQ_Exception
	End Method

	Rem
		bbdoc: Receive message from socket
		returns: TZMQ_Message
	End Rem
	Method Recv:TZMQ_Message(flags:Int = 0)
		Local msg:Byte Ptr = bmx_zmq_message_t()
		zmq_msg_init(msg)
		If zmq_recv(Self.socket, msg, flags) Then Return Null
		Return New TZMQ_Message.CreateFromMessage(msg)
	End Method
End Type


type.bmx: * Changed behavior of InitWithTypeID to not throw an exception when initializing an LExposedType instance with a type that's already been exposed so that it instead returns the already-initialized instance (the original instance is collected by the GC).

SuperStrict

Import "field.bmx"
Import "method.bmx"
Import "metadata.bmx"

Import Brl.LinkedList

Private

Global _exposedTypes:TList = New TList

Public

Type LExposedType
	Field exposed%
	Field static%
	Field noclass%
	Field hidefields%
	Field nonew%

	Field typeid:TTypeId
	Field methods:TList			' TList<LExposedMethod>
	Field fields:TList			' TList<LExposedField>
	Field constructor$
	Field name$

	' Returns an LExposedType for a typeid - recommended to use this instead of creating a new LExposedType and initializing it
	Function ForType:LExposedType(typeid:TTypeId)
		If typeid = ObjectTypeId Or typeid = StringTypeId Or typeid._class = ArrayTypeId._class Then
			Return Null
		EndIf

		Local link:TLink = _exposedTypes.FindLink(typeid)
		If link Then
			Return LExposedType(link.Value())
		EndIf
		Return New LExposedType.InitWithTypeID(typeid)
	End Function

	' Compares LExposedTypes based on the TTypeId associated with each LExposedType
	Method Compare:Int(other:Object)
		Return typeid.Compare(LExposedType(other).typeid)
	End Method

	' Returns a list of exposed types to iterate over
	Function EnumTypes:TList()
		Return _exposedTypes.Copy()
	End Function

	' Initializes an LExposedType with information for the type passed
	' The object returned may not be the one you originally sent the initialize message to
	' If there is already an instance for this type, that instance will be returned instead
	' of proceeding with intialization
	Method InitWithTypeID:LExposedType(tid:TTypeId)
		If tid = ObjectTypeId Or typeid = StringTypeId Or typeid._class = ArrayTypeId._class Then
			Return Null
		EndIf

		Local lnk:TLink = _exposedTypes.FindLink(tid)
		If lnk Then
			Return LExposedType(lnk.Value())
		EndIf

		exposed = typeid.Metadata(LUGI_META_EXPOSE).ToInt()>0
		static = typeid.Metadata(LUGI_META_STATIC).ToInt()>0
		noclass = typeid.Metadata(LUGI_META_NOCLASS).ToInt()>0
		hidefields = typeid.Metadata(LUGI_META_HIDEFIELDS).ToInt()>0
		nonew = typeid.Metadata(LUGI_META_DISABLECONSTRUCTOR).ToInt()>0

		name = typeid.Metadata(LUGI_META_RENAME).Trim()
		If Not name Then
			name = typeid.Name()
		EndIf

		If Not (nonew Or (static and noclass)) Then
			constructor = typeid.Metadata(LUGI_META_CONSTRUCTOR).Trim()
			If Not constructor Then
				' Force New[A-Z_].* as default
				constructor = "New"+name[0..1].ToUpper()+name[1..]
			EndIf
		EndIf

		__initMethods
		__initFields

		_exposedTypes.AddLast(Self)

		Return Self
	End Method

	Method PreInitBlock:String()
		Local outs$=""

		If Not (static And noclass) Then
			For Local m:LExposedMethod = EachIn methods
				Local initString$ = m.PreInitBlock()
				If initString Then
					outs :+ "~t" + initString + "~n"
				EndIf
			Next
		EndIf

		If Not noclass Then
			For Local f:LExposedField = EachIn fields
				Local initString$ = f.PreInitBlock()
				If initString Then
					outs :+ "~t" + initString + "~n"
				EndIf
			Next
		EndIf

		Return outs
	End Method

	Method PostInitBlock:String()
		If Not (nonew Or (static And noclass)) Then
			Return 	"~tlua_pushlightuserdata lua_vm, Byte Ptr(TTypeId.ForName(~q" + typeid.Name() + "~q)._class)" + ..
					"~tlua_pushcclosure lua_vm, p_lugi_new_object, 1"
		ElseIf static And Not noclass Then
			Return	"~t"
		EndIf
	End Method

	Method MethodImplementations:String()
		Local m:LExposedMethod
		Local outs$
		Local instMethod% = Not (static And noclass)
		Local block$

		For m = EachIn methods
			block = m.Implementation(instMethod)
			If block Then
				outs :+ "~n~n"+block
			EndIf
		Next

		Return outs
	End Method

	Method _exposedInParent:Int(m:TMethod)
		Local name$ = m.Name().ToLower()

		Local typ:TTypeId = typeid.SuperType()
		While typ

		Wend
	End Method

	Method __initMethods()
		methods = New TList

		If Not exposed Then
			Return
		EndIf

		' Build list of exposed methods
		For Local m:TMethod = EachIn typeid.Methods()

		Next
	End Method

	Method __initFields()
		fields = New TList

		If Not exposed Or hidefields Then
			Return
		EndIf

		For Local f:TField = EachIn typeid.Fields()

		Next
	End Method
End Type

' Builds up the information for all types
Function BuildTypeInfo()
End Function

Private

' Recursively creates the information for types
Function _buildTypeInfo(types:TList)
	' Iterate over types and load data for them
	For Local tid:TTypeId = EachIn types
		New LExposedType.InitWithTypeID(tid)
		_buildTypeInfo(tid.DerivedTypes())
	Next
End Function

SuperStrict

Import "field.bmx"
Import "method.bmx"
Import "metadata.bmx"

Import Brl.LinkedList

Private

Global _exposedTypes:TList = New TList

Public

Type LExposedType
	Field exposed%
	Field static%
	Field noclass%
	Field hidefields%
	Field nonew%

	Field typeid:TTypeId
	Field methods:TList			' TList<LExposedMethod>
	Field fields:TList			' TList<LExposedField>
	Field constructor$
	Field name$

	' Returns an LExposedType for a typeid - recommended to use this instead of creating a new LExposedType and initializing it
	Function ForType:LExposedType(typeid:TTypeId)
		If typeid = ObjectTypeId Or typeid = StringTypeId Or typeid._class = ArrayTypeId._class Then
			Return Null
		EndIf

		Local link:TLink = _exposedTypes.FindLink(typeid)
		If link Then
			Return LExposedType(link.Value())
		EndIf
		Return New LExposedType.InitWithTypeID(typeid)
	End Function

	' Compares LExposedTypes based on the TTypeId associated with each LExposedType
	Method Compare:Int(other:Object)
		Return typeid.Compare(LExposedType(other).typeid)
	End Method

	' Returns a list of exposed types to iterate over
	Function EnumTypes:TList()
		Return _exposedTypes.Copy()
	End Function

	' Initializes an LExposedType with information for the type passed
	' Will throw an exception if an LExposedType for the typeid has already been created and initialized
	Method InitWithTypeID:LExposedType(tid:TTypeId)
		typeid = tid

		If _exposedTypes.Contains(_exposedTypes) Then
			Throw "Attempt to initialize duplicate LExposedType for type "+tid.Name()
		EndIf

		exposed = typeid.Metadata(LUGI_META_EXPOSE).ToInt()>0
		static = typeid.Metadata(LUGI_META_STATIC).ToInt()>0
		noclass = typeid.Metadata(LUGI_META_NOCLASS).ToInt()>0
		hidefields = typeid.Metadata(LUGI_META_HIDEFIELDS).ToInt()>0
		nonew = typeid.Metadata(LUGI_META_DISABLECONSTRUCTOR).ToInt()>0

		name = typeid.Metadata(LUGI_META_RENAME).Trim()
		If Not name Then
			name = typeid.Name()
		EndIf

		If Not (nonew Or (static and noclass)) Then
			constructor = typeid.Metadata(LUGI_META_CONSTRUCTOR).Trim()
			If Not constructor Then
				' Force New[A-Z_].* as default
				constructor = "New"+name[0..1].ToUpper()+name[1..]
			EndIf
		EndIf

		__initMethods
		__initFields

		_exposedTypes.AddLast(Self)

		Return Self
	End Method

	Method PreInitBlock:String()
		Local outs$=""

		If Not (static And noclass) Then
			For Local m:LExposedMethod = EachIn methods
				Local initString$ = m.PreInitBlock()
				If initString Then
					outs :+ "~t" + initString + "~n"
				EndIf
			Next
		EndIf

		If Not noclass Then
			For Local f:LExposedField = EachIn fields
				Local initString$ = f.PreInitBlock()
				If initString Then
					outs :+ "~t" + initString + "~n"
				EndIf
			Next
		EndIf

		Return outs
	End Method

	Method PostInitBlock:String()
		If Not (nonew Or (static And noclass)) Then
			Return 	"~tlua_pushlightuserdata lua_vm, Byte Ptr(TTypeId.ForName(~q" + typeid.Name() + "~q)._class)" + ..
					"~tlua_pushcclosure lua_vm, p_lugi_new_object, 1"
		ElseIf static And Not noclass Then
			Return	"~t"
		EndIf
	End Method

	Method MethodImplementations:String()
		Local m:LExposedMethod
		Local outs$
		Local instMethod% = Not (static And noclass)
		Local block$

		For m = EachIn methods
			block = m.Implementation(instMethod)
			If block Then
				outs :+ "~n~n"+block
			EndIf
		Next

		Return outs
	End Method

	Method _exposedInParent:Int(m:TMethod)
		Local name$ = m.Name().ToLower()

		Local typ:TTypeId = typeid.SuperType()
		While typ

		Wend
	End Method

	Method __initMethods()
		methods = New TList

		If Not exposed Then
			Return
		EndIf

		' Build list of exposed methods
		For Local m:TMethod = EachIn typeid.Methods()

		Next
	End Method

	Method __initFields()
		fields = New TList

		If Not exposed Or hidefields Then
			Return
		EndIf

		For Local f:TField = EachIn typeid.Fields()

		Next
	End Method
End Type

' Builds up the information for all types
Function BuildTypeInfo()
End Function

Private

' Recursively creates the information for types
Function _buildTypeInfo(types:TList)
	' Iterate over types and load data for them
	For Local tid:TTypeId = EachIn types
		New LExposedType.InitWithTypeID(tid)
		_buildTypeInfo(tid.DerivedTypes())
	Next
End Function


newline was missing

newline was missing

Rem
Copyright (c) 2010 Tim Howard

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

Rem
	bbdoc: Maximus 'help' argument implementation.
End Rem
Type mxHelpImpl Extends mxArgumentImplementation

	Method New()
		init(["help", "--help", "-h"])
	End Method

	Rem
		bbdoc: Check the current arguments for errors (according to the specific implementation).
		returns: Nothing.
		about: This method will throw an error if the given arguments are invalid.
	End Rem
	Method CheckArgs()
		Select GetCallConvention()
			Case mxCallConvention.COMMAND ' "help"
				If m_args = Null
					ThrowCommonError(mxCmdErrors.MISSINGPARAMS, "help")
				End If
			Case mxCallConvention.OPTION ' "--help" or "-h"
				If m_args <> Null
					ThrowCommonError(mxOptErrors.DOESNOTTAKEPARAMS, "-h|--help")
				End If
		End Select
	End Method

	Rem
		bbdoc: Get a string describing the typical usage of the argument.
		returns: A string describing the typical usage of the argument.
	End Rem
	Method GetUsage:String()
		Select GetCallConvention()
			Case mxCallConvention.COMMAND
				Return "usage: maximus help <command>~n" + ..
						"e.g. maximus help get"
			Case mxCallConvention.OPTION
				Return "maximus usage: maximus [-v|--version] [-h|--help] COMMAND [ARGS]~n" + ..
						"The most commonly used commands:~n" + ..
						"~tget~tGet the given set modules~n" + ..
						"~tremove~tRemove the given set of modules~n" + ..
						"~tupdate~tUpdate the current set of modules~n" + ..
						"~thelp~tGet help on a specific command~n" + ..
						"Try 'maximus help <command>' for more information on a specific command."
		End Select
	End Method

	Rem
		bbdoc: Execute the implementation's operation.
		returns: Nothing.
	End Rem
	Method Execute()
		Select GetCallConvention()
			Case mxCallConvention.COMMAND
				For Local command:String = EachIn m_args
					If command.ToLower() = "help"
						logger.LogMessage(command + ":~t" + "HELP HELP I'M BEING REPRESSED!")
					Else
						Local argimpl:mxArgumentImplementation = mainapp.m_arghandler.GetArgImplFromAlias(command)
						If argimpl <> Null
							logger.LogMessage(command + ":~t" + argimpl.GetUsage().Replace("~n", "~n~t~t"))
						Else
							logger.LogMessage(command + ":~tCommand not found")
						End If
					End If
				Next
			Case mxCallConvention.OPTION
				logger.LogMessage(GetUsage())
		End Select
	End Method

End Type

Rem
Copyright (c) 2010 Tim Howard

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

Rem
	bbdoc: Maximus 'help' argument implementation.
End Rem
Type mxHelpImpl Extends mxArgumentImplementation

	Method New()
		init(["help", "--help", "-h"])
	End Method

	Rem
		bbdoc: Check the current arguments for errors (according to the specific implementation).
		returns: Nothing.
		about: This method will throw an error if the given arguments are invalid.
	End Rem
	Method CheckArgs()
		Select GetCallConvention()
			Case mxCallConvention.COMMAND ' "help"
				If m_args = Null
					ThrowCommonError(mxCmdErrors.MISSINGPARAMS, "help")
				End If
			Case mxCallConvention.OPTION ' "--help" or "-h"
				If m_args <> Null
					ThrowCommonError(mxOptErrors.DOESNOTTAKEPARAMS, "-h|--help")
				End If
		End Select
	End Method

	Rem
		bbdoc: Get a string describing the typical usage of the argument.
		returns: A string describing the typical usage of the argument.
	End Rem
	Method GetUsage:String()
		Select GetCallConvention()
			Case mxCallConvention.COMMAND
				Return "usage: maximus help <command>~n" + ..
						"e.g. maximus help get"
			Case mxCallConvention.OPTION
				Return "maximus usage: maximus [-v|--version] [-h|--help] COMMAND [ARGS]~n" + ..
						"The most commonly used commands:~n" + ..
						"~tget~tGet the given set modules~n" + ..
						"~tremove~tRemove the given set of modules" + ..
						"~tupdate~tUpdate the current set of modules~n" + ..
						"~thelp~tGet help on a specific command~n" + ..
						"Try 'maximus help <command>' for more information on a specific command."
		End Select
	End Method

	Rem
		bbdoc: Execute the implementation's operation.
		returns: Nothing.
	End Rem
	Method Execute()
		Select GetCallConvention()
			Case mxCallConvention.COMMAND
				For Local command:String = EachIn m_args
					If command.ToLower() = "help"
						logger.LogMessage(command + ":~t" + "HELP HELP I'M BEING REPRESSED!")
					Else
						Local argimpl:mxArgumentImplementation = mainapp.m_arghandler.GetArgImplFromAlias(command)
						If argimpl <> Null
							logger.LogMessage(command + ":~t" + argimpl.GetUsage().Replace("~n", "~n~t~t"))
						Else
							logger.LogMessage(command + ":~tCommand not found")
						End If
					End If
				Next
			Case mxCallConvention.OPTION
				logger.LogMessage(GetUsage())
		End Select
	End Method

End Type


TXMLRPC_Response_Data.IterateVector() now uses the Value ID as the TMap index when it has been set, otherwise key "0" will be used

Rem
	bbdoc: Exception for TXMLRPC_Response_Data
End Rem
Type TXMLRPC_Response_Data_Exception Extends TXMLRPC_Exception
End Type

Rem
	bbdoc: Data returned from XML-RPC server
End Rem
Type TXMLRPC_Response_Data
	Rem
		bbdoc: This field contains all data returned from a response. If a response value was given an ID it can be accessed by its ID. If not it can be accessed with an ID of 0..inf
	End Rem
	Field data:TMap

	Rem
		bbdoc: Create a TXMLRPC_Response_Data object by passing the response XML message and the output options.
	End Rem
	Method Create:TXMLRPC_Response_Data(xmlMessage:String, options:Byte Ptr)
		Local message:Byte Ptr = xmlMessage.ToCString()
		Local request:Byte Ptr = XMLRPC_REQUEST_FromXML(message, 0, options)

		Local el:Byte Ptr = XMLRPC_RequestGetData(request)

		Self.data = TXMLRPC_Response_Data.IterateVector(el)

		MemFree(message)
		XMLRPC_RequestFree(request, 1)

		Return Self
	End Method

	Rem
		bbdoc: Iterate over an XMLRPC vector and add it to a TMap. Private function
	End Rem
	Function IterateVector:TMap(el:Byte Ptr)
		Local data:TMap = New TMap

		If el
			'Rewind vector
			Local itr:Byte Ptr = XMLRPC_VectorRewind(el)
			If Not itr
				Local cStr:Byte Ptr = XMLRPC_GetValueID(itr)
				Local id:String = "0"
				If cStr
					id = String.FromCString(cStr)
					XMLRPC_Free(cstr)
				End If

				data.Insert(id, TXMLRPC_Value_Abstract.XMLRPC_To_BlizMax(el))
			Else
				Local dataCounter:Int = 0
				While itr
					Local cStr:Byte Ptr = XMLRPC_GetValueID(itr)
					Local id:String = String.FromCString(cStr)

					If id.Length = 0
						id = String.FromInt(dataCounter)
						dataCounter:+1
					End If

					data.Insert(id, TXMLRPC_Value_Abstract.XMLRPC_To_BlizMax(itr))
					XMLRPC_Free(cStr)

					'Next element
					itr = XMLRPC_VectorNext(el)
				Wend
			End If
		End If

		Return data
	End Function

	Rem
		bbdoc: Helper function to show what's inside the map
	End Rem
	Function DebugData:String(map:TMap, pad:Int Var)
		Local str:String
		Local prefix:String
		For Local i:Int = 0 To pad
			prefix:+"-"
		Next

		For Local val:TXMLRPC_Value_Abstract = EachIn map.Values()
			str:+prefix + " " + TTypeId.ForObject(val).Name() + " (" + val.name + ") = " + val.ToString() + "~n"
			If TXMLRPC_Value_Collection(val)
				pad:+1
				str:+TXMLRPC_Response_Data.DebugData(TXMLRPC_Value_Collection(val).data, pad) + "~n"
				pad:-1
			End If
		Next
		Return str
	End Function
End Type

Rem
	bbdoc: Exception for TXMLRPC_Response_Data
End Rem
Type TXMLRPC_Response_Data_Exception Extends TXMLRPC_Exception
End Type

Rem
	bbdoc: Data returned from XML-RPC server
End Rem
Type TXMLRPC_Response_Data
	Rem
		bbdoc: This field contains all data returned from a response. If a response value was given an ID it can be accessed by its ID. If not it can be accessed with an ID of 0..inf
	End Rem
	Field data:TMap

	Rem
		bbdoc: Create a TXMLRPC_Response_Data object by passing the response XML message and the output options.
	End Rem
	Method Create:TXMLRPC_Response_Data(xmlMessage:String, options:Byte Ptr)
		Local message:Byte Ptr = xmlMessage.ToCString()
		Local request:Byte Ptr = XMLRPC_REQUEST_FromXML(message, 0, options)

		Local el:Byte Ptr = XMLRPC_RequestGetData(request)

		Self.data = TXMLRPC_Response_Data.IterateVector(el)

		XMLRPC_RequestFree(request, 1)
		MemFree(message)
		Return Self
	End Method

	Rem
		bbdoc: Iterate over an XMLRPC vector and add it to a TMap. Private function
	End Rem
	Function IterateVector:TMap(el:Byte Ptr)
		Local data:TMap = New TMap

		If el
			'Rewind vector
			Local itr:Byte Ptr = XMLRPC_VectorRewind(el)
			If Not itr
				data.Insert("0", TXMLRPC_Value_Abstract.XMLRPC_To_BlizMax(el))
			Else
				Local dataCounter:Int = 0
				While itr
					Local cStr:Byte Ptr = XMLRPC_GetValueID(itr)
					Local id:String = String.FromCString(cStr)

					If id.Length = 0
						id = String.FromInt(dataCounter)
						dataCounter:+1
					End If

					data.Insert(id, TXMLRPC_Value_Abstract.XMLRPC_To_BlizMax(itr))
					XMLRPC_Free(cStr)

					'Next element
					itr = XMLRPC_VectorNext(el)
				Wend
			End If
		End If

		Return data
	End Function

	Rem
		bbdoc: Helper function to show what's inside the map
	End Rem
	Function DebugData:String(map:TMap, pad:Int Var)
		Local str:String
		Local prefix:String
		For Local i:Int = 0 To pad
			prefix:+"-"
		Next

		For Local val:TXMLRPC_Value_Abstract = EachIn map.Values()
			str:+prefix + " " + TTypeId.ForObject(val).Name() + " (" + val.name + ") = " + val.ToString() + "~n"
			If TXMLRPC_Value_Collection(val)
				pad:+1
				str:+TXMLRPC_Response_Data.DebugData(TXMLRPC_Value_Collection(val).data, pad) + "~n"
				pad:-1
			End If
		Next
		Return str
	End Function
End Type


Documentation

Documentation

Rem
	bbdoc: User Input interface
End Rem
Type mxUserInput

	Rem
		bbdoc:Command Line Interface
	End Rem
	Const c_cli:Byte = 0

	Rem
		bbdoc:Graphical User Interface
	End Rem
	Const c_gui:Byte = 1

	Field m_driver:mxUserInputDriver

	Rem
		bbdoc: Factory for initializing mxUserInput object
		about: interface can be either c_cli of c_gui
	End Rem
	Function factory:mxUserInput(interface:Byte)
		Local ui:mxUserInput = New mxUserInput
		Select interface
			Case c_cli
				ui.m_driver = New mxUserInputDriverCLI
			Case c_gui
				ui.m_driver = New mxUserInputDriverGUI
		End Select
		Return ui
	End Function

	Rem
		bbdoc: Ask user to confirm an action
		returns: True or False
	End Rem
	Method Confirm:Byte(question:String)
		Return Self.m_driver.Confirm(question)
	End Method

End Type

Rem
	bbdoc: User Input Driver interface
End Rem
Type mxUserInputDriver Abstract

	Rem
		bbdoc: Ask user to confirm an action
		returns: True or False
	End Rem
	Method Confirm:Byte(question:String) Abstract

End Type

Rem
	bbdoc: UserInpitDriver for Command Line Interface
End Rem
Type mxUserInputDriverCLI Extends mxUserInputDriver

	Rem
		bbdoc: Ask user to confirm an action
		returns: True or False
	End Rem
	Method Confirm:Byte(question:String)
		Local resp:String = Input(question + " " + _s("message.confirm")).ToLower()
		If resp = "y" Or resp = "yes"
			Return True
		Else
			Return False
		End If
	End Method

End Type

Rem
	bbdoc: UserInputDriver for Graphical User Interface
End Rem
Type mxUserInputDriverGUI Extends mxUserInputDriver

	Rem
		bbdoc:Ask user to confirm an action
	End Rem
	Method Confirm:Byte(question:String)
		Return brl.system.Confirm(question)
	End Method

End Type

Rem
	bbdoc: User Input interface
End Rem
Type mxUserInput

	Rem
		bbdoc:Command Line Interface
	End Rem
	Const c_cli:Byte = 0

	Rem
		bbdoc:Graphical User Interface
	End Rem
	Const c_gui:Byte = 1

	Field m_driver:mxUserInputDriver

	Rem
		bbdoc: Factory for initializing mxUserInput object
		about: interface can be either c_cli of c_gui
	End Rem
	Function factory:mxUserInput(interface:Byte)
		Local ui:mxUserInput = New mxUserInput
		Select interface
			Case c_cli
				ui.m_driver = New mxUserInputDriverCLI
			Case c_gui
				ui.m_driver = New mxUserInputDriverGUI
		End Select
		Return ui
	End Function

	Rem
		bbdoc: Ask user to confirm an action
		returns: True or False
	End Rem
	Method Confirm:Byte(question:String)
		Return Self.m_driver.Confirm(question)
	End Method

End Type

Rem
	bbdoc: User Input Driver interface
End Rem
Type mxUserInputDriver Abstract

	Rem
		bbdoc: Ask user to confirm an action
		returns: True or False
	End Rem
	Method Confirm:Byte(question:String) Abstract

End Type

Rem
	bbdoc: UserInpitDriver for Command Line Interface
End Rem
Type mxUserInputDriverCLI Extends mxUserInputDriver

	Rem
		bbdoc: Ask user to confirm an action
		returns: True or False
	End Rem
	Method Confirm:Byte(question:String)
		Local resp:String = Input(question + " " + _s("message.confirm")).ToLower()
		If resp = "y" Or resp = "yes"
			Return True
		Else
			Return False
		End If
	End Method

End Type

Type mxUserInputDriverGUI Extends mxUserInputDriver
	Rem
		bbdoc:Ask user to confirm an action
	End Rem
	Method Confirm:Byte(question:String)
		Return brl.system.Confirm(question)
	End Method

End Type


Modified to simply call Graphics.

Modified to simply call Graphics.

Strict

Import MaxB3D.Drivers

Graphics 800,600
SetAmbientLight 0,0,0

Local logo:TTexture=LoadTexture("media/blitzlogo.bmp")

Local pixmap:TPixmap=CreatePixmap(64,64,PF_RGBA8888)
For Local y=0 To 63
	For Local x=0 To 63
		Local data:Int Ptr=Int Ptr(PixmapPixelPtr(pixmap,x,y))
		If x<32 And y<32 data[0]=$FFFFFFFF
		If x>31 And y<32 data[0]=$FF808080
		If x<32 And y>31 data[0]=$FF808080
		If x>31 And y>31 data[0]=$FFFFFFFF
	Next
Next

Local grid:TTexture=LoadTexture(pixmap)
SetTextureScale grid,.5,.5

Local env:TTexture=LoadTexture("media/spheremap.bmp",TEXTURE_COLOR|TEXTURE_ALPHA|TEXTURE_SPHEREMAP)

Local cube:TMesh=CreateCube()
SetEntityTexture cube,logo,0,0
SetEntityTexture cube,grid,1,0
SetEntityTexture cube,env,2,0
UpdateMeshNormals cube

Local camera:TCamera=CreateCamera()
SetEntityPosition camera,0,0,-4

Local light1:TLight=CreateLight()
TurnEntity light1,45,45,0
SetEntityColor light1,255,0,0

Local light2:TLight=CreateLight()
TurnEntity light2,-45,45,0
SetEntityColor light2,0,255,0

Local light3:TLight=CreateLight()
TurnEntity light3,45,-45,0
SetEntityColor light3,0,0,255

Local blend1=BLEND_MULTIPLY,blend2=BLEND_MULTIPLY,blend3=BLEND_ALPHA
SetTextureBlend logo,blend1
SetTextureBlend grid,blend2
SetTextureBlend env,blend3

Local offset#

While Not KeyHit(KEY_ESCAPE) And Not AppTerminate()
	If KeyHit(KEY_F1)
		blend1=blend1+1
		If blend1=4 blend1=0
		SetTextureBlend logo,blend1
	EndIf
	If KeyHit(KEY_F2)
		blend2=blend2+1
		If blend2=4 blend2=0
		SetTextureBlend grid,blend2
	EndIf
	If KeyHit(KEY_F3)
		blend3=blend3+1
		If blend3=4 blend3=0
		SetTextureBlend env,blend3
	EndIf
	If KeyDown(KEY_A)
		TranslateEntity camera,0,0,.1
	EndIf
	If KeyDown(KEY_Z)
		TranslateEntity camera,0,0,-.1
	EndIf

	offset=offset-.01
	SetTexturePosition logo,offset,0

	TurnEntity cube,.1,.2,.3

	RenderWorld
	DoMax2D
	DrawText "(F1) TextureBlend 1="+mode(blend1),0,0
	DrawText "(F2) TextureBlend 2="+mode(blend2),0,13
	DrawText "(F3) TextureBlend 3="+mode(blend3),0,26

	Flip
Wend

Function mode$( mode )
	Select mode
	Case BLEND_NONE
		Return "BLEND_NONE"
	Case BLEND_ALPHA
		Return "BLEND_ALPHA"
	Case BLEND_MULTIPLY
		Return "BLEND_MULTIPLY"
	Case BLEND_ADD
		Return "BLEND_ADD"
	End Select
	Return "Unknown"
End Function

Strict

Import MaxB3D.Drivers

GLGraphics3D 800,600
SetAmbientLight 0,0,0

Local logo:TTexture=LoadTexture("media/blitzlogo.bmp")

Local pixmap:TPixmap=CreatePixmap(64,64,PF_RGBA8888)
For Local y=0 To 63
	For Local x=0 To 63
		Local data:Int Ptr=Int Ptr(PixmapPixelPtr(pixmap,x,y))
		If x<32 And y<32 data[0]=$FFFFFFFF
		If x>31 And y<32 data[0]=$FF808080
		If x<32 And y>31 data[0]=$FF808080
		If x>31 And y>31 data[0]=$FFFFFFFF
	Next
Next

Local grid:TTexture=LoadTexture(pixmap)
SetTextureScale grid,.5,.5

Local env:TTexture=LoadTexture("media/spheremap.bmp",TEXTURE_COLOR|TEXTURE_ALPHA|TEXTURE_SPHEREMAP)

Local cube:TMesh=CreateCube()
SetEntityTexture cube,logo,0,0
SetEntityTexture cube,grid,1,0
SetEntityTexture cube,env,2,0
UpdateMeshNormals cube

Local camera:TCamera=CreateCamera()
SetEntityPosition camera,0,0,-4

Local light1:TLight=CreateLight()
TurnEntity light1,45,45,0
SetEntityColor light1,255,0,0

Local light2:TLight=CreateLight()
TurnEntity light2,-45,45,0
SetEntityColor light2,0,255,0

Local light3:TLight=CreateLight()
TurnEntity light3,45,-45,0
SetEntityColor light3,0,0,255

Local blend1=BLEND_MULTIPLY,blend2=BLEND_MULTIPLY,blend3=BLEND_ALPHA
SetTextureBlend logo,blend1
SetTextureBlend grid,blend2
SetTextureBlend env,blend3

Local offset#

While Not KeyHit(KEY_ESCAPE) And Not AppTerminate()
	If KeyHit(KEY_F1)
		blend1=blend1+1
		If blend1=4 blend1=0
		SetTextureBlend logo,blend1
	EndIf
	If KeyHit(KEY_F2)
		blend2=blend2+1
		If blend2=4 blend2=0
		SetTextureBlend grid,blend2
	EndIf
	If KeyHit(KEY_F3)
		blend3=blend3+1
		If blend3=4 blend3=0
		SetTextureBlend env,blend3
	EndIf
	If KeyDown(KEY_A)
		TranslateEntity camera,0,0,.1
	EndIf
	If KeyDown(KEY_Z)
		TranslateEntity camera,0,0,-.1
	EndIf

	offset=offset-.01
	SetTexturePosition logo,offset,0

	TurnEntity cube,.1,.2,.3

	RenderWorld
	DoMax2D
	DrawText "(F1) TextureBlend 1="+mode(blend1),0,0
	DrawText "(F2) TextureBlend 2="+mode(blend2),0,13
	DrawText "(F3) TextureBlend 3="+mode(blend3),0,26

	Flip
Wend

Function mode$( mode )
	Select mode
	Case BLEND_NONE
		Return "BLEND_NONE"
	Case BLEND_ALPHA
		Return "BLEND_ALPHA"
	Case BLEND_MULTIPLY
		Return "BLEND_MULTIPLY"
	Case BLEND_ADD
		Return "BLEND_ADD"
	End Select
	Return "Unknown"
End Function


Added module description

Added module description

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.01"
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.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)
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 "Version: 0.01"
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.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)
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


Fixed possible TSurface.Copy issue.

Fixed possible TSurface.Copy issue.

Strict

Import MaxB3D.Math
Import "brush.bmx"

Const SURFACE_POS = 1
Const SURFACE_NML = 2
Const SURFACE_CLR = 4
Const SURFACE_TEX = 8
Const SURFACE_TRI = 16
Const SURFACE_ALL = SURFACE_POS|SURFACE_NML|SURFACE_CLR|SURFACE_TEX|SURFACE_TRI

Type TSurface
	Field _brush:TBrush=New TBrush

	Field _vertexcnt,_trianglecnt
	Field _vertexpos#[],_vertexnml#[],_vertexclr#[]
	Field _vertextex#[][],_texcoordsize=-1

	Field _triangle[]

	Field _res:TSurfaceRes,_reset=-1

	Field _resetbounds=True,_minx#,_miny#,_minz#,_maxx#,_maxy#,_maxz#
	Field _boundsupdatedmsg:TMaxB3DMsg=New TMaxB3DMsg

	Method Copy:TSurface(data=SURFACE_ALL)
		Local surface:TSurface=New TSurface
		surface._brush.Load(_brush)
		surface._vertexcnt=_vertexcnt
		If data&SURFACE_POS surface._vertexpos=_vertexpos[..]
		If data&SURFACE_NML surface._vertexnml=_vertexnml[..]
		If data&SURFACE_CLR surface._vertexclr=_vertexclr[..]
		If data&SURFACE_TEX
			surface._vertextex = New Float[][_texcoordsize]
			For Local i=0 To _texcoordsize-1
				surface._vertextex[i]=_vertextex[i][..]
			Next
			surface._texcoordsize=_texcoordsize
		EndIf
		If data&SURFACE_TRI surface._trianglecnt=_trianglecnt;surface._triangle=_triangle[..]
		Return surface
	End Method

	Method Resize(vertexcount,trianglecount)
		If vertexcount>-1
			_vertexpos=_vertexpos[..vertexcount*3]
			_vertexnml=_vertexnml[..vertexcount*3]
			_vertexclr=_vertexclr[..vertexcount*4]
			For Local i=_vertexcnt*4 To vertexcount*4-1
				_vertexclr[i]=1.0
			Next
			For Local i=0 To _texcoordsize-1
				_vertextex[i]=_vertextex[i][..vertexcount*2]
			Next
			_vertexcnt=vertexcount
		EndIf

		If trianglecount>-1
			_triangle=_triangle[..trianglecount*3]
			_trianglecnt=trianglecount
		EndIf
	End Method

	Method GetSize(vertices Var,triangles Var)
		vertices=_vertexcnt
		triangles=_trianglecnt
	End Method

	Method AddVertex(x#,y#,z#,u#=0.0,v#=0.0)
		Resize(_vertexcnt+1,-1)
		SetCoords(_vertexcnt-1,x,y,z)
		SetTexCoords(_vertexcnt-1,u,v)
		Return _vertexcnt-1
	End Method

	Method GetCoords(index,x# Var,y# Var,z# Var)
		x=_vertexpos[index*3+0]
		y=_vertexpos[index*3+1]
		z=_vertexpos[index*3+2]
	End Method
	Method SetCoords(index,x#,y#,z#)
		_vertexpos[index*3+0]=x
		_vertexpos[index*3+1]=y
		_vertexpos[index*3+2]=z
		_reset:|1;_resetbounds=True
	End Method

	Method GetNormal(index,nx# Var,ny# Var,nz# Var)
		nx=_vertexnml[index*3+0]*-1
		ny=_vertexnml[index*3+1]*-1
		nz=_vertexnml[index*3+2]*-1
	End Method
	Method SetNormal(index,nx#,ny#,nz#)
		_vertexnml[index*3+0]=nx*-1
		_vertexnml[index*3+1]=ny*-1
		_vertexnml[index*3+2]=nz*-1
		_reset:|2
	End Method

	Method GetColor(index,red Var,green Var,blue Var,alpha# Var)
		red=_vertexclr[index*4+0]*255.0
		green=_vertexclr[index*4+1]*255.0
		blue=_vertexclr[index*4+2]*255.0
		alpha=_vertexclr[index*4+3]
	End Method
	Method SetColor(index,red,green,blue,alpha#)
		_vertexclr[index*4+0]=red/255.0
		_vertexclr[index*4+1]=green/255.0
		_vertexclr[index*4+2]=blue/255.0
		_vertexclr[index*4+3]=alpha
		_reset:|4
	End Method

	Method GetTexCoords(index,u# Var,v# Var,set=0)
		ResizeTexSets set
		u=_vertextex[set][index*2+0]
		v=_vertextex[set][index*2+1]
	End Method
	Method SetTexCoords(index,u#,v#,set=0)
		ResizeTexSets set
		_vertextex[set][index*2+0]=u
		_vertextex[set][index*2+1]=v
		_reset:|Int(2^(4+set))
	End Method

	Method ResizeTexSets(set)
		If set+1>_texcoordsize
			Local size=_vertextex.length
			_vertextex=_vertextex[..set+1]
			For Local i=size To set
				_vertextex[i]=New Float[_vertexcnt*2]
			Next
			_texcoordsize=set+1
		EndIf
	End Method

	Method AddTriangle(v0,v1,v2)
		Resize(-1,_trianglecnt+1)
		SetTriangle _trianglecnt-1,v0,v1,v2
		Return _trianglecnt-1
	End Method

	Method GetTriangle(index,v0 Var,v1 Var,v2 Var)
		v0=_triangle[index*3+0]
		v1=_triangle[index*3+1]
		v2=_triangle[index*3+2]
	End Method
	Method SetTriangle(index,v0,v1,v2)
		_triangle[index*3+0]=v0
		_triangle[index*3+1]=v1
		_triangle[index*3+2]=v2
		_reset:|8
	End Method

	Method Flip()
		For Local t=0 To _trianglecnt-1
			Local v2=_triangle[t*3+2]
			_triangle[t*3+2]=_triangle[t*3+0]
			_triangle[t*3+0]=v2
		Next
		For Local v=0 To _vertexcnt-1
			_vertexnml[(v*3)+0]:*-1
			_vertexnml[(v*3)+1]:*-1
			_vertexnml[(v*3)+2]:*-1
		Next
		_reset:|2|8
	End Method

	Method Transform(matrix:TMatrix)
		For Local i=0 To _vertexcnt-1
			matrix.TransformVec3 _vertexpos[i*3+0],_vertexpos[i*3+1],_vertexpos[i*3+2]
			'matrix.TransformVector _vertexnml[i+0],_vertexnml[i+1],_vertexnml[i+2],w
		Next
	End Method

	Method UpdateBounds(force=False)
		If Not _resetbounds And force=false Return
		_minx=999999999;_miny=999999999;_minz=999999999
		_maxx=-999999999;_maxy=-999999999;_maxz=-999999999
		For Local v=0 To _vertexcnt-1
			Local x#,y#,z#
			GetCoords v,x,y,z
			_minx=Min(x,_minx);_maxx=Max(x,_maxx)
			_miny=Min(y,_miny);_maxy=Max(y,_maxy)
			_minz=Min(z,_minz);_maxz=Max(z,_maxz)
		Next
		_boundsupdatedmsg.Run
		_resetbounds=False
	End Method

	Method UpdateNormals(smoothing=True)
		If smoothing
			C_UpdateNormals(_trianglecnt,_vertexcnt,_triangle,_vertexpos,_vertexnml)
		Else
			Local face_normal:TVector[_trianglecnt],vertex_triangles[][_vertexcnt]

			For Local i=0 To _trianglecnt-1
				Local v0,v1,v2
				GetTriangle i,v0,v1,v2

				vertex_triangles[v0]:+[i]
				vertex_triangles[v1]:+[i]
				vertex_triangles[v2]:+[i]

				Local a:TVector=New TVector,b:TVector=New TVector,c:TVector=New TVector
				GetCoords v0,a.x,a.y,a.z
				GetCoords v1,b.x,b.y,b.z
				GetCoords v2,c.x,c.y,c.z

				face_normal[i]=New TVector.FromTriangle(a,b,c)
			Next

			Local normal:TVector=New TVector
			For Local i=0 To _vertexcnt-1
				normal.Create3(0,0,0)
				For Local t=0 To vertex_triangles[i].length-1
					normal=normal.Add(face_normal[vertex_triangles[i][t]])
				Next
				normal.Normalize()
				SetNormal i,-normal.x,-normal.y,-normal.z
			Next
		EndIf
		_reset:|2
	End Method

	Method SetTriangleNormal(index,nx#,ny#,nz#)
		Local v0,v1,v2
		GetTriangle index,v0,v1,v2
		SetNormal v0,nx,ny,nz
		SetNormal v1,nx,ny,nz
		SetNormal v2,nx,ny,nz
	End Method

	Method GetBrush:TBrush()
		Return _brush.Copy()
	End Method
	Method SetBrush(brush:TBrush)
		_brush.Load(brush)
	End Method

	Method CountVertices()
		Return _vertexcnt
	End Method
	Method CountTriangles()
		Return _trianglecnt
	End Method

	Method IsEmpty()
		Return _vertexcnt=0 And _trianglecnt=0
	End Method

	Method HasAlpha()
		Return _brush.HasAlpha()
	End Method
End Type

Type TSurfaceRes Extends TDriverResource
	Field _vertexcnt
	Field _trianglecnt

	Method Copy:TSurfaceRes() Abstract
End Type

Type TMaxB3DMsg
	Field _succ:TMaxB3DMsg
	Field _context:Object
	Field _func(context:Object)

	Method Add(func(context:Object),context:Object)
		Local msg:TMaxB3DMsg=Self
		While msg._succ
			msg=msg._succ
		Wend
		msg._succ=New TMaxB3DMsg
		msg._context=context
		msg._func=func
	End Method

	Method Run()
		Local msg:TMaxB3DMsg=Self
		While msg
			If msg._func msg._func(msg._context)
			msg=msg._succ
		Wend
	End Method
End Type

Strict

Import MaxB3D.Math
Import "brush.bmx"

Const SURFACE_POS = 1
Const SURFACE_NML = 2
Const SURFACE_CLR = 4
Const SURFACE_TEX = 8
Const SURFACE_TRI = 16
Const SURFACE_ALL = SURFACE_POS|SURFACE_NML|SURFACE_CLR|SURFACE_TEX|SURFACE_TRI

Type TSurface
	Field _brush:TBrush=New TBrush

	Field _vertexcnt,_trianglecnt
	Field _vertexpos#[],_vertexnml#[],_vertexclr#[]
	Field _vertextex#[][],_texcoordsize=-1

	Field _triangle[]

	Field _res:TSurfaceRes,_reset=-1

	Field _resetbounds=True,_minx#,_miny#,_minz#,_maxx#,_maxy#,_maxz#
	Field _boundsupdatedmsg:TMaxB3DMsg=New TMaxB3DMsg

	Method Copy:TSurface(data=SURFACE_ALL)
		Local surface:TSurface=New TSurface
		surface._brush.Load(_brush)
		surface._vertexcnt=_vertexcnt
		If data&SURFACE_POS surface._vertexpos=_vertexpos[..]
		If data&SURFACE_NML surface._vertexnml=_vertexnml[..]
		If data&SURFACE_CLR surface._vertexclr=_vertexclr[..]
		If data&SURFACE_TEX surface._vertextex=_vertextex[..];surface._texcoordsize=_texcoordsize
		If data&SURFACE_TRI surface._trianglecnt=_trianglecnt;surface._triangle=_triangle[..]
		Return surface
	End Method

	Method Resize(vertexcount,trianglecount)
		If vertexcount>-1
			_vertexpos=_vertexpos[..vertexcount*3]
			_vertexnml=_vertexnml[..vertexcount*3]
			_vertexclr=_vertexclr[..vertexcount*4]
			For Local i=_vertexcnt*4 To vertexcount*4-1
				_vertexclr[i]=1.0
			Next
			For Local i=0 To _texcoordsize-1
				_vertextex[i]=_vertextex[i][..vertexcount*2]
			Next
			_vertexcnt=vertexcount
		EndIf

		If trianglecount>-1
			_triangle=_triangle[..trianglecount*3]
			_trianglecnt=trianglecount
		EndIf
	End Method

	Method GetSize(vertices Var,triangles Var)
		vertices=_vertexcnt
		triangles=_trianglecnt
	End Method

	Method AddVertex(x#,y#,z#,u#=0.0,v#=0.0)
		Resize(_vertexcnt+1,-1)
		SetCoords(_vertexcnt-1,x,y,z)
		SetTexCoords(_vertexcnt-1,u,v)
		Return _vertexcnt-1
	End Method

	Method GetCoords(index,x# Var,y# Var,z# Var)
		x=_vertexpos[index*3+0]
		y=_vertexpos[index*3+1]
		z=_vertexpos[index*3+2]
	End Method
	Method SetCoords(index,x#,y#,z#)
		_vertexpos[index*3+0]=x
		_vertexpos[index*3+1]=y
		_vertexpos[index*3+2]=z
		_reset:|1;_resetbounds=True
	End Method

	Method GetNormal(index,nx# Var,ny# Var,nz# Var)
		nx=_vertexnml[index*3+0]*-1
		ny=_vertexnml[index*3+1]*-1
		nz=_vertexnml[index*3+2]*-1
	End Method
	Method SetNormal(index,nx#,ny#,nz#)
		_vertexnml[index*3+0]=nx*-1
		_vertexnml[index*3+1]=ny*-1
		_vertexnml[index*3+2]=nz*-1
		_reset:|2
	End Method

	Method GetColor(index,red Var,green Var,blue Var,alpha# Var)
		red=_vertexclr[index*4+0]*255.0
		green=_vertexclr[index*4+1]*255.0
		blue=_vertexclr[index*4+2]*255.0
		alpha=_vertexclr[index*4+3]
	End Method
	Method SetColor(index,red,green,blue,alpha#)
		_vertexclr[index*4+0]=red/255.0
		_vertexclr[index*4+1]=green/255.0
		_vertexclr[index*4+2]=blue/255.0
		_vertexclr[index*4+3]=alpha
		_reset:|4
	End Method

	Method GetTexCoords(index,u# Var,v# Var,set=0)
		ResizeTexSets set
		u=_vertextex[set][index*2+0]
		v=_vertextex[set][index*2+1]
	End Method
	Method SetTexCoords(index,u#,v#,set=0)
		ResizeTexSets set
		_vertextex[set][index*2+0]=u
		_vertextex[set][index*2+1]=v
		_reset:|Int(2^(4+set))
	End Method

	Method ResizeTexSets(set)
		If set+1>_texcoordsize
			Local size=_vertextex.length
			_vertextex=_vertextex[..set+1]
			For Local i=size To set
				_vertextex[i]=New Float[_vertexcnt*2]
			Next
			_texcoordsize=set+1
		EndIf
	End Method

	Method AddTriangle(v0,v1,v2)
		Resize(-1,_trianglecnt+1)
		SetTriangle _trianglecnt-1,v0,v1,v2
		Return _trianglecnt-1
	End Method

	Method GetTriangle(index,v0 Var,v1 Var,v2 Var)
		v0=_triangle[index*3+0]
		v1=_triangle[index*3+1]
		v2=_triangle[index*3+2]
	End Method
	Method SetTriangle(index,v0,v1,v2)
		_triangle[index*3+0]=v0
		_triangle[index*3+1]=v1
		_triangle[index*3+2]=v2
		_reset:|8
	End Method

	Method Flip()
		For Local t=0 To _trianglecnt-1
			Local v2=_triangle[t*3+2]
			_triangle[t*3+2]=_triangle[t*3+0]
			_triangle[t*3+0]=v2
		Next
		For Local v=0 To _vertexcnt-1
			_vertexnml[(v*3)+0]:*-1
			_vertexnml[(v*3)+1]:*-1
			_vertexnml[(v*3)+2]:*-1
		Next
		_reset:|2|8
	End Method

	Method Transform(matrix:TMatrix)
		For Local i=0 To _vertexcnt-1
			matrix.TransformVec3 _vertexpos[i*3+0],_vertexpos[i*3+1],_vertexpos[i*3+2]
			'matrix.TransformVector _vertexnml[i+0],_vertexnml[i+1],_vertexnml[i+2],w
		Next
	End Method

	Method UpdateBounds(force=False)
		If Not _resetbounds And force=false Return
		_minx=999999999;_miny=999999999;_minz=999999999
		_maxx=-999999999;_maxy=-999999999;_maxz=-999999999
		For Local v=0 To _vertexcnt-1
			Local x#,y#,z#
			GetCoords v,x,y,z
			_minx=Min(x,_minx);_maxx=Max(x,_maxx)
			_miny=Min(y,_miny);_maxy=Max(y,_maxy)
			_minz=Min(z,_minz);_maxz=Max(z,_maxz)
		Next
		_boundsupdatedmsg.Run
		_resetbounds=False
	End Method

	Method UpdateNormals(smoothing=True)
		If smoothing
			C_UpdateNormals(_trianglecnt,_vertexcnt,_triangle,_vertexpos,_vertexnml)
		Else
			Local face_normal:TVector[_trianglecnt],vertex_triangles[][_vertexcnt]

			For Local i=0 To _trianglecnt-1
				Local v0,v1,v2
				GetTriangle i,v0,v1,v2

				vertex_triangles[v0]:+[i]
				vertex_triangles[v1]:+[i]
				vertex_triangles[v2]:+[i]

				Local a:TVector=New TVector,b:TVector=New TVector,c:TVector=New TVector
				GetCoords v0,a.x,a.y,a.z
				GetCoords v1,b.x,b.y,b.z
				GetCoords v2,c.x,c.y,c.z

				face_normal[i]=New TVector.FromTriangle(a,b,c)
			Next

			Local normal:TVector=New TVector
			For Local i=0 To _vertexcnt-1
				normal.Create3(0,0,0)
				For Local t=0 To vertex_triangles[i].length-1
					normal=normal.Add(face_normal[vertex_triangles[i][t]])
				Next
				normal.Normalize()
				SetNormal i,-normal.x,-normal.y,-normal.z
			Next
		EndIf
		_reset:|2
	End Method

	Method SetTriangleNormal(index,nx#,ny#,nz#)
		Local v0,v1,v2
		GetTriangle index,v0,v1,v2
		SetNormal v0,nx,ny,nz
		SetNormal v1,nx,ny,nz
		SetNormal v2,nx,ny,nz
	End Method

	Method GetBrush:TBrush()
		Return _brush.Copy()
	End Method
	Method SetBrush(brush:TBrush)
		_brush.Load(brush)
	End Method

	Method CountVertices()
		Return _vertexcnt
	End Method
	Method CountTriangles()
		Return _trianglecnt
	End Method

	Method IsEmpty()
		Return _vertexcnt=0 And _trianglecnt=0
	End Method

	Method HasAlpha()
		Return _brush.HasAlpha()
	End Method
End Type

Type TSurfaceRes Extends TDriverResource
	Field _vertexcnt
	Field _trianglecnt

	Method Copy:TSurfaceRes() Abstract
End Type

Type TMaxB3DMsg
	Field _succ:TMaxB3DMsg
	Field _context:Object
	Field _func(context:Object)

	Method Add(func(context:Object),context:Object)
		Local msg:TMaxB3DMsg=Self
		While msg._succ
			msg=msg._succ
		Wend
		msg._succ=New TMaxB3DMsg
		msg._context=context
		msg._func=func
	End Method

	Method Run()
		Local msg:TMaxB3DMsg=Self
		While msg
			If msg._func msg._func(msg._context)
			msg=msg._succ
		Wend
	End Method
End Type