Type TPhysic
	Global World:Byte Ptr
	Global Debug:Byte = False
	Global ActiveBodies:Int
	Global UnActiveBodies:Int = 0
	Global CurrentContact:TContactinfo
	Global ContactEnd(Contact:TContactinfo)
	Global ContactProcess(Contact:TContactInfo)
	Global BallUserCallBack(Ball:TBallConstrait)
	Global MainBall_Callback(ball:Byte Ptr)
	
	Field PhysicObjects:TList = New TList
	Field Standard_Transform_Callback(body:Byte Ptr)
	Field Standard_ForceAndTorque_Callback(body:Byte Ptr)
	Field Standard_Activation_Callback(body:Byte Ptr)
	Field Contact_Begin_CallBack:Int(material:Byte Ptr,body0:Byte Ptr, body1:Byte Ptr)
	Field Contact_Process_CallBack:Int(material:Byte Ptr,body0:Byte Ptr, body1:Byte Ptr,contact:Byte Ptr)
	Field Contact_End_Callback(material:Byte Ptr)
	
	Field Materials:TMap = CreateMap()
	Field Standard_Material:Int 
		
	
	
	Function init:TPhysic()
		'?win32
		'StartNewton()
		'?
		Local P:TPhysic = New TPhysic
		World = NewtonCreate(Null , Null)
		NewtonSetPlatformArchitecture (World, 0)
		P.Standard_Transform_Callback = TransformCallback
		P.Standard_ForceAndTorque_Callback = ForceCallBack
		P.Standard_Activation_Callback = ActivationCallback
		P.Contact_Begin_CallBack = Contact_Begin_CallBack
		P.Contact_Process_CallBack = Contact_Process_CallBack
		P.Contact_End_CallBack = Contact_End_CallBack
		P.Standard_Material = NewtonMaterialGetDefaultGroupID(World)
		MainBall_CallBack = Ball_Callback
		Return P
	End Function
	
	Method SetWorldSize(V1:TVector,V2:TVector)
		NewtonSetWorldSize(World,V1,V2)
	End Method
	
	Method SetPhysicModel(SolverModel:Int,FrictionModel:Int)
		NewtonSetSolverModel(TPhysic.World,SolverModel)
		NewtonSetFrictionModel(TPhysic.World,FrictionModel)
	End Method
	
	Method Update(UpTime:Float = - 1.0)
		If  Uptime < 0 Then
			NewtonUpdate(World , TGlobal.GetDelta() ) 
		Else
			NewtonUpdate(World , Uptime ) 
		EndIf
		TPhysic.ActiveBodies = PhysicObjects.Count()-TPhysic.UnActiveBodies
	End Method
	
	Method AddMaterial(Material:TPhysicMaterial)
		If Material <> Null
			MapInsert(Materials,Material.Name,Material)
		EndIf
	End Method
	
	Method BuildMaterialLibraries(BuildOption:Int = PHYS_MATERIAL_AVERAGE)
		Local KFriction:Float
		Local SFriction:Float
		Local Softness:Float
		Local Elasticity:Float
		For Local M1:TPhysicMaterial = EachIn Materials.Values()
			For Local M2:TPhysicMaterial = EachIn Materials.Values()
				Select BuildOption
					Case PHYS_MATERIAL_AVERAGE
						SFriction = (M1.DefaultFriction[0] + M2.DefaultFriction[0]) / 2
						KFriction = (M1.DefaultFriction[1] + M2.DefaultFriction[1]) / 2
						Softness = (M1.DefaultSoftness + M2.DefaultSoftness) / 2
						Elasticity = (M1.DefaultElasticity + M2.DefaultElasticity) / 2
						
						NewtonMaterialSetDefaultFriction(TPhysic.World,M1.GroupID,M2.GroupID,SFriction,KFriction)
						NewtonMaterialSetDefaultSoftness(TPhysic.World,M1.GroupID,M2.GroupID,Softness)
						NewtonMaterialSetDefaultElasticity(TPhysic.World,M1.GroupID,M2.GroupID,Elasticity)
				End Select
				
				NewtonMaterialSetCollisionCallback(TPhysic.World,M1.GroupID,M2.GroupID,Null,Contact_Begin_CallBack,Contact_Process_CallBack,Contact_End_CallBack)
			Next
		Next
		
		For Local M:String = EachIn MapKeys(Materials)
			Print "Material : " + String(M)
		Next
	End Method
	
	Method SetMaterialCollision(M1:Object,M2:Object,state:Int = 1)
		If TPhysicMaterial(M1)<>Null And TPhysicMaterial(M2) <> Null Then
			NewtonMaterialSetDefaultCollidable(TPhysic.World,TPhysicMaterial(M1).GroupID,TPhysicMaterial(M2).GroupID,state)
		Else
			Local MT1:TPhysicMaterial = TPhysicMaterial(MapValueForKey(Materials,String(M1)))
			Local MT2:TPhysicMaterial = TPhysicMaterial(MapValueForKey(Materials,String(M2)))
			
			If MT1 <> Null And MT2 <> Null Then 
				NewtonMaterialSetDefaultCollidable(TPhysic.World,MT1.GroupID,MT2.GroupID,state)
			EndIf
		EndIf
	End Method

	
	Method AddObject(NO:TNewtonObject)
		NewtonBodySetTransformCallback(NO.Node,Standard_Transform_Callback)
		NewtonBodySetForceAndTorqueCallback(NO.Node,Standard_ForceAndTorque_Callback)
		?Debug
		NewtonBodySetAutoActiveCallback(NO.Node,Standard_Activation_Callback)
		?
		PhysicObjects.Addlast(NO)

	End Method
	
	Method GetNode:Byte Ptr(mesh:TEntity)
		For Local T:TNewtonObject = EachIn PhysicObjects
			If T.Mesh = mesh Then Return T.node
		Next
		Return Null
	End Method
	
	Method GetPhysicTime:Float()
		Return NewtonGetTimeStep(World)
	End Method
	
	Method GetActiveBodyCount:Int()
		Return TPhysic.ActiveBodies
	End Method
	
	Method GetUnActiveBodyCount:Int()
		Return TPhysic.UnActiveBodies
	End Method
	
	Method ApplyImpulse(mesh:TEntity,impactX:Float,ImpactY:Float,ImpactZ:Float,ForceX:Float,ForceY:Float,ForceZ:Float)
		NewtonAddBodyImpulse(GetNode(mesh),[ForceX,ForceY,ForceZ],[impactX,impactY,impactZ])
	End Method
	
	Method SetDefaultElasticity(Value:Float)
		NewtonMaterialSetDefaultElasticity(TPhysic.World,Standard_Material,Standard_Material,Value)
	End Method
	
	Method SetDefaultFriction(staticFriction:Float,kineticfriction:Float)
		NewtonMaterialSetDefaultFriction(TPhysic.World,Standard_Material,Standard_Material,staticFriction,kineticFriction)
	End Method
	
	Method SetDefaultSoftiness(Value:Float)
		NewtonMaterialSetDefaultSoftness(TPhysic.World,Standard_Material,Standard_Material,Value)
	End Method
	
	Method SetBodyMaterial(NObject:TNewtonObject,MAterial:Object)
		'Print "Material : " + TPhysicMaterial(Material).Name
		If TPhysicMaterial(Material)<>Null 
			Print TPhysicMaterial(Material).Name + "applied"
			NewtonBodySetMaterialGroupID(NObject.node,TPhysicMaterial(Material).GroupID)
			NObject.Material = TPhysicMaterial(Material)
		Else
			Local MT1:TPhysicMaterial = TPhysicMaterial(MapValueForKey(Materials,String(Material)))
			If MT1 <> Null
				Print mt1.Name + "applied" 
				 NewtonBodySetMaterialGroupID(NObject.node,Mt1.GroupID)
				 NObject.Material = MT1
			EndIf
		EndIf
	
	End Method
	
	Method SetCollisionMode(Material1:Object,Material2:Object,Mode:Int = PHYS_NORMAL_COLLISION)
		Local Mat1:TPhysicMaterial
		Local Mat2:TPhysicMaterial
		If TPhysicMaterial(Material1)<>Null 
			Mat1 = TPhysicMaterial(Material1)
		Else
			Local MT1:TPhysicMaterial = TPhysicMaterial(MapValueForKey(Materials,String(Material1)))
			If MT1 <> Null
				Mat1 = MT1
			EndIf
		EndIf
		If TPhysicMaterial(Material2)<>Null 
			Mat1 = TPhysicMaterial(Material2)
		Else
			Local MT1:TPhysicMaterial = TPhysicMaterial(MapValueForKey(Materials,String(Material2)))
			If MT1 <> Null
				Mat2 = MT1
			EndIf
		EndIf
		
		If Mat1 = Null Or Mat2 = Null Then Return
		
		NewtonMaterialSetContinuousCollisionMode(TPhysic.World,Mat1.GroupID,Mat2.GroupID,Mode)
	End Method
	
	Method DestroyBody(mesh:TMesh)
		Local NO:Byte Ptr = GetNode(mesh)
		If NO <> Null Then
			NewtonDestroyBody(TPhysic.World,NO)
			'PhysicObjects.Remove(NO)
		EndIf
	End Method
	
		
