Pretty neat, eh?
Pub.NewtonAndIrrlicht:
Irrlicht.Extended:
'my second newton physics test 'using newton collision trees Framework BRL.Blitz 'core module Import BRL.Random 'random number generator. Import Pub.NewtonAndIrrlicht 'Imports Newton, Irrlicht, and some 'nice interface functions Print "HELLO WORLD!!!" ms=MilliSecs() SeedRnd ms 'randomize seed based on the system timer -- the best way to get 'the most random results. Print "Seeded random number generator with system clock. ("+ms+")" 'irrlicht pointers Global dvc:IrrlichtDevice 'the core irrlicht device class Global dvr:IVideoDriver 'the video driver class Global sne:ISceneManager 'the scene manager class Global msm:IMeshManipulator 'the mesh manipulator class Global csr:ICursorControl 'the cursor manipulator class Global rcv:SmoothEventReceiver 'the input event receiver 'newton pointers and matricies Global boxlist:TList Global collision:Byte Ptr Global boxcollision:Byte Ptr 'create irrlicht context DebugCreateIrrlicht False,True,fullScn,rAccel,dvc,dvr,sne,rcv msm=sne.getMeshManipulator() csr=dvc.getCursorControl() dvc.SetResizeable True Print "Successfully created Irrlicht Device context." Global font:IGUIFont=dvc.getGUIEnvironment().getFont("fontcourier.bmp") Print "Successfully generated font." dvr.beginScene True,True font.draw "LOADING...",_RECTI(3,3,300,50),_SCOLOR(255,255,255,255) dvr.endScene() 'create skybox If rAccel Then sne.addSkyBoxSceneNode( .. dvr.getTexture("up.jpg"), .. dvr.getTexture("down.jpg"), .. dvr.getTexture("left.jpg"), .. dvr.getTexture("right.jpg"), .. dvr.getTexture("back.jpg"), .. dvr.getTexture("front.jpg")) End If Print "Successfully added skybox." 'create scene camera (viewpoint) Global cam:ICameraSceneNode=sne.addCameraSceneNodeFPS(Null,92,64,64) cam.setPosition(_VECTOR3DF(0,20,-10)) Print "Successfully added camera." 'add a light source sne.addLightSceneNode(Null,_VECTOR3DF(0,50,0)) Print "Successfully added light source." 'attach the newton api lib If Not StartNewton() Then Print "Could not attach dynamics engine API." Notify "Could not attach dynamics engine API.",True End End If Print "Successfully attached dynamics engine API!" 'create a newton world using custom memory handlers by pointing 'to the functions; null argument selects standard memory handlers Global world:Byte Ptr=NewtonCreate(MemAllocate,MemRelease) NewtonSetMinimumFrameRate world,500 sim_gravity=9800 'scale up 1000 from 9.8 meter/sec^2 'Set the solver and friction models to perfect. All calculations are resolved as 'many times as is neccessary to eliminate all drift errors before iterating. Slower 'but much more accurate. NewtonSetSolverModel world,0 NewtonSetFrictionModel world,0 Print "Successfully generated dynamics world!" 'load a mesh for the collision tree Global amesh:IAnimatedMesh=sne.getMesh("testlevel.b3d") Global mesh:IMesh=amesh.getMesh(0) msm.ScaleMesh(mesh,_VECTOR3DF(10,10,10)) Global meshnode:ISceneNode=sne.addMeshSceneNode(mesh) 'meshnode.setScale _VECTOR3DF(10,10,10) Local meshcollision:Byte Ptr=NewtonCreateTreeCollision(world,Null) Local meshbody:Byte Ptr=MeshToNewtonCollisionTree(world,mesh,meshcollision,True) Local meshmat#[16] 'Local wmn#[3] 'Local wmx#[3] 'NewtonBodyGetMatrix meshbody,Varptr mat[0] 'NewtonCollisionCalculateAABB meshcollision,Varptr mat[0],Varptr wmn[0],Varptr wmx[0] 'wmx[2]:+200 'NewtonSetWorldSize world,Varptr wmn[0],Varptr wmx[0] NewtonBodySetUserData meshbody,Byte Ptr(meshnode.handle) NewtonBodySetDestructorCallback meshbody,BodyDestructor GetEulerMatrix meshnode,meshmat NewtonBodySetMatrix meshbody,Varptr meshmat[0] NewtonReleaseCollision world,meshcollision Print "Successfully added geo-collision tree." 'Print "Successfully generated cube collision object." Global boxmesh:IMesh=sne.getMesh("smallcube.3ds").getMesh(0) msm.ScaleMesh(boxmesh,_VECTOR3DF(.1,.1,.1)) Global tex:ITexture=dvr.getTexture("wall.jpg") 'boxcollision=NewtonCreateTreeCollision(world,Null) 'MeshToNewtonCollisionTree world,boxmesh,boxcollision,False,False boxcollision=NewtonCreateBox(world,4,4,4,Null) csr.setVisible False 'okay, here we go WriteStdout "Begin simulation..." fps=0 str$="" timestep!=0''Local intMat[16] msdn=False Repeat If rcv.IsMouseButtonDown(0) And Not msdn Then AddBox msdn=True Else If Not rcv.IsMouseButtonDown(0) And msdn=True msdn=False End If If rcv.IsKeyDownUp(EKEY_ESCAPE) Then dvc.closeDevice() 'update world euler matrix timestep=NewtonGetTimeStep(world) NewtonUpdate world,timestep NodeDestructor 'destroy the deleted/released nodes dvr.beginScene True,True sne.drawAll() 'draw scene 'draw general data fps=dvr.getFPS() str="renderer ~q" str:+dvr.getName()+"~q physics ~qNewton Dynamics v" str:+NewtonWorldGetVersion(world)+"~q " str:+"FPS = "+fps+" TimeStep = "+timestep font.draw str,_RECTI(5,5,300,50),_SCOLOR(255,0,0,0) str="renderer ~q" str:+dvr.getName()+"~q physics ~qNewton Dynamics v" str:+NewtonWorldGetVersion(world)+"~q " str:+"FPS = "+fps+" TimeStep = "+timestep font.draw str,_RECTI(3,3,300,50),_SCOLOR(255,255,255,64) 'draw debug data curralloced=GCMemAlloced() font.draw "CoreMem="+(curralloced/1024)+"KB "+.. "SimMem="+(nMemSize/1024)+.. "KB TotalMem="+((curralloced+nMemSize)/1024)+.. "KB Note: Irrlicht uses a seperate memory system.",.. _RECTI(5,21,300,50),_SCOLOR(255,0,0,0) font.draw "CoreMem="+(curralloced/1024)+"KB "+.. "SimMem="+(nMemSize/1024)+.. "KB TotalMem="+((curralloced+nMemSize)/1024)+.. "KB Note: Irrlicht uses a seperate memory system.",.. _RECTI(3,19,300,50),_SCOLOR(255,255,255,64) dvr.endScene() GCCollect Until Not dvc.run() Print "ended properly." 'now we clean up NewtonReleaseCollision world,boxcollision NewtonDestroyAllBodies world 'destroy all bodies in dynamics world Print "Successfully destroyed all physical bodies." NewtonDestroy world 'destroy dynamics world Print "Successfully destroyed dynamics world." NodeDestructor Print "Successfully destroyed scene nodes." ReleaseIrrlicht dvc 'release irrlicht context Print "Successfully released Irrlicht Device context." StopNewton 'drop newton api Print "Successfully dropped dynamics engine API." End Function AddBox:Byte Ptr() Local boxnode:ISceneNode Local box:Byte Ptr boxnode=sne.addMeshSceneNode(boxmesh) boxnode.setPosition(cam.getPosition()) boxnode.setMaterialFlag EMF_LIGHTING,True boxnode.setMaterialTexture(0,tex) GCCollect GetEulerMatrix boxnode,mat box=NewtonCreateBody(world,boxcollision) NewtonBodySetMassMatrix box,1#,1#,1#,1# NewtonBodySetMatrix box,Varptr mat[0] omega=[Float(Rnd(-10,10)),Float(Rnd(-10,10)),Float(Rnd(-10,10))] NewtonBodySetOmega box,Varptr omega[0] NewtonBodySetAutoFreeze box,1 NewtonBodySetUserData box,Byte Ptr(boxnode.handle) NewtonBodySetDestructorCallback box,BodyDestructor NewtonBodySetTransformCallback box,NSetTransform NewtonBodySetForceAndTorqueCallback box,ApplyForceAndTorque GCCollect Return box End Function
Pub.NewtonAndIrrlicht:
Rem bbdoc: Irrlicht and Newton Integration Helper End Rem Module Pub.NewtonAndIrrlicht ModuleInfo "Author: Bill Whitacre (ninjarat), GMan" 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] Global sim_gravity#=9.8 '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(NewtonMat[12],NewtonMat[13],NewtonMat[14]) NSceneNode.setRotation _VECTOR3DF(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) ?Debug origMemSize=nMemSize ? nMemSize:+size ?Debug Print "Allocated "+size+"Bytes memory on top of "+origMemSize+" for sim. nNewMemSize="+nMemSize origMemSize=Null ? GCCollect Return MemAlloc(size) End Function Function MemRelease(memptr:Byte Ptr,size:Int) ?Debug origMemSize=nMemSize ? nMemSize:-size MemClear memptr,size MemFree memptr ?Debug Print "Released "+size+"/"+origMemSize+"Bytes memory for sim. nNewMemSize="+nMemSize origMemSize=Null ? 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*-sim_gravity,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(Rnd(-1#,1#),Rnd(9#,12#),Rnd(-1#,1#)) 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 'Fixed by gman. That guy's showing up in the credits for sure. Thank you G! Function AnimatedMeshToNewtonCollisionTree:Byte Ptr(world:Byte Ptr,map:IAnimatedMesh,newtonMap:Byte Ptr,createbox=True,createbody=True) NewtonTreeCollisionBeginBuild(newtonmap) Local cMeshBuffer,j Local mb:IMeshBuffer Local vArray#[9] 'vertex array (3*3 floats) For cMeshBuffer=0 To map.getMesh(0).getMeshBufferCount() - 1 mb = map.getMesh(0).getMeshBuffer(cMeshBuffer) Local vertType=mb.getVertexType() Local arr_standardVerts:Array_S3DVertex=Null Local arr_2TCoordVerts:Array_S3DVertex2TCoords=Null Local arr_TangentVerts:Array_S3DVertexTangents=Null If vertType=EVT_STANDARD arr_standardVerts=mb.getVertices() Else If vertType=EVT_2TCOORDS arr_2TCoordVerts=mb.getVertices2TCoords() Else If vertType=EVT_TANGENTS arr_TangentVerts=mb.getVerticesTangents() EndIf 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] Local v1:Vertex=Null Local v2:Vertex=Null Local v3:Vertex=Null If vertType=EVT_STANDARD Then v1=Vertex(arr_standardVerts.elementAt(v1i)) v2=Vertex(arr_standardVerts.elementAt(v2i)) v3=Vertex(arr_standardVerts.elementAt(v3i)) Else If vertType=EVT_2TCOORDS Then v1=Vertex(arr_2TCoordVerts.elementAt(v1i)) v2=Vertex(arr_2TCoordVerts.elementAt(v2i)) v3=Vertex(arr_2TCoordVerts.elementAt(v3i)) Else If vertType=EVT_TANGENTS Then v1=Vertex(arr_tangentVerts.elementAt(v1i)) v2=Vertex(arr_tangentVerts.elementAt(v2i)) v3=Vertex(arr_tangentVerts.elementAt(v3i)) EndIf vArray[0]=v1.getPos().getX() vArray[1]=v1.getPos().getY() vArray[2]=v1.getPos().getZ() vArray[3]=v2.getPos().getX() vArray[4]=v2.getPos().getY() vArray[5]=v2.getPos().getZ() vArray[6]=v3.getPos().getX() vArray[7]=v3.getPos().getY() vArray[8]=v3.getPos().getZ() NewtonTreeCollisionAddFace(newtonmap, 3,Varptr vArray[0], 12, j) Next Next NewtonTreeCollisionEndBuild(newtonmap,0) If createbody Then Local newtonmapbody:Byte Ptr=NewtonCreateBody(world,newtonmap) If createbox Then 'set the newton world size based on the mesh size Local boxP0#[3] Local boxP1#[3] NewtonBodyGetMatrix newtonmapbody,Varptr mat[0] NewtonCollisionCalculateAABB newtonmap,Varptr mat[0],Varptr boxP0[0],Varptr boxP1[0] 'pad the box boxP0[0]:-60 boxP1[0]:+60 boxP0[1]:-60 boxP1[1]:+60 boxP0[2]:-60 boxP1[2]:+60 NewtonSetWorldSize world,Varptr boxP0[0],Varptr boxP1[0] End If Return newtonmapbody End If Return Null End Function Function MeshToNewtonCollisionTree:Byte Ptr(world:Byte Ptr,map:IMesh,newtonMap:Byte Ptr,createbox=True,createbody=True) NewtonTreeCollisionBeginBuild(newtonmap) Local cMeshBuffer,j Local mb:IMeshBuffer Local vArray#[9] 'vertex array (3*3 floats) For cMeshBuffer=0 To map.getMeshBufferCount() - 1 mb = map.getMeshBuffer(cMeshBuffer) Local vertType=mb.getVertexType() Local arr_standardVerts:Array_S3DVertex=Null Local arr_2TCoordVerts:Array_S3DVertex2TCoords=Null Local arr_TangentVerts:Array_S3DVertexTangents=Null If vertType=EVT_STANDARD arr_standardVerts=mb.getVertices() Else If vertType=EVT_2TCOORDS arr_2TCoordVerts=mb.getVertices2TCoords() Else If vertType=EVT_TANGENTS arr_TangentVerts=mb.getVerticesTangents() EndIf 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] Local v1:Vertex=Null Local v2:Vertex=Null Local v3:Vertex=Null If vertType=EVT_STANDARD Then v1=Vertex(arr_standardVerts.elementAt(v1i)) v2=Vertex(arr_standardVerts.elementAt(v2i)) v3=Vertex(arr_standardVerts.elementAt(v3i)) Else If vertType=EVT_2TCOORDS Then v1=Vertex(arr_2TCoordVerts.elementAt(v1i)) v2=Vertex(arr_2TCoordVerts.elementAt(v2i)) v3=Vertex(arr_2TCoordVerts.elementAt(v3i)) Else If vertType=EVT_TANGENTS Then v1=Vertex(arr_tangentVerts.elementAt(v1i)) v2=Vertex(arr_tangentVerts.elementAt(v2i)) v3=Vertex(arr_tangentVerts.elementAt(v3i)) EndIf vArray[0]=v1.getPos().getX() vArray[1]=v1.getPos().getY() vArray[2]=v1.getPos().getZ() vArray[3]=v2.getPos().getX() vArray[4]=v2.getPos().getY() vArray[5]=v2.getPos().getZ() vArray[6]=v3.getPos().getX() vArray[7]=v3.getPos().getY() vArray[8]=v3.getPos().getZ() NewtonTreeCollisionAddFace(newtonmap,3,Varptr vArray[0],12,j) Next Next NewtonTreeCollisionEndBuild(newtonmap,0) If createbody Then Local newtonmapbody:Byte Ptr=NewtonCreateBody(world,newtonmap) If createbox Then 'set the newton world size based on the mesh size Local boxP0#[3] Local boxP1#[3] NewtonBodyGetMatrix newtonmapbody,Varptr mat[0] NewtonCollisionCalculateAABB newtonmap,Varptr mat[0],Varptr boxP0[0],Varptr boxP1[0] 'pad the box boxP0[0]:-80 boxP1[0]:+80 boxP0[1]:-80 boxP1[1]:+80 boxP0[2]:-80 boxP1[2]:+80 NewtonSetWorldSize world,Varptr boxP0[0],Varptr boxP1[0] End If Return newtonmapbody End If Return Null End Function
Irrlicht.Extended:
Module Irrlicht.Extended Import Irrlicht.AddOns Import BRL.System Private OnEnd byebye Function byebye() Print "Goodbye." End Function Global eventrcv:SmoothEventReceiver=SmoothEventReceiver.createReceiver() Public Function DebugCreateIrrlicht(stencil,vsync,fullScn% Var,rAccel% Var,dvc:IrrlichtDevice Var,dvr:IVideoDriver Var,sne:ISceneManager Var,rcv:SmoothEventReceiver Var) fsn=Confirm("Run in fullscreen?") rac=Confirm("Click OK to use HW Driven rendering acceleration. If you~n~r"+.. "don't, a software renderer will be used instead.") If rac Then Select Confirm("Default driver is Direct3D (v8.x to v9.x). Use OpenGL(1.x.x) instead?") Case True CreateIrrlicht EDT_OPENGL,640,480,16,fsn,stencil,vsync,dvc,dvr,sne,eventrcv Case False Select Confirm( .. "Use Direct3D 9.0? Cancel will default to older driver (Direct3D 8.1).~n~r"+.. "D3D 8.1 is not fully functional in the rendering techniques this program uses, so~n~r"+.. "rendering errors may occur. Most commonly reported is the inexplicable failiure to~n~r"+.. "render seemingly random polygons on the sphere mesh primitives. The physics~n~r"+.. "simulation is entirely independent of the renderer, so it should be the same regardless.") Case True CreateIrrlicht EDT_DIRECT3D9,640,480,16,fsn,stencil,vsync,dvc,dvr,sne,eventrcv Case False CreateIrrlicht EDT_DIRECT3D8,640,480,16,fsn,stencil,vsync,dvc,dvr,sne,eventrcv End Select End Select Else If Confirm("Use high quality software renderer? WARNING: This will be VERY SLOW!") Then CreateIrrlicht EDT_SOFTWARE2,640,480,16,fsn,stencil,vsync,dvc,dvr,sne,eventrcv Else CreateIrrlicht EDT_SOFTWARE,640,480,16,fsn,stencil,vsync,dvc,dvr,sne,eventrcv End If End If fullScn=fsn rAccel=rac rcv=eventrcv End Function Function CreateIrrlicht(renderer,rezx,rezy,bits,fullscrn,stencil,vsync,DVC:IrrlichtDevice Var,DVR:IVideoDriver Var,SCN:ISceneManager Var,RCV:SmoothEventReceiver Var) DVC=IrrlichtDevice.create(.. renderer,_DIMENSION2DI(rezx,rezy),rezdepth,.. fullscrn,stencil,vsync,eventrcv) If DVC.handle=0 Then Print "Could not create 3D device!" Notify "Could not create 3D device!",True End Else Print "Created 3D device successfully!" End If DVR=DVC.getVideoDriver() SCN=DVC.getSceneManager() RCV=eventrcv End Function Function ReleaseIrrlicht(DVC:IrrlichtDevice) DVC.drop() DVC=Null If DVC Then Print "3D device was not released successfully!" Notify "3D device was not released successfully!",True End Else Print "3D device was released successfully!" End If End Function