Browse Source

Added mojo3d physics files.

Mark Sibly 7 years ago
parent
commit
4791faad66

+ 550 - 0
modules/mojo3d/components/collider.monkey2

@@ -0,0 +1,550 @@
+
+Namespace mojo3d
+
+Class Entity Extension
+	
+	Property Collider:Collider()
+		
+		Return GetComponent<Collider>()
+	End
+	
+End
+
+Class Collider Extends Component
+	
+	Const Type:=New ComponentType( "Collider",-1,ComponentTypeFlags.Singleton )
+	
+	Method New( entity:Entity )
+		
+		Super.New( entity,Type )
+	End
+	
+	Property Margin:Float()
+		
+		Return btShape.getMargin()
+	
+	Setter( margin:Float )
+		
+		btShape.setMargin( margin )
+	End
+
+	Method CalculateLocalInertia:Vec3f( mass:Float )
+		
+		Return btShape.calculateLocalInertia( mass )
+	End
+
+	Property btShape:btCollisionShape()
+		
+		If Not _btshape _btshape=OnCreate()
+	
+		Return _btshape
+	End
+	
+	Property Seq:Int()
+		
+		Return _seq
+	End
+
+Protected
+
+	Method OnCreate:btCollisionShape() Abstract
+	
+	Method Invalidate()
+		
+		If Not _btshape Return
+		
+		_btshape.destroy()
+		_btshape=Null
+		
+		_gseq+=1
+		_seq=_gseq
+	End
+
+	function SetOrigin:btCollisionShape( shape:btCollisionShape,origin:Vec3f )
+		
+		If origin=Null Return shape
+		
+		Local tshape:=New btCompoundShape( False,1 )
+		
+		tshape.addChildShape( AffineMat4f.Translation( origin ),shape )
+		
+		Return tshape
+	End
+	
+	Private
+	
+	Global _gseq:Int
+
+	Field _btshape:btCollisionShape
+	
+	Field _seq:Int
+	
+End
+
+Class ConvexCollider Extends Collider
+	
+	Method New( Entity:Entity )
+		Super.New( Entity )
+	End
+	
+End
+
+Class BoxCollider Extends ConvexCollider
+	
+	Method New( Entity:Entity )
+		Super.New( Entity )
+		
+		Box=New Boxf( -1,1 )
+	End
+	
+	Property Box:Boxf()
+		
+		Return _box
+	
+	Setter( box:Boxf )
+		
+		_box=box
+		
+		Invalidate()
+	End
+	
+	Protected
+	
+	Method OnCopy:BoxCollider( entity:Entity ) Override
+		
+		Local collider:=New BoxCollider( entity )
+		
+		collider.Box=Box
+		
+		Return collider
+	End
+	
+	Method OnCreate:btCollisionShape() Override
+		
+		Local shape:=New btBoxShape( _box.Size/2 )
+		
+		Return SetOrigin( shape,_box.Center )
+	End
+	
+	Private
+	
+	Field _box:=New Boxf( -1,1 )
+End
+
+Class SphereCollider Extends ConvexCollider
+	
+	Method New( Entity:Entity )
+		Super.New( Entity )
+	End
+	
+	Property Radius:Float()
+		
+		Return _radius
+	
+	Setter( radius:Float )
+		
+		_radius=radius
+		
+		Invalidate()
+	End
+	
+	Property Origin:Vec3f()
+		
+		Return _origin
+		
+	Setter( origin:Vec3f )
+		
+		_origin=origin
+		
+		Invalidate()
+	End
+	
+	Protected
+	
+	Method OnCopy:SphereCollider( entity:Entity ) Override
+		
+		Local collider:=New SphereCollider( entity )
+		
+		collider.Radius=Radius
+		collider.Origin=Origin
+		
+		Return collider
+	End
+	
+	Method OnCreate:btCollisionShape() Override
+		
+		Local shape:=New btSphereShape( _radius )
+		
+		return SetOrigin( shape,_origin )
+	End
+	
+	Private
+	
+	Field _radius:Float=1
+	
+	Field _origin:Vec3f
+	
+End
+
+Class CylinderCollider Extends ConvexCollider
+	
+	Method New( entity:Entity )
+		Super.New( entity )
+	End
+	
+	Property Radius:Float()
+		
+		Return _radius
+		
+	Setter( radius:Float )
+		
+		_radius=radius
+		
+		Invalidate()
+	End
+	
+	Property Length:Float()
+		
+		Return _length
+		
+	Setter( length:Float )
+		
+		_length=length
+		
+		Invalidate()
+	End
+	
+	Property Axis:Axis()
+		
+		Return _axis
+		
+	Setter( axis:Axis )
+		
+		_axis=axis
+		
+		Invalidate()
+	End
+	
+	Property Origin:Vec3f()
+		
+		Return _origin
+	
+	Setter( origin:Vec3f )
+		
+		_origin=origin
+		
+		Invalidate()
+	End
+
+	Protected
+
+	Method OnCopy:CylinderCollider( entity:Entity ) Override
+		
+		Local collider:=New CylinderCollider( entity )
+		
+		collider.Radius=Radius
+		collider.Length=Length
+		collider.Axis=Axis
+		collider.Origin=Origin
+		
+		Return collider
+	End
+	
+	Method OnCreate:btCollisionShape() Override
+
+		Local shape:btCollisionShape
+		
+		Select _axis
+		case Axis.X
+			shape=New btCylinderShapeX( New btVector3( _length/2,_radius,_radius ) )
+		Case Axis.Y
+			shape=New btCylinderShape ( New btVector3( _radius,_length/2,_radius ) )
+		case Axis.Z
+			shape=New btCylinderShapeZ( New btVector3( _radius,_radius,_length/2 ) )
+		Default
+			RuntimeError( "Invalid Cylinder Axis" )
+		End
+		
+		Return SetOrigin( shape,_origin )
+	End
+	
+	Private
+	
+	Field _radius:Float=0.5
+	Field _length:Float=1.0
+	Field _axis:Axis=geom.Axis.Y
+	Field _origin:Vec3f
+
+End
+
+Class CapsuleCollider Extends ConvexCollider
+	
+	Method New( entity:Entity )
+		Super.New( entity )
+	End
+	
+	Property Radius:Float()
+		
+		Return _radius
+		
+	Setter( radius:Float )
+		
+		_radius=radius
+		
+		Invalidate()
+	End
+	
+	Property Length:Float()
+		
+		Return _length
+		
+	Setter( length:Float )
+		
+		_length=length
+		
+		Invalidate()
+	End
+	
+	Property Axis:Axis()
+		
+		Return _axis
+		
+	Setter( axis:Axis )
+		
+		_axis=axis
+		
+		Invalidate()
+	End
+	
+	Property Origin:Vec3f()
+		
+		Return _origin
+	
+	Setter( origin:Vec3f )
+		
+		_origin=origin
+		
+		Invalidate()
+	End
+
+	Protected
+	
+	Method OnCopy:CapsuleCollider( entity:Entity ) Override
+		
+		Local collider:=New CapsuleCollider( entity )
+		
+		collider.Radius=Radius
+		collider.Length=Length
+		collider.Axis=Axis
+		collider.Origin=Origin
+		
+		Return collider
+	End
+	
+	Method OnCreate:btCollisionShape() Override
+		
+		Local shape:btCollisionShape
+		
+		Select _axis
+		Case Axis.X
+			shape=New btCapsuleShapeX( _radius,_length )
+		Case Axis.Y
+			shape=New btCapsuleShape ( _radius,_length )
+		Case Axis.Z
+			shape=New btCapsuleShapeZ( _radius,_length )
+		Default
+			RuntimeError( "Invalid Capsule Axis" )
+		End
+		
+		Return SetOrigin( shape,_origin )
+	End
+	
+	Private
+	
+	Field _radius:Float=0.5
+	Field _length:Float=1.0
+	Field _axis:Axis=geom.Axis.Y
+	Field _origin:Vec3f
+
+End
+
+Class ConeCollider Extends ConvexCollider
+	
+	Method New( entity:Entity )
+		Super.New( entity )
+	End
+	
+	Property Radius:Float()
+		
+		Return _radius
+		
+	Setter( radius:Float )
+		
+		_radius=radius
+		
+		Invalidate()
+	End
+	
+	Property Length:Float()
+		
+		Return _length
+		
+	Setter( length:Float )
+		
+		_length=length
+		
+		Invalidate()
+	End
+	
+	Property Axis:Axis()
+		
+		Return _axis
+		
+	Setter( axis:Axis )
+		
+		_axis=axis
+		
+		Invalidate()
+	End
+	
+	Property Origin:Vec3f()
+		
+		Return _origin
+	
+	Setter( origin:Vec3f )
+		
+		_origin=origin
+		
+		Invalidate()
+	End
+
+	Protected
+	
+	Method OnCopy:ConeCollider( entity:Entity ) Override
+		
+		Local collider:=New ConeCollider( entity )
+		
+		collider.Radius=Radius
+		collider.Length=Length
+		collider.Axis=Axis
+		collider.Origin=Origin
+		
+		Return collider
+	End
+	
+	Method OnCreate:btCollisionShape() Override
+		
+		Local shape:btCollisionShape
+		
+		Select _axis
+		Case Axis.X
+			shape=New btConeShapeX( _radius,_length )
+		Case Axis.Y
+			shape=New btConeShape ( _radius,_length )
+		Case Axis.Z
+			shape=New btConeShapeZ( _radius,_length )
+		Default
+			RuntimeError( "Invalid Cone Axis" )
+		End
+
+		Return SetOrigin( shape,_origin )
+	End
+	
+	Private
+	
+	Field _radius:Float=0.5
+	Field _length:Float=1.0
+	Field _axis:Axis=geom.Axis.Y
+	Field _origin:Vec3f
+	
+End
+
+Class ConcaveCollider Extends Collider
+
+	Method New( entity:Entity )
+		Super.New( entity )
+	End
+	
+End
+
+Class MeshCollider Extends ConcaveCollider
+	
+	Method New( entity:Entity )
+		Super.New( entity )
+	End
+	
+	Property Mesh:Mesh()
+		
+		Return _mesh
+	
+	Setter( mesh:Mesh ) 
+		
+		_mesh=mesh
+		
+		Invalidate()
+	End
+
+	Protected
+	
+	Method OnCopy:MeshCollider( entity:Entity ) Override
+		
+		Local collider:=New MeshCollider( entity )
+		
+		collider.Mesh=Mesh
+		
+		Return collider
+	End
+	
+	Method OnCreate:btCollisionShape() Override
+		
+		Local vertices:=_mesh.GetVertices()
+		_vertices=New btVector3[vertices.Length]
+		
+		For Local i:=0 Until vertices.Length
+			_vertices[i].x=vertices[i].position.x
+			_vertices[i].y=vertices[i].position.y
+			_vertices[i].z=vertices[i].position.z
+		Next
+		
+		Local indices:=_mesh.GetAllIndices()
+		_indices=New Int[indices.Length]
+		For Local i:=0 Until indices.Length
+			_indices[i]=indices[i]
+		Next
+		
+		_btmesh=New btTriangleIndexVertexArray( _indices.Length/3,_indices.Data,12,_vertices.Length,Cast<btScalar Ptr>( _vertices.Data ),16 )
+		
+		Local shape:=New btBvhTriangleMeshShape( _btmesh,True,True )
+		
+		'CreateInternalEdgeInfo( shape )
+		
+		Return shape
+	End
+	
+	Private
+	
+	Field _mesh:Mesh
+	Field _vertices:btVector3[]
+	Field _indices:Int[]
+	Field _btmesh:btTriangleIndexVertexArray
+	
+End
+
+#rem
+Class TerrainCollider Extends ConcaveCollider
+
+	Method New( box:Boxf,data:Pixmap )
+	
+		Local shape:=New btHeightfieldTerrainShape( data.Width,data.Height,data.Data,1.0/255.0,0.0,1.0,1,PHY_UCHAR,False )
+		
+		shape.setUseDiamondSubdivision( True )
+		
+		_btshape=shape
+		
+		_btshape.setLocalScaling( New Vec3f( box.Width/data.Width,box.Height,box.Depth/data.Height ) )
+		
+		SetOrigin( box.Center )
+	End
+
+End
+#end