End Type

Type TConstrait
	Field Constrait:Byte Ptr
	
	Method SetCollisionState(state:Int = 0)
		NewtonJointSetCollisionState(Constrait,state)
	End Method
	
	Method SetStiffness(stiffiness:Float)
		Print "Stiff: " + Int(Constrait)
		NewtonJointSetStiffness(Constrait,stiffiness)
	End Method
	
	Method GetStiffiness:Float()
		Return NewtonJointGetStiffness(Constrait)
	End Method
	
	Method Destroy()
		NewtonDestroyJoint(TPhysic.World,Constrait)
	End Method
	
End Type

Type TBallConstrait Extends TConstrait
	Function Create:TBallConstrait(WorldPosition:TVector,body0:TNewtonObject,body1:TNewtonObject)
		Local Ball:TBallConstrait = New TBallConstrait
		If body1 = Null Then
			Ball.Constrait = NewtonConstraintCreateBall(Tphysic.World,WorldPosition,body0.node,Null)
		Else
			Ball.Constrait = NewtonConstraintCreateBall(Tphysic.World,WorldPosition,body0.node,body1.node)
		EndIf
		
		NewtonJointSetUserData(Ball.Constrait,Byte Ptr(bbHandleFromObject(Ball)))
		NewtonBallSetUserCallback(Ball.Constrait,TPhysic.MainBall_CallBack)
		Return Ball
	End Function
	
	Method SetConeLimits(Vector:TVector,maxConeAngle:Float,MaxTwistAngle:Float)
		NewtonBallSetConeLimits(Constrait,Vector,maxConeAngle,MaxTwistAngle)
	End Method
	
	Method GetForce:TVector()
		Local V:TVector = New TVector
		NewtonBallGetJointForce(Constrait,V)
		Return V
	End Method
