JV-ODE Physics Thread 3

Blitz3D Forums/Blitz3D Userlibs/JV-ODE Physics Thread 3

; ###################################################################################################
; #								JV-ODE - Pyramid Destruction IV Demo								#
; #									Jim Williams (VIP3R) and Wayne Gray								#
; ###################################################################################################

AppTitle "JV-ODE - Pyramid Destruction IV"

Include "JV-ODE.bb"

Graphics3D 800,600,32,2
HidePointer


Global ElapsedTime
Global LastTime
Global FrameCount
Global Frames
Global Time

Global cflag
Global Proj
Global Projbody
Global snd1
Global snd2
Global piv1

Global Planet$
Global gx

Global Wide=10  ; Number of blocks wide at the base, default 10
Global Gap#=8  ; Gap spacing, default 8
Global RBW#=5  ; Real block width, default 5
			
piv1=CreatePivot()

Type ODEGeom
	Field body
	Field geom
	Field mesh
End Type

; create a blank image 
gfxBlank=CreateImage (256,256) 


; ###################################################################################################

; ### Setup ODE

Global World=dWorldCreate()
Global Space=dHashSpaceCreate(0)
Global ContactGroup=dJointGroupCreate(0)

dWorldSetAutoDisableFlag(World,1)
dWorldSetGravity(World,0,-1.0,0)

Planet="Earth"
gx=1

dWorldSetERP(World,0.4)
dContactSetMode(dContactBounce)
dContactSetBounce(0.0)
dContactSetMu(80)

; High Performance Settings
; Causes objects to settle down and sleep faster
dWorldSetAutoDisableLinearThreshold (World, .1)
dWorldSetAutoDisableAngularThreshold (World, .1)
dWorldSetAutoDisableSteps (World,10)
dContactSetMaxContacts(16)
dWorldSetQuickStepNumIterations (World,20) ; default 20

; ### Create light

Global Light=CreateLight()

RotateEntity Light,45,-90,0
LightColor Light,255,255,255
AmbientLight 130,130,130

; ### Create camera

Global Camera=CreateCamera()

CameraClsColor Camera,0,0,0
CameraRange Camera,1,1000
PositionEntity Camera,30,25,-100
RotateEntity Camera,15,0,0

; Create first camera 
Global cam1=CreateCamera() 
; Set the first camera's viewport so that it fills the top half of the camera 
CameraViewport cam1,GraphicsWidth()-256,0,256,256 


; ### Load sounds
snd1=Load3DSound("media\Impact.wav")
snd2=LoadSound("media\whizz.wav")

SoundVolume snd2,.2

mic1=CreateListener(camera,.3,1,1) ; Create listener, make it child of camera 

; ### Create plane

dCreatePlane(Space,0,1,0,0)

Plane=CreatePlane()

EntityAlpha Plane,0.8

PlaneTexture=CreateTexture(128,128,9)

ClsColor 0,200,80
Cls

Color 255,255,255

Rect 0,0,64,64,1
Rect 64,64,64,64,1

CopyRect 0,0,128,128,0,0,BackBuffer(),TextureBuffer(PlaneTexture)
ScaleTexture PlaneTexture,20,20
EntityTexture Plane,PlaneTexture,0,0

Mirror=CreateMirror()

; Construct pyramid