+ 329 - 0
modules/mojo3d/components/rigidbody.monkey2

@@ -0,0 +1,329 @@
+
+#rem
+
+Notes:
+
+* Have to remove/add bodies from world if collision shape changes. http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=5194
+
+* default btCollsionObject activationState=ACTIVE_TAG (1)?
+
+#end
+
+Namespace mojo3d
+
+Private
+
+Class MotionState Extends btMotionState
+	
+	Method New( entity:Entity )
+		
+		_entity=entity
+	End
+	
+	Method getWorldTransform( tform:btTransform Ptr ) Override
+		
+		If Not _entity.RigidBody.Kinematic Print "Dynamic getWorldTransform! Position="+_entity.Position
+
+		tform->setOrigin( _entity.Position )
+		
+		tform->setBasis( _entity.Basis )
+	End
+	
+	Method setWorldTransform( tform:btTransform Ptr ) Override
+		
+		If _entity.RigidBody.Kinematic Print "Kinematic setWorldTransform!"
+		
+		_entity.Position=tform->getOrigin()
+		
+		_entity.Basis=tform->getBasis()
+	End
+	
+	Private
+	
+	Field _entity:Entity
+End
+
+Public
+
+Class Entity Extension
+	
+	Property RigidBody:RigidBody()
+		
+		Return GetComponent<RigidBody>()
+	End
+	
+End
+
+Class RigidBody Extends Component
+	
+	Const Type:=New ComponentType( "RigidBody",1,ComponentTypeFlags.Singleton )
+	
+	Method New( entity:Entity )
+		
+		Super.New( entity,Type )
+		
+		Local collider:=entity.Collider
+		Local inertia:btVector3=collider?.CalculateLocalInertia( _mass )
+		
+		_btmotion=New MotionState( entity )
+		
+		_btbody=New btRigidBody( _mass,_btmotion,collider.btShape,inertia )
+		
+		Kinematic=False
+		Mass=1
+		Friction=1
+		RollingFriction=1
+		Restitution=0
+		CollisionGroup=1
+		CollisionMask=1
+	End
+	
+	Method New( entity:Entity,body:RigidBody )
+		
+		Self.New( entity )
+		
+		Kinematic=body.Kinematic
+		Mass=body.Mass
+		Friction=body.Friction
+		RollingFriction=body.RollingFriction
+		Restitution=body.Restitution
+		CollisionGroup=body.CollisionGroup
+		CollisionMask=body.CollisionMask
+	End
+
+	Property Kinematic:Bool()
+		
+		Return _kinematic
+	
+	Setter( kinematic:Bool )
+		
+		If kinematic=_kinematic Return
+		
+		_kinematic=kinematic
+		
+		If _kinematic
+			_btbody.setCollisionFlags( _btbody.getCollisionFlags() | btCollisionObject.CF_KINEMATIC_OBJECT )
+			_btbody.setActivationState( DISABLE_DEACTIVATION )
+		Else
+			_btbody.setCollisionFlags( _btbody.getCollisionFlags() & ~btCollisionObject.CF_KINEMATIC_OBJECT )
+			_btbody.forceActivationState( ACTIVE_TAG )
+		Endif
+			
+'		_dirty|=Dirty.Kinematic
+	End
+	
+	Property Mass:Float()
+		
+		Return _mass
+		
+	Setter( mass:Float )
+		
+		If mass=_mass Return
+		
+		_mass=mass
+		
+		Local collider:=Entity.Collider
+		Local inertia:=collider?.CalculateLocalInertia( _mass )
+		_btbody.setMassProps( _mass,inertia )
+		
+'		_dirty|=Dirty.Mass
+	End
+
+	Property Friction:Float()
+		
+		Return _btbody.getFriction()
+	
+	Setter( friction:Float )
+		
+		_btbody.setFriction( friction )
+	End
+	
+	Property RollingFriction:Float()
+		
+		Return _btbody.getRollingFriction()
+	
+	Setter( friction:Float )
+		
+		_btbody.setRollingFriction( friction )
+	End
+	
+	Property Restitution:Float()
+		
+		Return _btbody.getRestitution()
+		
+	Setter( restitution:Float )
+		
+		_btbody.setRestitution( restitution )
+	End
+	
+	Property LinearVelocity:Vec3f()
+		
+		Return _btbody.getLinearVelocity()
+		
+	Setter( velocity:Vec3f )
+		
+		_btbody.setLinearVelocity( velocity )
+	End
+	
+	Property AngularVelocity:Vec3f()
+		
+		Return _btbody.getAngularVelocity()
+	
+	Setter( avelocity:Vec3f )
+		
+		_btbody.setAngularVelocity( avelocity )
+	End
+
+	Property CollisionGroup:Short()
+		
+		Return _collGroup
+		
+	Setter( collGroup:Short )
+		
+		_collGroup=collGroup
+	End
+	
+	Property CollisionMask:Short()
+		
+		Return _collMask
+		
+	Setter( collMask:Short )
+		
+		_collMask=collMask
+	End
+	
+	Property btBody:btRigidBody()
+	
+		Return _btbody
+	End
+	
+	Method ClearForces()
+
+		_btbody.clearForces()
+	End
+
+	Protected
+	
+	Method OnCopy:RigidBody( entity:Entity ) Override
+		
+		Return New RigidBody( entity,Self )
+	End
+
+	Method OnBeginUpdate() Override
+		
+'		Validate()
+		
+		Local collider:=Entity.Collider
+		
+		Local seq:=collider?.Seq
+		
+		If seq<>_colliderseq
+			
+			If _rvisible
+				If Entity.ReallyVisible 
+					World.btWorld.removeRigidBody( _btbody )
+				Else
+					_rvisible=False
+					World.Remove( Self )
+				Endif
+			Endif
+			
+			_btbody.setCollisionShape( collider?.btShape )
+			Local inertia:btVector3=collider?.CalculateLocalInertia( _mass )
+			_btbody.setMassProps( _mass,inertia )
+			
+			If _rvisible World.btWorld.addRigidBody( _btbody )
+			
+			_colliderseq=seq
+			
+		Endif
+			
+		If Entity.ReallyVisible<>_rvisible
+			
+			_rvisible=Entity.ReallyVisible
+
+			If _rvisible World.Add( Self ) Else World.Remove( Self )
+				
+		Endif
+
+		If Not _kinematic And Entity.Seq<>_seq 
+			
+			_btbody.setWorldTransform( Entity.Matrix )
+		Endif
+		
+	End
+	
+	Method OnUpdate( elapsed:Float ) Override
+		
+'		If _kinematic Return
+		
+'		Local tform:=_btbody.getWorldTransform()
+		
+'		Entity.Position=tform.getOrigin()
+		
+'		Entity.Basis=tform.getBasis()
+		
+		_seq=Entity.Seq
+	End
+	
+	Method OnDestroy() Override
+		
+		If Not _rvisible Return
+		
+		_rvisible=False
+		
+		World.Remove( Self )
+	End
+	
+	Internal
+	
+	Property World:World()
+		
+		Return Entity.Scene.World
+	End
+	
+	Private
+	
+	Enum Dirty
+		Mass=1
+		Kinematic=2
+	End
+	
+	Field _kinematic:Bool=False
+	Field _mass:Float=1
+	Field _collGroup:Short=1
+	Field _collMask:Short=1
+
+	Field _btmotion:MotionState
+	Field _btbody:btRigidBody
+	Field _dirty:Dirty=Null
+	
+	Field _colliderseq:Int
+	Field _rvisible:Bool
+	Field _seq:Int
+	
+	Method Validate()
+		
+		If Not _dirty Return
+		
+		If _dirty & Dirty.Mass
+
+			Local collider:=Entity.Collider
+			Local inertia:btVector3=collider?.CalculateLocalInertia( _mass )
+			_btbody.setMassProps( _mass,inertia )
+		Endif
+		
+		If _dirty & Dirty.Kinematic
+			
+			If _kinematic
+				_btbody.setCollisionFlags( _btbody.getCollisionFlags() | btCollisionObject.CF_KINEMATIC_OBJECT )
+				_btbody.setActivationState( DISABLE_DEACTIVATION )
+			Else
+				_btbody.setCollisionFlags( _btbody.getCollisionFlags() & ~btCollisionObject.CF_KINEMATIC_OBJECT )
+				_btbody.forceActivationState( ACTIVE_TAG )
+			Endif
+		Endif
+		
+		_dirty=Null
+	End
+End