End Type
 

Type TContactInfo
	Field ContactPoints:Byte Ptr
	Field body1:TNewtonObject
	Field body2:TNewtonObject
	Field Material:Byte Ptr
	Field ContactNormalSpeed:Float
	Field ContactTangentSpeed1:Float
	Field ContactTangentSpeed2:Float
	Field ContactForce:TVector = New TVector
	Field ContactPosition:TVector = New TVector
	Field ContactNormalPosition:TVector = New TVector
	Field TimeStep:Float
	Field ContactTangentDirection1:TVector = New TVector
	Field ContactTangentDirection2:TVector = New TVector
	
	
	
	Method Info()
		DebugLog "Materials      : " + body1.Material.Name + " : " + body2.Material.Name
		DebugLog "NormalSpeed    : " + ContactNormalSpeed
		DebugLog "TangentSpeed 1 : " + ContactTangentSpeed1
		DebugLog "TangentSpeed 2 : " + ContactTangentSpeed2
		DebugLog "Force          : " + ContactForce.x + "," + ContactForce.y + "," + ContactForce.z
		DebugLog "Position       : " + ContactPosition.x + "," + ContactPosition.y + "," + ContactPosition.z
		DebugLog "NormalPosition : " + ContactNormalPosition.x + "," + ContactNormalPosition.y + "," + ContactNormalPosition.z
		DebugLog "TimeStep       : " + TimeStep
		DebugLog "-------------------------------------------------------"
	End Method
	
	Method OverrideElasticity(value:Float)
		NewtonMaterialSetContactElasticity(Material , Value)
	End Method
	
	Method OverrideFrictionState(state:Int , id:Int = 0)
		NewtonMaterialSetContactFrictionState(Material , State , id)
	End Method
	
	Method OverrideSoftness(Value:Float)
		NewtonMaterialSetContactSoftness(Material,Max(0.0,Value))
	End Method
	
	Method OverrideStaticFriction(Value:Float,id:Int=0)
		NewtonMaterialSetContactStaticFrictionCoef(Material,Value,id)
	End Method
	
	Method OverrideKineticFriction(Value:Float,id:Int = 0)
		NewtonMaterialSetContactKineticFrictionCoef(Material,Value,id)
	End Method
	
	Method OverrideNormalAcceleration(value:Float)
		NewtonMaterialSetContactNormalAcceleration(Material,value)
	End Method
	
	Method OverrideNormalDirection(Value:TVector)
		NewtonMaterialSetContactNormalDirection(Material,Value)
	End Method
	
	Method OverrideTangentAcceleration(Value:Float,id:Int = 0)
		NewtonMaterialSetContactTangentAcceleration(Material,Value,id)
	End Method
			
End Type

Const PHYS_SPHERE_HULL:Int =1
Const PHYS_BOX_HULL:Int = 2
Const PHYS_CONE_HULL:Int = 3
Const PHYS_CYLINDER_HULL:Int = 4
Const PHYS_MESHCONVEX_HULL:Int = 5
Const PHYS_MESHCOMPLEX_HULL:Int = 6
Const PHYS_MESHCOMPLEXUNOPTOMIZED_HULL:Int = 7


Const PHYS_MATERIAL_MIN:Int = 0
Const PHYS_MATERIAL_MAX:Int = 1
Const PHYS_MATERIAL_ORDER:Int = 2
Const PHYS_MATERIAL_AVERAGE:Int = 3
Const PHYS_MATERIAL_AVERAGE_WITH_REFERENCE:Int = 4

Const PHYS_NORMAL_COLLISION:Int = 0
Const PHYS_CONTINUES_COLLISION:Int = 1


