Irrlicht and Newton

BlitzMax Forums/BlitzMax Programming/Irrlicht and Newton

While I'm at it I'll just show you the module I'm working on; it gives what I showed you guys some context.

Rem
bbdoc: Irrlicht and Newton Integration Helper
End Rem
Module Pub.NewtonAndIrrlicht
ModuleInfo "Author: Bill Whitacre (ninjarat)"
ModuleInfo "History: Added functions used in Newton Examples and converted to Irrlicht graphics."

Import BRL.LinkedList
Import Pub.Newton
Import Irrlicht.Extended

Global nMemSize,nNodeDestroyList:TList=New TList
Global mat#[16]
Global omega#[3]

'Excellent Euler Matrix converter functions.  Not by me, and I would give credit where
'it was called for, except I honestly don't know who did this.
Function GetEulerMatrix(NSceneNode:ISceneNode,NewtonMat#[])
	Local Euler#[3]
	Euler[0]=NSceneNode.getRotation().getX()*(Pi/180#)
	Euler[1]=NSceneNode.getRotation().getY()*(Pi/180#)
	Euler[2]=NSceneNode.getRotation().getZ()*(Pi/180#)
	NewtonSetEulerAngle(Varptr Euler[0],Varptr NewtonMat[0])
	
	NewtonMat[12]=NSceneNode.getPosition().getX()
	NewtonMat[13]=NSceneNode.getPosition().getY()
	NewtonMat[14]=NSceneNode.getPosition().getZ()
End Function
Function SetEulerMatrix(NSceneNode:ISceneNode,NewtonMat#[])
	Local Euler#[3]
	NewtonGetEulerAngle(Varptr NewtonMat[0],Varptr Euler[0])
	NSceneNode.setPosition _VECTOR3DF(NewtonMat[12],NewtonMat[13],NewtonMat[14])
	NSceneNode.setRotation _VECTOR3DF(Euler[0]*(180/Pi),Euler[1]*(180/Pi),Euler[2]*(180/Pi))
End Function
'pointer edition euler matrix functions
Function GetEulerMatrix2(NSceneNode:ISceneNode,NewtonMat:Float Ptr)
	Local Euler#[3]
	Euler[0]=NSceneNode.getRotation().getX()*(Pi/180)
	Euler[1]=NSceneNode.getRotation().getY()*(Pi/180)
	Euler[2]=NSceneNode.getRotation().getZ()*(Pi/180)
	NewtonSetEulerAngle Varptr Euler[0],Varptr newtonMat[0]
	Newtonmat[12]=NSceneNode.getPosition().getX()
	newtonMat[13]=NSceneNode.getPosition().getY()
	NewtonMat[14]=NSceneNode.getPosition().getZ()	
End Function
Function SetEulerMatrix2(NSceneNode:ISceneNode,NewtonMat:Float Ptr)
	Local Euler#[3]
	NewtonGetEulerAngle Varptr NewtonMat[0],Varptr Euler[0]
	NSceneNode.setPosition Vector3df.createFromVals(NewtonMat[12],NewtonMat[13],NewtonMat[14])
	NSceneNode.setRotation Vector3df.createfromVals(Euler[0]*(180/Pi),Euler[1]*(180/Pi),Euler[2]*(180/Pi))
End Function

'These override Newton's local memory functions with native function wrappers.
Function MemAllocate:Byte Ptr(size:Int)
	nMemSize:+size
	Return MemAlloc(size)
End Function
Function MemRelease(memptr:Byte Ptr,size:Int)
	nMemSize:-size
	MemClear memptr,size
	MemFree memptr
	GCCollect
End Function

'body event callbacks
Function  ApplyForceAndTorque(Body:Byte Ptr) 'gravity callback
	Local mass#,Ixx#,Iyy#,Izz#
	NewtonBodyGetMassMatrix(body,Varptr mass, Varptr Ixx, Varptr Iyy, Varptr Izz)
	Local force#[]=[0#,Iyy*mass*-550#,0#]
	NewtonBodySetForce body,Varptr force[0]
End Function
Function  NSetTransform(body:Byte Ptr,NewtonMat# Ptr) 'the N prefix is because the
                                           'set transform function is already used
                                             'by this language for something else.
	Local node:ISceneNode
	node=ISceneNode.CreateFromHandle(Int(newtonBodyGetUserData(body)),False)
	
	newtonBodyGetMatrix body,Varptr NewtonMat[0]
	SetEulerMatrix2 node,Varptr NewtonMat[0]
End Function
Function BodyLeftWorld(body:Byte Ptr) 'What do we do if we've gone off the edge of the
                                      'world?  Answer: We get dropped back in.
	Local node:ISceneNode=ISceneNode.CreateFromHandle(Int(newtonBodyGetUserData(body)),False)
	node.setPosition _VECTOR3DF(0,0,0)
	GetEulerMatrix node,mat
	
	NewtonBodySetMatrix body,Varptr mat[0]
End Function
Function BodyDestructor(body:Byte Ptr) 'if a physical body is destroyed, we add it's
                                       'graphics node to the destructor list.
	Local NodeHandle:Int
	
	NodeHandle=Int(newtonBodyGetUserData(body))
	nNodeDestroyList.AddLast NodeHandle
End Function

'Destructor for the released scene nodes.  Call every time any node(s) is destroyed.
Function NodeDestructor()
	If nNodeDestroyList.Count()>0 Then
		Local tempNode:ISceneNode
		Local objarr:Object[]=ListToArray(nNodeDestroyList)
		Local intarr[objarr.length]
		For j=0 To objarr.length-1
			intarr[j]=objarr[j]
		Next
		For del=EachIn intarr
			tempNode=ISceneNode.CreateFromHandle(del,False)
			tempNode.remove
		Next
		nNodeDestroyList=New TList;tempNode=Null;objarr=Null;intarr=Null
		GCCollect
	End If
End Function

'this is where the trouble is.
Function AnimatedMeshToNewtonCollisionTree:Byte Ptr(nWorld:Byte Ptr,g_map:IAnimatedMesh,g_newtonMap:Byte Ptr)
	NewtonTreeCollisionBeginBuild(g_newtonmap)
	Local cMeshBuffer:Int,j:Int
	Local v1i:Int,v2i:Int,v3i:Int
	Local mb:IMeshBuffer
	
	Local vArray:Float[9]	'vertex array (3*3 floats)
	
	Local tmpCount:Int = 0
	
	For cMeshBuffer=0 To g_map.getMesh(0).getMeshBufferCount() - 1
		
		mb = g_map.getMesh(0).getMeshBuffer(cMeshBuffer)
		
		Local mb_vertices:Array_S3DVertex=mb.getVertices()
		Local mb_indices:Array_u16=mb.getIndices()
		
		'add each triangle from the mesh
		For j=0 To mb.getIndexCount() - 1 Step 3
			v1i=mb_indices.elementAt(j)[0]
			v2i=mb_indices.elementAt(j+1)[0]
			v3i=mb_indices.elementAt(j+2)[0]
			
			vArray[0]=mb_vertices.elementAt(v1i).getPos().getX()
			vArray[1]=mb_vertices.elementAt(v1i).getPos().getY()
			vArray[2]=mb_vertices.elementAt(v1i).getPos().getZ()
			vArray[3]=mb_vertices.elementAt(v2i).getPos().getX()
			vArray[4]=mb_vertices.elementAt(v2i).getPos().getY()
			vArray[5]=mb_vertices.elementAt(v2i).getPos().getZ()
			vArray[6]=mb_vertices.elementAt(v3i).getPos().getX()
			vArray[7]=mb_vertices.elementAt(v3i).getPos().getY()
			vArray[8]=mb_vertices.elementAt(v3i).getPos().getZ()
			
			NewtonTreeCollisionAddFace(g_newtonmap,3,Varptr vArray[0],12,1)
		Next
		
	Next
	NewtonTreeCollisionEndBuild(g_newtonmap,0);
	Local g_newtonmapbody:Byte Ptr=NewtonCreateBody(nWorld,g_newtonmap);
	
Rem
After loading the bsp mesh in irrlicht we must create a newton collision tree consisting of all the triangles
in the bsp mesh. To do this we loop through the indices list And add vertices 3 at a time into newton. I should
mention here that I was lazy when writing this And just used a straight cast To video::S3DVertex2TCoords - this is because
bsp meshes have lightmap textures on them. If you are using a mesh with only 1 set of texture co-ordinates (like
a landscape Or .x level) Then use (video::S3DVertex).
Newton requires 2 pointers For every Object - a NewtonBody* For the rigid body, And a NewtonCollision* that
describes the objects geometry. After creating the tree collision geometry, we create a body For the map And
assign it To the collision. Bodys which have a tree collision For their geometry are static And their mass
will be ignored by newton - so you can only use meshes For your scenery!
End Rem
	'set the newton world size based on the bsp size
	Local boxP0#[3] 
	Local boxP1#[3] 
	NewtonBodyGetMatrix g_newtonmapbody,Varptr mat[0]
	NewtonCollisionCalculateAABB g_newtonmap,Varptr mat[0],Varptr boxP0[0],Varptr boxP1[0]
	'pad the box
	boxP0[0]:-100
	boxP1[0]:+100
	boxP0[1]:-100
	boxP1[1]:+100
	boxP0[2]:-100
	boxP1[2]:+100
	NewtonSetWorldSize nWorld,Varptr boxP0[0],Varptr boxP1[0]
Rem
After loading the map, we can calculate the bounding box surrounding it And set the newton world size To
match. Newton should automatically disable anything which falls out of the map this way.
End Rem
	Return g_newtonmapbody
End Function