+ 74 - 0
modules/mojo3d/geometry/bttypeconvs.monkey2

@@ -0,0 +1,74 @@
+
+Namespace mojo3d
+
+Public
+
+Struct Vec3<T> Extension
+
+	Operator To:btVector3()
+
+		Return New btVector3( x,y,z )
+	End
+End
+
+Struct btVector3 Extension
+
+	Operator To:Vec3f()
+
+		Return New Vec3f( x,y,z )
+	End
+End
+
+Struct Vec4<T> Extension
+	Operator To:btVector4()
+
+		Return New btVector4( x,y,z,w )
+	End
+End
+
+Struct btVector4 Extension
+
+	Operator To:Vec4f()
+	
+		Return New Vec4f( x,y,z,w )
+	End
+End
+
+Struct Mat3f Extension
+
+	Operator To:btMatrix3x3()
+
+		Return New btMatrix3x3( i.x,j.x,k.x, i.y,j.y,k.y, i.z,j.z,k.z )
+	End
+End
+
+Struct btMatrix3x3 Extension
+
+	Operator To:Mat3f()
+	
+		Return New Mat3f( Cast<Vec3f>( getColumn(0) ),Cast<Vec3f>( getColumn(1) ),Cast<Vec3f>( getColumn(2) ) )
+	End
+End
+
+
+Struct AffineMat4f<T> Extension
+	
+	Operator To:btTransform()
+	
+		Return New btTransform( Cast<btMatrix3x3>( m ),Cast<btVector3>( t ) )
+	End
+
+End
+
+Struct btTransform Extension
+	
+	Operator To:AffineMat4f()
+	
+		Return New AffineMat4f( Cast<Mat3f>( getBasis() ),Cast<Vec3f>( getOrigin() ) )
+	End
+
+End
+
+
+
+