For j#=wide To 1 Step -1
	For k#=1 To j
		AddObject(k#*Gap+(wide-j#)*Gap/2,RBW/2 + (wide-j#)*RBW)
		bcount=bcount+1
	Next
Next
		
addProjectile(EntityX(camera),EntityY(camera),EntityZ(camera))

		

; ###################################################################################################

While Not KeyHit(1)

UpdateControls()

; Calculate Time 
If T=0 Then T=MilliSecs()
T=MilliSecs() 

; Mouse Look code

; Poll Mouse Movement every 25ms ( 40/sec )
If T > Time2 + 25 Then
	Time2=T
	mxs#=mxs#+(MouseXSpeed()-mxs#)/3
	mys#=mys#+(MouseYSpeed()-mys#)/3

	If MouseDown(2) Then 
		MoveMouse GraphicsWidth()/2,GraphicsHeight()/2
		p1#=p1#-mys#
		y1#=y1#-mxs#
		RotateEntity camera,-p1#,y1#,0
	EndIf
EndIf	

; Run Physics every 15ms ( 66/sec )
If T > Time3 + 15 Then
	Time3=T	
	
	PTime=MilliSecs()

	UpdateGeoms()
	
	dSpaceCollide(Space,World,ContactGroup)
	
	UpdateSounds()
	
	dWorldQuickStep(World,.2)
	
	dJointGroupEmpty(ContactGroup)

	PhysicsTime#=MilliSecs()-PTime
End If

; Update missle cam image buffer every 66ms ( 15/sec )
If T > Time4 + 66 Then
	Time4=T
	cam1_flag=True
Else
	cam1_flag=False
End If

	
	SetBuffer BackBuffer()
	
	If cam1_flag=False Then
		;Cls
		WireFrame False
		ShowEntity camera
		HideEntity cam1
		RenderWorld
		CopyRect 0,0,256,256,GraphicsWidth()-256,0,ImageBuffer(gfxBlank),BackBuffer()
		
		
	Else
		;save block cam image
		WireFrame False ; true to make wirefram missle cam
		HideEntity camera
		ShowEntity cam1
		RenderWorld
		CopyRect GraphicsWidth()-256,0,256,256,0,0,BackBuffer(),ImageBuffer(gfxBlank) 
		Cls
		ShowEntity camera
		HideEntity cam1
		WireFrame False
		RenderWorld
		CopyRect 0,0,256,256,GraphicsWidth()-256,0,ImageBuffer(gfxBlank),BackBuffer()

	EndIf
	
	Rect GraphicsWidth()-256,0,256,256,0
	
	Color 255,255,255
	Text 0,0,"JV-ODE Version "+dGetVersion()
	Text 0,15,"Physics Time:"+PhysicsTime
	Text 0,30,"FPS:"+Fps()
	Color 255,0,0
	Text 0,60,"P - Planet="+Planet
	Color 255,255,255
	Text 0,75,"LM - Pushes Object"
	Text 0,90, "RM - Mouse Look"
	Text 0,105, "R  - Reconstruct Pyramid"
	Text 0,120, "WSAD - Movement"
    Text 0,135, "K - Missle Cam"
	Text 0,150, "Space - Shoots"
	
	Text GraphicsWidth()/2-1,GraphicsHeight()/2,"[ ]"
	
	Flip  

Wend

dJointGroupDestroy(ContactGroup)
dSpaceDestroy(Space)
dWorldDestroy(World)
dCloseODE()

End

; ###################################################################################################

Function AddObject(x#,height#)

ode.ODEGeom=New ODEGeom
ode\body=dBodyCreate(World)

dBodySetRotation(ode\body,0,0,0)
dBodySetPosition(ode\body,x,Height,0)

dBodySetAutoDisableFlag(ode\body,1)
mass=dMassCreate()
dMassSetBox(mass,1,5,5,5)
dMassSetBoxTotal(mass,20,5,5,5)
dBodySetMass(ode\body,mass)
dMassDestroy(mass)
ode\geom=dCreateBox(Space,5,5,5)
dGeomContactSetMode(ode\geom,dContactBounce)
dGeomContactSetBounce(ode\geom,0.0)
dGeomContactSetSoftERP(ode\geom,0.1)
dGeomSetBody(ode\geom,ode\body)
ode\mesh=CreateCube()
ScaleMesh ode\mesh,2.5,2.5,2.5
EntityColor ode\mesh,Rand(255),Rand(255),Rand(255)
EntityAlpha ode\mesh,1
EntityShininess ode\mesh,0.7

EntityPickMode ode\mesh,2 ; Make pickable

End Function

; ###################################################################################################

Function PosObject(x#,height#, body)

dBodyDisable(body)
dBodySetRotation(body,0,0,0)
dBodySetPosition(body,x,Height,0)
dBodySetLinearVel  (body, 0,0,0)
dBodySetAngularVel (body, 0,0,0)
dBodyEnable(body)

End Function

; ###################################################################################################

Function AddProjectile(X#,Y#,Z#)

ode.ODEGeom=New ODEGeom
ode\body=dBodyCreate(World)

dBodySetRotation(ode\body,0,0,0)
dBodySetPosition(ode\body,x#,Y#,Z#)

dBodySetAutoDisableFlag(ode\body,1)
mass=dMassCreate()
dMassSetBox(mass,1,5,5,5)
dMassSetBoxTotal(mass,20,5,5,5)
dBodySetMass(ode\body,mass)
dMassDestroy(mass)
ode\geom=dCreateBox(Space,5,5,5)
dGeomContactSetMode(ode\geom,dContactBounce)
dGeomContactSetBounce(ode\geom,0.0)
dGeomContactSetSoftERP(ode\geom,0.1)
dGeomSetBody(ode\geom,ode\body)
ode\mesh=CreateCube()
ScaleMesh ode\mesh,2.5,2.5,2.5
EntityColor ode\mesh,Rand(255),Rand(255),Rand(255)
EntityAlpha ode\mesh,1
EntityShininess ode\mesh,0.7

proj=ode\mesh ; ENTITY	
projbody=ode\body

End Function
; ###################################################################################################

Function UpdateGeoms()

For ode.ODEGeom=Each ODEGeom
	If dBodyIsEnabled(ode\body)
		RotateEntity ode\mesh,dGeomGetPitch#(ode\geom),dGeomGetYaw#(ode\geom),dGeomGetRoll#(ode\geom)
		PositionEntity ode\mesh,dGeomGetPositionX#(ode\geom),dGeomGetPositionY#(ode\geom),dGeomGetPositionZ#(ode\geom)
	End If
Next

End Function

; ###################################################################################################

Function Fps()
Time=MilliSecs()

ElapsedTime=ElapsedTime+Time-LastTime
LastTime=Time
FrameCount=FrameCount+1

If ElapsedTime>1000
	ElapsedTime=0
	Frames=FrameCount
	FrameCount=0
EndIf
Return Frames
End Function 

; ###################################################################################################

Function UpdateControls()

	If MouseDown(1)=1

	CameraPick(Camera,MouseX(),MouseY())
		If PickedEntity()
			For ode.ODEGeom=Each ODEGeom
				If ode\mesh=PickedEntity()
					dBodyEnable(ode\body)
					dBodyAddForce ode\body,-300*PickedNX#(),-300*PickedNY#(),-300*PickedNZ#()
				End If
			Next
		End If
	End If


	; Spacebar - Fire
	If KeyHit(57) Then
		dBodyDisable(Projbody)
		; Set projectile to match camera orientation
		dBodySetRotation(Projbody,EntityPitch(camera),EntityYaw(camera),EntityRoll(camera))
		dBodySetPosition(Projbody,EntityX(camera),EntityY(camera),EntityZ(camera))
		; Set projectile velocity and spin to zero
		dBodySetLinearVel  (Projbody, 0,0,0)
		dBodySetAngularVel (Projbody, 0,0,0)
		
		dBodyEnable(Projbody)
		dBodyAddRelForce(Projbody,0,0,2500)
		
		PlaySound snd2
	EndIf
	
	; Reconstruct pyramid
	If KeyDown(19) Then
		ode.ODEGeom=First ODEGeom
		
			; Construct pyramid
	
			For j#=wide To 1 Step -1
				For k#=1 To j
					PosObject(k#*Gap+(wide-j#)*Gap/2,RBW/2 + (wide-j#)*RBW,ode\body)

					ode = After ode
				Next
			Next
			
		
	End If
	
	; (K)amera
	If KeyHit(37) Then
		PositionEntity cam1,EntityX(proj),EntityY(proj),EntityZ(proj)
		RotateEntity cam1,EntityPitch(proj), EntityYaw(proj), EntityRoll(proj)
		EntityParent cam1,proj
	EndIf
	

	
; WSAD - Movement

; W- Forward
If KeyDown(17) Or KeyDown(200) Then
	MoveEntity camera,0,0,1
EndIf
; S- Reverse
If KeyDown(31) Or KeyDown(208) Then
	MoveEntity camera,0,0,-1
EndIf

; A- Left
If KeyDown(30) Or KeyDown(203) Then
	MoveEntity camera,-1,0,0
EndIf
; D- Right
If KeyDown(32) Or KeyDown(205) Then
	MoveEntity camera,1,0,0
EndIf

; G - Gravity
If KeyHit(25) Then
	gx=gx+1
	If gx>4 Then gx=1
	Select gx
	  Case 1
		Planet="Earth "
		dWorldSetGravity(World,0,-1.0,0)
	
	  Case 2
		Planet="Mars"
		dWorldSetGravity(World,0,-.33333,0)

	  Case 3
		Planet="Moon"
		dWorldSetGravity(World,0,-.16666,0)
		
	  Case 4
		Planet="Space"
		dWorldSetGravity(World,0,0,0)
	End Select
	
EndIf


End Function

; ###################################################################################################

Function UpdateSounds()

For ode.ODEGeom=Each ODEGeom
	If dGeomIsEnabled(ode\geom)
		numjoints=dBodyGetNumJoints(ode\body)
		If numjoints>0 
		
			For joints=0 To numjoints-1
				joint=dBodyGetJoint(ode\body,joints)
				If dJointGetType(joint)=dJointTypeContact
					
					; Get linear velocity vector
			  		ax#=dBodyGetLinearVelX#(ode\body)
			  		ay#=dBodyGetLinearVelY#(ode\body)
				    az#=dBodyGetLinearVelZ#(ode\body)
					; Get Angular velocity vector
			  		bx#=dBodyGetAngularVelX#(ode\body)
			  		by#=dBodyGetAngularVelY#(ode\body)
					bz#=dBodyGetAngularVelZ#(ode\body)
			  		; Calculate magnitudes
					ForceA#=Sqr(ax*ax+ay*ay+az*az)
					ForceB#=Sqr(bx*bx+by*by+bz*bz)
					
					;If ForceA>.01
					;	LinearDamp(ode\body,.04)
					;End If
					
					If ForceA>1.5
						PositionEntity piv1,dGeomGetPositionX#(ode\geom),dGeomGetPositionY#(ode\geom),dGeomGetPositionZ#(ode\geom)
						EmitSound(snd1,piv1)
					End If

					;If ForceB>.01
					;	AngularDamp(ode\body,.06)
					;End If
					
				End If
			Next
		End If
	End If
Next

End Function