Type TNewtonObject
	Field Mesh:TMesh
	
	Field Mat:Float[16]
	Field rotX:Float,rotY:Float,rotZ:Float
	Field posX:Float,posY:Float,PosZ:Float
	
	Field LCX:Float,LCY:Float,LCZ:Float
	
	Field Body:Byte Ptr
	Field Node:Byte Ptr
	
	Field Velocity:Float[3]
	Field Omega:Float[3]
	Field Active:Byte = False
	Field Material:TPhysicMaterial
	Field Volume:Float
	Field AABB:TVector[2]
	Field UpdateForce:Float[3]
	Field Extra:Object
	Field UpPos:Byte = False
	
	Field UserForceCallback(Body:TNewtonObject)
	Field tp:Int

	
	Function Create:TNewtonObject(Mesh:TMesh,T:Int = 0)
		Local NO:TNewtonObject = New TNewtonObject
			Local nx:Float
			Local ny:Float
			Local nz:Float
			nx = Mesh.sx * Mesh.msx
			ny = Mesh.sy * Mesh.msy
			nz = Mesh.sz * Mesh.msz
			NO.tp=T

		Select T		
			Case 1
				NO.Body =  NewtonCreateSphere(TPhysic.World,nx,ny,nz,Null)
			Case 2
				NO.Body = NewtonCreateBox(TPhysic.World,-nx*2,ny*2,-nz*2,Null)
			Case 5
				Local surf:TSurface = Mesh.GetSurface(1)
				If Surf <> Null Then
					'Print "Creating Convex Hull"
					NO.Body = NewtonCreateConvexHull(TPhysic.World,surf.no_verts,surf.vert_coords,12,Null)
				EndIf
			Case 3
				NO.Body = NewtonCreateCone(TPhysic.World,nx,ny*2,Null)
			Case 4
				NO.Body = NewtonCreateCylinder(TPhysic.World,nx,ny*2,Null)
			Case 6
				NO.BODY = NewtonCreateTreeCollision(TPhysic.World,Null) 
				NewtonTreeCollisionBeginBuild(NO.Body)
				Local Vector:Float[9]
				For	Local Surf:TSurface = EachIn Mesh.surf_List
						For Local I:Int = 0 To surf.no_tris-1
							Local v0=surf.TriangleVertex(i,0)
							Local v1=surf.TriangleVertex(i,1)
							Local v2=surf.TriangleVertex(i,2)
							
							Vector[0] = surf.VertexX(v0)
							Vector[1] = surf.VertexY(v0)
							Vector[2] = surf.VertexZ(v0)
							
							Vector[3] = surf.VertexX(v1)
							Vector[4] = surf.VertexY(v1)
							Vector[5] = surf.VertexZ(v1)
							
							Vector[6] = surf.VertexX(v2)
							Vector[7] = surf.VertexY(v2)
							Vector[8] = surf.VertexZ(v2)
							
							NewtonTreeCollisionAddFace(NO.Body,3,Vector,12,0)
						Next
				Next		
				NewtonTreeCollisionEndBuild(NO.Body , 1)
				
			Case 7
				NO.BODY = NewtonCreateTreeCollision(TPhysic.World,Null) 
				NewtonTreeCollisionBeginBuild(NO.Body)
				Local Vector:Float[9]
				For	Local Surf:TSurface = EachIn Mesh.surf_List
						For Local I:Int = 0 To surf.no_tris-1
							Local v0=surf.TriangleVertex(i,0)
							Local v1=surf.TriangleVertex(i,1)
							Local v2=surf.TriangleVertex(i,2)
							
							Vector[0] = surf.VertexX(v0)
							Vector[1] = surf.VertexY(v0)
							Vector[2] = surf.VertexZ(v0)
							
							Vector[3] = surf.VertexX(v1)
							Vector[4] = surf.VertexY(v1)
							Vector[5] = surf.VertexZ(v1)
							
							Vector[6] = surf.VertexX(v2)
							Vector[7] = surf.VertexY(v2)
							Vector[8] = surf.VertexZ(v2)
							
							NewtonTreeCollisionAddFace(NO.Body,3,Vector,12,0)
						Next
				Next		
				NewtonTreeCollisionEndBuild(NO.Body,0)

							
		End Select
		
		NO.PosX = EntityX(mesh)
		NO.PosY = EntityY(mesh)
		NO.PosZ = EntityZ(mesh)
		NO.Mesh = mesh

		
			
		
		NO.Node =  newtonCreateBody(TPhysic.World , NO.Body)
		
		'Max3DGetMatrix(NO , Varptr NO.Mat[0])
						
		Local tempmat:Float[16]
		Local mmp:Float Ptr=Mesh.Mat.grid
		tempmat[0]=mmp[0]
		tempmat[1]=mmp[1]
		tempmat[2]=-mmp[2]
		tempmat[4]=mmp[4]
		tempmat[5]=mmp[5]
		tempmat[6]=-mmp[6]
		tempmat[8]=mmp[8]
		tempmat[9]=mmp[9]
		tempmat[10]=-mmp[10]
		tempmat[12]=mmp[12]'posx
		tempmat[13]=mmp[13]'posy
		tempmat[14]=-mmp[14]'-posz
		'Mesh.Mat.Scale(-mesh.sx,-mesh.sy,-mesh.sz)
		
				
	
		newtonBodySetMatrix(NO.Node , tempmat)
		newtonBodySetUserData(NO.node ,Byte Ptr bbhandlefromobject(NO))
		
		NO.Volume = NewtonConvexCollisionCalculateVolume(No.Body)
		NO.AABB[0] = New TVector
		NO.AABB[1] = New TVector
		NewtonBodyGetAABB(NO.Node,No.AABB[0],NO.AABB[1])
		
		No.UpdateForce = [0.0 , 9.81 , 0.0]
				
		Mesh.PhysicObject = NO
						
		Return NO
	End Function
		
	Method OmegaToString:String()
		Return "Omega : " + Omega[0] + " : " + (Omega[1]* 180.0 / Pi) + " : " + Omega[2]
	End Method
	
	Method VelocityToString:String()
		Return "Velocity : " + Velocity[0] + " : " + Velocity[1] + " : " + Velocity[2]
	End Method
	
	Method GetVelocity:TVector()
		Local V:TVector = New TVector
		V.X = Velocity[0]
		V.Y = Velocity[1]
		V.Z = Velocity[2]
		Return V
	End Method
		
	Method GetPosition:TVector()
		Local V:TVector = New TVector
		V.X = PosX
		V.Y = PosY
		V.Z = PosZ
		Return V
	End Method
	
	Method SetRotation(Pitch# , Roll# , Yaw#)
		RotX = Pitch 
		RotY = Roll
		RotZ = Yaw
		Local Euler:Float[3]
		Euler[0] = rotX * Pi / 180.0
		Euler[1] = rotY * Pi / 180.0
		Euler[2] = rotZ * Pi / 180.0
		NewtonSetEulerAngle(Varptr Euler[0] , Varptr Mat[0])
		
		Max3DSetMatrix(Self,Mat)

	End Method
		
	
	Method Update()
		If UpPos = True Then
			UpdatePos()
			Return
		EndIf
		newtonBodyGetMatrix(Node , Mat)
		NewtonBodyGetVelocity(Node,Velocity)
		NewtonBodyGetOmega(Node,Omega)
		Max3DSetMatrix(Self,Mat)
		Local mmp:Float Ptr=Mesh.Mat.grid
		mmp[0]=mat[0]
		mmp[1]=mat[1]
		mmp[2]=-mat[2]
		mmp[4]=mat[4]
		mmp[5]=mat[5]
		mmp[6]=-mat[6]
		mmp[8]=mat[8]
		mmp[9]=mat[9]
		mmp[10]=-mat[10]
		mmp[12]=mat[12]'posx
		mmp[13]=mat[13]'posy
		mmp[14] = - mat[14]'-posz
		
		posx = mat[12]
		posy = mat[13]
		posz = - mat[14]
		
		Mesh.Mat.Scale(-mesh.sx,-mesh.sy,-mesh.sz)
	End Method
	
	Method UpdatePos()
		newtonBodyGetMatrix(Node , Mat)
		NewtonBodyGetVelocity(Node,Velocity)
		NewtonBodyGetOmega(Node,Omega)
		Max3DSetMatrix(Self,Mat)
		Local mmp:Float Ptr=Mesh.Mat.grid
		mmp[12]=mat[12]'posx
		mmp[13]=mat[13]'posy
		mmp[14] = - mat[14]'-posz
		
		posx = mat[12]
		posy = mat[13]
		posz = - mat[14]
		
		Mesh.Mat.Scale(-mesh.sx,-mesh.sy,-mesh.sz)
	End Method
		
		
	Method SetMass(Mass:Float)
		Local Massp:Float[3]
		Local Inertia:Float[3]
		newtonBodySetMassMatrix(Node , Mass , inertia[0] , inertia[1], inertia[2])
		NewtonConvexCollisionCalculateInertialMatrix(body,Inertia,Massp)
		NewtonBodySetCentreOfMass(Node,Massp)
		'Print "Inertia: " + inertia[0] +","+inertia[1]+","+inertia[2]
		'Print "Mass: " + Massp[0] +","+Massp[1]+","+Massp[2]
		
		newtonBodySetMassMatrix(Node , Mass , inertia[0] , inertia[1], inertia[2])
	End Method
	
	Method SetCollisionMode(Mode:Int = PHYS_NORMAL_COLLISION)
		NewtonBodySetContinuousCollisionMode(Node,Mode)
	End Method
	
	Method SetAutoSleep(State:Int = 1)
		NewtonBodySetAutoFreeze(node , State)
	End Method
	
	Method SetSleepTreshold(speedmag:Float,omegamag:Float,frames:Int)
		NewtonBodySetFreezetreshold(node , speedmag , omegamag , frames)
	End Method
	
	Method SetUserForceCallback(Callback(NewtonObject:TNewtonObject))
		UserForceCallBack = CallBack
	End Method
	
	Method GetRotation:String()
		Local Euler:Float[3]
		NewtonGetEulerAngle(Varptr Mat[0] , Varptr Euler[0])
		rotX  = Euler[0] * 180.0 / Pi
		rotY  = Euler[1] * 180.0 / Pi
		rotZ = Euler[2] * 180.0 / Pi
		Return "Rotation : " + rotX   + " : " + rotY + " : " + rotZ

	End Method
	
	
	
End Type

Type TPhysicMaterial
	Field Name:String = ""
	Field GroupID:Int
	Field UseContactCallback:Byte = False
	
	Field DefaultFriction:Float[2]
	Field DefaultSoftness:Float
	Field DefaultElasticity:Float
	
	Field StaticFriction:Float
	Field KineticFriction:Float
	Field Softness:Float
	Field Elasticity:Float
	Field FrictionState:Int
	Field TangantACC:Float
	Field TangantDirs:Float
	Field NormalAcc:Float
	Field NormalDir:Float
	
	Function Create:TPhysicMaterial(Name:String)
		Local Mat:TPhysicMaterial = New TPhysicMaterial
		Mat.Name = Name
		Mat.GroupID = NewtonMaterialCreateGroupID(TPhysic.World)
		Return Mat
	End Function
	
	Method SetFriction(staticFriction:Float,KineticFriction:Float)
		DefaultFriction = [staticFriction,KineticFriction]
	End Method
	
	Method SetSoftness(Softness:Float)
		DefaultSoftness = Softness
	End Method
	
	Method SetElasticity(Elasticity:Float)
		DefaultElasticity = Elasticity
	End Method
End Type
	

Function Max3DGetMatrix(Node:TNewtonObject , NewtonMat:Float Ptr)
	Local Euler:Float[3]
	Euler[0] = Node.rotX * Pi / 180.0
	Euler[1] = Node.rotY * Pi / 180.0
	Euler[2] = Node.rotZ * Pi / 180.0
	NewtonSetEulerAngle(Varptr Euler[0] , Varptr newtonMat[0])
	Newtonmat[12] = Node.PosX
	newtonMat[13] = Node.PosY
	NewtonMat[14] = Node.PosZ	
End Function

Function Max3DSetMatrix(Node:TNewtonObject , NewtonMat:Float Ptr)
	Local Euler:Float[3]
	NewtonGetEulerAngle(Varptr NewtonMat[0] , Varptr Euler[0])
	Node.Posx = NewtonMat[12]
	Node.Posy = NewtonMat[13]
	Node.Posz = NewtonMat[14]
	Node.rotX  = Euler[0] * 180.0 / Pi
	Node.rotY  = Euler[1] * 180.0 / Pi
	Node.rotZ  = Euler[2] * 180.0 / Pi
End Function


Function ForceCallback(body:Byte Ptr)
	
	Local T:Byte Ptr = newtonBodyGetUserData(body)
	Local T2:TNewtonObject = TNewtonObject(bbhandletoobject(Int(T) ) )
	
	If T2.UserForceCallBack <> Null Then
		T2.UserForceCallBack(T2)
	EndIf
	
	Local Ixx:Float[1]
	Local Iyy:Float[1]
	Local Izz:Float[1]
	Local mass:Float[1]

	NewtonBodyGetMassMatrix (body, mass, Ixx, Iyy, Izz);
	Local force:Float[] = [T2.UpdateForce[0], -mass[0]* T2.UpdateForce[1], T2.UpdateForce[2]]
	NewtonBodySetForce (body, force)
End Function

Function TransformCallback(body:Byte Ptr)
	Local T:Byte Ptr = newtonBodyGetUserData(body)
	Local T2:TNewtonObject = TNewtonObject(bbhandletoobject(Int(T)))
	T2.Update()
End Function

Function ActivationCallback(body:Byte Ptr)
	Local T:Byte Ptr = newtonBodyGetUserData(body)
	Local T2:TNewtonObject = TNewtonObject(bbhandletoobject(Int(T)))
	
	
	If T2.Active = True Then
		T2.Active = False
		TPhysic.UnActiveBodies:+1
	Else
		T2.Active = True
		TPhysic.UnActiveBodies:-1
	EndIf
	
	If TPhysic.UnActiveBodies < 0 Then TPhysic.UnActiveBodies = 0
	
End Function

Function Contact_Begin_CallBack:Int(material:Byte Ptr,body0:Byte Ptr, body1:Byte Ptr)
	TPhysic.CurrentContact = New TContactInfo
	Local T:Byte Ptr = newtonBodyGetUserData(body0)
	Local TT:TNewtonObject = TNewtonObject(bbhandletoobject(Int(T)))
	
	Local T1:Byte Ptr = newtonBodyGetUserData(body1)
	Local TT1:TNewtonObject = TNewtonObject(bbhandletoobject(Int(T1)))
	

	TPhysic.CurrentContact.Body1 = TT
	TPhysic.CurrentContact.Body2 = TT1
	TPhysic.CurrentContact.Material = material
	Return 1
End Function

Function Contact_Process_CallBack:Int(material:Byte Ptr,body0:Byte Ptr, body1:Byte Ptr,contact:Byte Ptr)
	TPhysic.CurrentContact.Contactpoints = contact
	?win32
	TPhysic.CurrentContact.ContactNormalSpeed = NewtonMaterialGetContactNormalSpeed(Varptr material,Varptr contact)
	?	
	NewtonMaterialGetContactPositionAndNormal(material,TPhysic.CurrentContact.ContactPosition,TPhysic.CurrentContact.ContactNormalPosition)
	NewtonMaterialGetContactForce(material,TPhysic.CurrentContact.ContactForce)
	NewtonMaterialGetContactTangentDirections(material,TPhysic.CurrentContact.ContactTangentDirection1,TPhysic.CurrentContact.ContactTangentDirection2)
	TPhysic.CurrentContact.TimeStep = NewtonMaterialGetCurrentTimeStep(material)
	?win32
	TPhysic.CurrentContact.ContactTangentSpeed1 = NewtonMaterialGetContactTangentSpeed(Varptr material,Varptr contact,0)
	TPhysic.CurrentContact.ContactTangentSpeed1 = NewtonMaterialGetContactTangentSpeed(Varptr material,Varptr contact,1)
	?
	If TPhysic.ContactProcess
		TPhysic.ContactProcess(TPhysic.CurrentContact)
	EndIf
	Return 1
End Function

Function Contact_End_CallBack(material:Byte Ptr)
	If TPhysic.ContactEnd Then
		TPhysic.ContactEnd(TPhysic.CurrentContact)
	EndIf
End Function

Function Ball_CallBack(ball:Byte Ptr)
	Local h:Byte Ptr = NewtonJointGetUserData(Ball)
	Local B:TBallConstrait = TBallConstrait(bbHandletoObject(Int(h)))
	
	If TPhysic.BallUserCallBack Then
		TPhysic.BallUserCallBack(B)
	EndIf
End Function


Function RenderDebugCollision(body:Byte Ptr,vertexCount:Int,faceVertec:Float Ptr,id:Byte Ptr)
	Local i:Int
	Local p0:TVector
	Local p1:TVector
	
	'glDisable(GL_LIGHTING)
	'glDisable(GL_TEXTURE_2D)
	
	'glMaterialfv(GL_FRONT,GL_DIFFUSE,[1.0,0.0,0.0,1.0])
	'glDrawElements(GL_LINES ,vertexCount/2, GL_UNSIGNED_INT , faceVertec)

	'glBegin(GL_LINES)
	'glColor3f(1.0, 1.0, 0.0)
	
	
	i = vertexcount - 1
	p0=  New TVector
	p0.x = faceVertec[i * 3 + 0]
	p0.y = faceVertec[i * 3 + 1]
	p0.z = faceVertec[i * 3 + 2]
	For i = 0 To vertexcount-1
		p1 = New TVector
		p1.x = faceVertec[i * 3 + 0]
		p1.y = faceVertec[i * 3 + 1]
		p1.z = faceVertec[i * 3 + 2]

		glVertex3f (p0.x, p0.y, -p0.z)
		glVertex3f (p1.x, p1.y, -p1.z)
 		p0 = p1
	Next
	'glEND()
	
End Function

Function RenderBodyCollision(body:Byte Ptr)
	NewtonBodyForEachPolygonDo (body, RenderDebugCollision)
End Function
	
Extern
Function bbHandleToObject:Object( handle )
Function bbHandleFromObject:Int( obj:Object )
End Extern

' Leadwerks function
Function EulerToQuat:TQuaternion(pitch#,yaw#,roll#)
	Local cr#=Cos(-roll#/2.0)
	Local cp#=Cos(pitch#/2.0)
	Local cy#=Cos(yaw#/2.0)
	Local sr#=Sin(-roll#/2.0)
	Local sp#=Sin(pitch#/2.0)
	Local sy#=Sin(yaw#/2.0)
	Local cpcy#=cp#*cy#
	Local spsy#=sp#*sy#
	Local spcy#=sp#*cy#
	Local cpsy#=cp#*sy#
	Local q:TQuaternion=New TQuaternion
	q.w#=cr#*cpcy#+sr#*spsy#
	q.x#=sr#*cpcy#-cr#*spsy#
	q.y#=cr#*spcy#+sr#*cpsy#
	q.z#=cr#*cpsy#-sr#*spcy#
	Return q
End Function

Function MultiplyQuats:TQuaternion(q1:TQuaternion,q2:TQuaternion)

	Local q:TQuaternion=New TQuaternion
	
	q.w = q1.w*q2.w - q1.x*q2.x - q1.y*q2.y - q1.z*q2.z
	q.x = q1.w*q2.x + q1.x*q2.w + q1.y*q2.z - q1.z*q2.y
	q.y = q1.w*q2.y + q1.y*q2.w + q1.z*q2.x - q1.x*q2.z
	q.z = q1.w*q2.z + q1.z*q2.w + q1.x*q2.y - q1.y*q2.x

	Return q

End Function

Function NormalizeQuat:TQuaternion(q:TQuaternion)

	Local uv#=Sqr(q.w*q.w+q.x*q.x+q.y*q.y+q.z*q.z)

	q.w=q.w/uv
	q.x=q.x/uv
	q.y=q.y/uv
	q.z=q.z/uv

	Return q

End Function

Type TCameraController
	Field Cam:TCamera
	Field Bounding:TMesh
	Field NewtonObject:TNewtonObject
	Field Upvector:Float[] = [0.0 , 1.0 , 0.0]
	Field Dummies:TPivot[3] 'Left = 0,Front = 1,Right = 2
	Field System:TPhysic
	
	Function Create:TCameraController(Cam:TCamera,System:TPhysic,RadiusX:Int = 5,RadiusY:Int = 10,RadiusZ:Int = 5)
		Local CC:TCameraController = New TCameraController
		CC.Cam = Cam
		
		'temporaly saving orientation of the cam
		Local X:Float = EntityX(Cam)
		Local Y:Float = EntityY(Cam)
		Local Z:Float = EntityZ(Cam)
		Local Pitch:Float = EntityPitch(Cam)
		Local Roll:Float = EntityRoll(Cam)
		Local Yaw:Float = EntityYaw(Cam)
		
		'Setting all cam coords to 0 (for propper dummy align)
		
		PositionEntity(Cam , 0 , 0 , 0) 
		RotateEntity(Cam , 0 , 0 , 0)
		
		'Creating Pivots
		
		CC.Dummies[0] = CreatePivot(Cam)
		CC.Dummies[1] = CreatePivot(Cam)
		CC.Dummies[2] = CreatePivot(Cam)
		
		TranslateEntity(CC.Dummies[0] , 5 , 0 , 0)
		TranslateEntity(CC.Dummies[1] , 0 , 0 , 5)
		TranslateEntity(CC.Dummies[2] , -5 , 0 , 0)
		
		'Reseting Cam
		
		PositionEntity(Cam , X , Y , Z)
		RotateEntity(Cam , Pitch , Yaw , Roll)
		
		CC.Bounding = CreateSphere(8) 
		ScaleEntity(CC.Bounding , RadiusX , RadiusY , RadiusZ)
		PositionEntity(CC.Bounding, X , Y , Z)
		RotateEntity(CC.Bounding , Pitch , Yaw , Roll)
		HideEntity(CC.Bounding)

		
		'EntityParent(Cam,CC.Bounding)
		
		CC.NewtonObject = TNewtonObject.Create(CC.Bounding , PHYS_SPHERE_HULL)		
		CC.NewtonObject.SetMass(1.0) ' Set it solid
		CC.System = system
		CC.NewtonObject.extra = cc
		CC.NewtonObject.SetUserForceCallback(Control_Callback)
		System.AddObject(CC.NewtonObject) 
		NewtonConstraintCreateUpVector(TPhysic.World,[0.0,1.0,0.0],CC.NewtonObject.Node)

		
		
		Return CC
		
	End Function
	
	Method Move(Speed:Float)
		Local V1:TVector = TVector.Create(EntityX(Dummies[1],True),EntityY(Dummies[1],True),EntityZ(Dummies[1],True))
		Local V2:TVector = TVector.Create(EntityX(Cam) , EntityY(Cam) , EntityZ(Cam) )
		
		Local V3:TVector = V1.Subtract(V2).Multiply(Speed/20.0)
					
		System.ApplyImpulse(Bounding,EntityX(Cam),EntityY(cam),EntityZ(cam),V3.X,V3.Y,V3.Z)
	End Method
	
	Method MoveVector(V:TVector)
		
		'V = Cam.mat.MulV(V)
		NewtonObject.SetRotation(EntityPitch(Cam) , EntityRoll(Cam) , EntityYaw(Cam) )
		NewtonObject.Update()

		System.ApplyImpulse(Bounding,EntityX(Cam),EntityY(cam),EntityZ(cam),V.Y,V.X,V.Z)
	End Method
		
	
End Type

Function Control_Callback(body:TNewtonObject)
	Local CC:TCameraController = TCameraController(body.extra)
	If CC = Null Then Return
	PositionEntity(CC.Cam,body.posx,body.posy,-body.posz)
End Function	
		 
	
	