+ 97 - 0
modules/mojo3d/scene/native/collisiondetect.cpp

@@ -0,0 +1,97 @@
+
+#include "collisiondetect.h"
+
+namespace{
+
+	void *_colls[65536];
+	
+	void **_collp=_colls;
+}
+
+void collisionCallback( btDynamicsWorld *world,btScalar timeStep ){
+
+	int numManifolds=world->getDispatcher()->getNumManifolds();
+	
+	for( int i=0;i<numManifolds;++i ){
+
+		btPersistentManifold *manifold=world->getDispatcher()->getManifoldByIndexInternal( i );
+        
+		const btCollisionObject *body0=manifold->getBody0();
+		const btCollisionObject *body1=manifold->getBody1();
+       
+//		printf( "Collision! body0=%p body1=%p\n",body0,body1 );fflush( stdout );
+		
+		*_collp++=body0->getUserPointer();
+		*_collp++=body1->getUserPointer();
+	}
+}
+
+bool contactAddedCallback( btManifoldPoint &cp,const btCollisionObjectWrapper *colObj0,int partId0,int index0,const btCollisionObjectWrapper *colObj1,int partId1,int index1 ){
+
+	printf( "contact added!\n" );fflush( stdout );
+	return true;
+}
+
+bool contactProcessedCallback( btManifoldPoint &cp,void *body0,void *body1 ){
+
+	//printf( "contact processed!\n" );fflush( stdout );
+	return true;
+}
+
+bool contactDestroyedCallback( void *userPersistentData ){
+
+	printf( "contact destroyed!\n" );fflush( stdout );
+	return true;
+}
+
+/*
+void collisionCallback( btDynamicsWorld *world,btScalar timeStep )
+{
+	int numManifolds = world->getDispatcher()->getNumManifolds();
+    for (int i = 0; i < numManifolds; i++)
+    {
+        btPersistentManifold* contactManifold =  world->getDispatcher()->getManifoldByIndexInternal(i);
+        const btCollisionObject* obA = contactManifold->getBody0();
+        const btCollisionObject* obB = contactManifold->getBody1();
+
+        int numContacts = contactManifold->getNumContacts();
+        for (int j = 0; j < numContacts; j++)
+        {
+            btManifoldPoint& pt = contactManifold->getContactPoint(j);
+            if (pt.getDistance() < 0.f)
+            {
+                const btVector3& ptA = pt.getPositionWorldOnA();
+                const btVector3& ptB = pt.getPositionWorldOnB();
+                const btVector3& normalOnB = pt.m_normalWorldOnB;
+                
+                printf( "Collision!\n" );fflush( stdout );
+            }
+        }
+    }
+}
+*/
+
+void initCollisions( btDynamicsWorld *world ){
+
+	world->setInternalTickCallback( &collisionCallback,0,false );
+	
+	gContactAddedCallback=&contactAddedCallback;
+//	gContactProcessedCallback=&contactProcessedCallback;
+//	gContactDestroyedCallback=&contactDestroyedCallback;
+}
+
+void resetCollisions(){
+	
+	_collp=_colls;
+}
+
+int getNumCollisions(){
+
+	return (_collp-_colls)/2;
+}
+
+void **getCollisions(){
+
+	return _colls;
+}
+

+ 14 - 0
modules/mojo3d/scene/native/collisiondetect.h

@@ -0,0 +1,14 @@
+
+#ifndef BB_COLLISIONDETECT_H
+#define BB_COLLISIONDETECT_H
+
+#include "btBulletDynamicsCommon.h"
+
+
+
+void initCollisions( btDynamicsWorld *world );
+void resetCollisions();
+int  getNumCollisions();
+void **getCollisions();
+
+#endif

+ 33 - 0
modules/mojo3d/scene/raycastresult.monkey2

@@ -0,0 +1,33 @@
+
+Namespace mojo3d
+
+Class RayCastResult
+
+	Field time:Float
+	Field body:RigidBody
+	Field point:Vec3f
+	Field normal:Vec3f
+	
+	Method New()
+	End
+	
+	Method New( btresult:btCollisionWorld.ClosestRayResultCallback Ptr )
+		time=btresult->m_closestHitFraction
+		body=Cast<RigidBody>( btresult->m_collisionObject.getUserPointer() )
+		point=btresult->m_hitPointWorld
+		normal=btresult->m_hitNormalWorld
+	End
+	
+	Method New( btresult:btCollisionWorld.ClosestConvexResultCallback Ptr )
+		
+		Local castFrom:=Cast<Vec3f>( btresult->m_convexFromWorld )
+		Local castTo:=Cast<Vec3f>( btresult->m_convexToWorld )
+		
+		time=btresult->m_closestHitFraction
+		body=Cast<RigidBody>( btresult->m_hitCollisionObject.getUserPointer() )
+		point=(castTo-castFrom) * btresult->m_closestHitFraction + castFrom
+		normal=btresult->m_hitNormalWorld
+	End
+	
+End
+

+ 156 - 0
modules/mojo3d/scene/world.monkey2

@@ -0,0 +1,156 @@
+
+Namespace mojo3d
+
+#Import "native/collisiondetect.cpp"
+#Import "native/collisiondetect.h"
+
+Extern Private
+
+Function initCollisions( world:btDynamicsWorld )
+Function resetCollisions()
+Function getNumCollisions:Int()
+Function getCollisions:Void Ptr Ptr()
+
+Public
+
+Class World
+	
+	Method New( scene:Scene )
+		
+		_scene=scene
+		
+		Local broadphase:=New btDbvtBroadphase()
+		
+		Local config:=New btDefaultCollisionConfiguration()
+
+		Local dispatcher:=New btCollisionDispatcher( config )
+		
+		Local solver:=New btSequentialImpulseConstraintSolver()
+		
+		_btworld=New btDiscreteDynamicsWorld( dispatcher,broadphase,solver,config )
+		
+		initCollisions( _btworld )
+
+		Gravity=New Vec3f( 0,-9.81,0 )
+	End
+	
+	Property Scene:Scene()
+	
+		Return _scene
+	End
+
+	Property Gravity:Vec3f()
+	
+		Return _btworld.getGravity()
+		
+	Setter( gravity:Vec3f )
+	
+		_btworld.setGravity( gravity )
+	End
+	
+	Method RayCast:RayCastResult( rayFrom:Vec3f,rayTo:Vec3f,collisionMask:Int )
+		
+		Local btresult:=New btCollisionWorld.ClosestRayResultCallback( rayFrom,rayTo )
+		
+		btresult.m_collisionFilterGroup=collisionMask
+		btresult.m_collisionFilterMask=collisionMask
+		
+		_btworld.rayTest( rayFrom,rayTo,Cast<btCollisionWorld.RayResultCallback Ptr>( Varptr btresult ) )
+		
+		If Not btresult.hasHit() Return Null
+		
+		Return New RayCastResult( Varptr btresult )
+	End
+	
+	Method ConvexSweep:RayCastResult( collider:ConvexCollider,castFrom:AffineMat4f,castTo:AffineMat4f )
+		
+		Local btresult:=New btCollisionWorld.ClosestConvexResultCallback( castFrom.t,castTo.t )
+		
+		_btworld.convexSweepTest( Cast<btConvexShape>( collider.btShape ),castFrom,castTo,Cast<btCollisionWorld.ConvexResultCallback Ptr>( Varptr btresult ),0 )
+		
+		If Not btresult.hasHit() Return Null
+		
+		Return New RayCastResult( Varptr btresult )
+	End
+	
+	Method ConvexSweep:RayCastResult( collider:ConvexCollider,castFrom:Vec3f,castTo:Vec3f )
+		
+		Return ConvexSweep( collider,AffineMat4f.Translation( castFrom ),AffineMat4f.Translation( castTo ) )
+	End
+
+	Method Update( elapsed:Float )
+		
+		resetCollisions()
+		
+		_btworld.stepSimulation( 1.0/60.0 )
+		
+		Local n:=getNumCollisions()
+		
+		Local p:=getCollisions()
+		
+		For Local i:=0 Until n
+			
+			Local body0:=Cast<RigidBody>( p[i*2] )
+			Local body1:=Cast<RigidBody>( p[i*2+1] )
+
+			Local entity0:=body0.Entity
+			Local entity1:=body1.Entity
+			
+			entity0.Collide( body1 )
+			entity1.Collide( body0 )
+			
+'			body0.Entity.Collide( body1 )
+'			body1.Entity.Collide( body0 )
+			
+'			Print "Collision:"+entity0.Name+"->"+entity1.Name
+			
+		Next
+		
+		resetCollisions()
+		
+	End
+	
+	Property btWorld:btDynamicsWorld()
+		
+		Return _btworld
+	End
+	
+	Internal
+	
+	Method Add( body:RigidBody )
+		
+		Print "World.Add( RigidBody )"
+		
+		_bodies.Add( body )
+		
+		Local btbody:=body.btBody
+		
+		btbody.setUserPointer( Cast<Void Ptr>( body ) )
+		
+		_btworld.addRigidBody( btbody,body.CollisionGroup,body.CollisionMask )
+	End
+	
+	Method Remove( body:RigidBody )
+		
+		Print "World.Remove( RigidBody )"
+		
+		Local btbody:=body.btBody
+		
+		_btworld.removeRigidBody( btbody )
+		
+		body.btBody.setUserPointer( Null )
+
+		_bodies.Remove( body )
+	End
+	
+	Private
+	
+	Field _scene:Scene
+	
+	Field _btworld:btDynamicsWorld
+	
+	Field _newBodies:=New Stack<RigidBody>
+	
+	Field _bodies:=New Stack<RigidBody>
+
+End

+ 215 - 0
modules/mojo3d/tests/shapes.monkey2

@@ -0,0 +1,215 @@
+
+Namespace myapp
+
+#Import "<std>"
+#Import "<mojo>"
+#Import "<mojo3d>"
+
+#Import "assets/"
+
+#Import "util"
+
+Using std..
+Using mojo..
+Using mojo3d..
+
+Class MyWindow Extends Window
+	
+	Field _scene:Scene
+	
+	Field _camera:Camera
+	
+	Field _light:Light
+	
+	Field _ground:Model
+	
+	Field _marker:Model
+	
+'	Method OnMeasure:Vec2i() Override
+		
+'		Return New Vec2i( 640,480 )
+'	End
+	
+	Method New( title:String="Simple mojo app",width:Int=640,height:Int=480,flags:WindowFlags=WindowFlags.Resizable )
+
+		Super.New( title,width,height,flags )
+		
+'		Layout="letterbox"
+		
+		_scene=Scene.GetCurrent()
+		
+		'create camera
+		'
+		_camera=New Camera
+		_camera.Name="Camera"
+		_camera.Near=.1
+		_camera.Far=60
+		_camera.Move( 0,10,-10 )
+		New FlyBehaviour( _camera )
+		
+		Local camCollider:=New SphereCollider( _camera )
+		camCollider.Radius=1
+		Local camBody:=New RigidBody( _camera )
+		camBody.Kinematic=True
+		camBody.Mass=0
+		camBody.CollisionGroup=32
+		camBody.CollisionMask=127
+		
+		'create light
+		'
+		_light=New Light
+		_light.RotateX( 75,15 )
+		
+		'create ground
+		'
+		Local groundBox:=New Boxf( -60,-1,-60,60,0,60 )
+		
+		_ground=Model.CreateBox( groundBox,16,16,16,New PbrMaterial( Color.Green ) )
+		_ground.Name="Ground"
+		
+		_ground.Collided+=Lambda( body:RigidBody )
+		
+'			Print "Ground hit: "+body.Entity.Name
+		End
+		
+		Local groundCollider:=New BoxCollider( _ground )
+		groundCollider.Box=groundBox
+		
+		Local groundBody:=New RigidBody( _ground )
+		groundBody.Mass=0
+		groundBody.CollisionGroup=64
+		groundBody.CollisionMask=127
+		
+		Local material:=New PbrMaterial( Color.White )
+
+		Local box0:=New Boxf( -1,-5,-1,1,5,1 )		
+		Local model0:=Model.CreateBox( box0,1,1,1,material )
+		model0.Name="Box"
+		Local collider0:=New BoxCollider( model0 )
+		collider0.Box=box0
+		Local body0:=New RigidBody( model0 )
+		body0.CollisionGroup=1
+		body0.CollisionMask=127
+		
+		Local model1:=Model.CreateSphere( 1,32,16,material )
+		model1.Name="Sphere"
+		Local collider1:=New SphereCollider( model1 )
+		Local body1:=New RigidBody( model1 )
+		body1.CollisionGroup=2
+		body1.CollisionMask=127
+
+		Local model2:=Model.CreateCylinder( 1,8,Axis.Y,32,material )
+		model2.Name="Cylinder"
+		Local collider2:=New CylinderCollider( model2 )
+		collider2.Radius=1
+		collider2.Length=8
+		Local body2:=New RigidBody( model2 )
+		body2.CollisionGroup=4
+		body2.CollisionMask=127
+
+		Local model3:=Model.CreateCapsule( 1,10,Axis.Y,32,material )
+		model3.Name="Capsule"
+		Local collider3:=New CapsuleCollider( model3 )
+		collider3.Radius=1
+		collider3.Length=10
+		Local body3:=New RigidBody( model3 )
+		body3.CollisionGroup=8
+		body3.CollisionMask=127
+		
+		Local model4:=Model.CreateCone( 2.5,5,Axis.Y,32,material )
+		model4.Name="Cone"
+		Local collider4:=New ConeCollider( model4 )
+		collider4.Radius=2.5
+		collider4.Length=5
+		Local body4:=New RigidBody( model4 )
+		body4.CollisionGroup=16
+		body4.CollisionMask=127
+		
+		Local models:=New Model[]( model0,model1,model2,model3,model4 )
+		
+		#rem
+		For Local x:=-40 To 40 Step 8
+			
+			For Local z:=-40 To 40 Step 8
+				
+				Local i:=Int( Rnd(5) )
+				
+				Local model:=models[i].Copy()
+				
+				model.Materials=New Material[]( New PbrMaterial( New Color( Rnd(),Rnd(),Rnd() ) ) )
+				
+				model.Move( x,10,z )
+			Next
+		
+		Next
+		#end
+		
+		Local x:=0.0
+		
+		For Local model:=Eachin models
+			
+			model.Move( x,10,0 )
+			
+			x+=5.0
+			
+			'model.Destroy()
+		Next
+		
+		_marker=Model.CreateCone( 1,2,Axis.Y,12,New PbrMaterial( Color.Red ),Null )
+		
+		_marker.Mesh.FitVertices( New Boxf( -.125,0,-.125,.125,1,.125 ),False )
+		
+	End
+	
+	Method OnRender( canvas:Canvas ) Override
+		
+		RequestRender()
+		
+		_camera.Viewport=Rect
+		
+		_scene.Update()
+		
+		Local raycast:=_camera.MousePick( 127 )
+		
+		Local picked:=""
+		
+		If raycast
+			
+			Local j:=raycast.normal,i:Vec3f,k:Vec3f
+			
+			If Abs( j.x )>.5
+				k=New Vec3f( 0,0,1 )
+				i=j.Cross( k ).Normalize()
+				k=i.Cross( j ).Normalize()
+			Else
+				i=New Vec3f( 1,0,0 )
+				k=i.Cross( j ).Normalize()
+				i=j.Cross( k ).Normalize()
+			Endif
+			
+			_marker.Position=raycast.point
+			_marker.Basis=New Mat3f( i,j,k )
+			_marker.Visible=True
+			picked=raycast.body.Entity.Name+" "+_marker.Basis.j
+			
+		Else
+			
+			_marker.Visible=False
+			
+		Endif
+		
+		_scene.Render( canvas )
+		
+		canvas.DrawText( "Camera pos="+_camera.Position+", Picked="+picked+", FPS="+App.FPS,0,0 )
+	End
+	
+End
+
+Function Main()
+
+	New AppInstance
+	
+	New MyWindow
+	
+	App.Run()
+End