Spherical Gravity function for Tokamak-- need help

Blitz3D Forums/Blitz3D Beginners Area/Spherical Gravity function for Tokamak-- need help

WarpZone(Posted 2004) [#1]
(Note: You can use this code for any purpose whatsoever without giving me so much as a nod.)

I'm extremely new, both to Blitz3D and to Tokamak, but when I asked if Tokamak could be used to simulate spherical gravity rather than vertical, the good Mr. Sweeny gave me the following advice:

-Get the directionvector from the center To the actual Object.
-Normalize the vector And call
-TOKRB_SetForce

Let me see how far I can go before I get stuck...

I'm starting with this tutorial: http://www.blitzcoder.com/cgi-bin/articles/show_article.pl?f=bot__builder103252004031037.html

-Changed the model name to point to my own creation. "Down" gravity works normally. :)

-Turned off gravity by setting the Y value to 0. Simple enough. I quickly figured out how to change the direction spacebar pushes them by modifying the values, and how to make Blitz choose random numbers within a range as the values.

Okay, let's see here... Guess I should probably write a function for this.

Function SphereGravity()
End Function


Direction Vector... hmmm. The first step for li'l ol' me is to figure out what a vector is. And since the Blitz forum search engine AND the playerfactory forum both return absolutely no results, ever, no matter what search terms I enter, I suppose I'd better consult my old college buddy professor Google for advice...

http://www.netcomuk.co.uk/~jenolive/vect3.html

Um... wait, what?

http://www.gamedev.net/reference/articles/article813.asp

Ah! Okay, that makes more sense!

Okay, so to "get the direction vector," I need to know the coordinates of the center of the world (Guess I'll just use the values 0,0,0. Later on, I can add an entity to represent the center of gravity, I guess...) and the x,y,z coordinates of each Entity.

Let's see... I'll use that nifty little "for i=1 To ENTS" trick to do it once for each particle object...

Function SphereGravity()
For i=1 To ENTS

vx#= 0-(TOKRB_Getx(rb(i))
vy#= 0-(TOKRB_Gety(rb(i))
vz#= 0-(TOKRB_Getz(rb(i))


End Function


That normalizes the verctors... I think. I hope I didn't have to declare those variables before assinging a value... well, if I did, it'll let me know when I try to run it. ;)

Whoops, forgot some )'s!

Function SphereGravity()
vx#= 0-(TOKRB_GetX(rb(i)))
vy#= 0-(TOKRB_GetY(rb(i)))
vz#= 0-(TOKRB_GetZ(rb(i)))



End Function


Okay... now I can just call the Tokamak command like you said to, right?

Function SphereGravity()
vx#= 0-(TOKRB_GetX(rb(i)))
vy#= 0-(TOKRB_GetY(rb(i)))
vz#= 0-(TOKRB_GetZ(rb(i)))


TOKRB_SetForce (rb(i),vx#*Grav*Mass,vy#*Grav*Mass,vz#*Grav*Mass)
End Function 



Where do I get the values for gravity and mass...?

I guess I can arbitrarily define the gravity as a global value someplace up near the top of my program. Later on, I can turn that into a gravity entity with adjustible gravity pull. In the meantime, I'll use the original y value from TOKSIM_CreateSimulator, negative ten.

Hmmm... I see a SetMass command in the Blitz-integrated Tokamak help Command Reference, but no GetMass. I guess I'll randomly try GetMass(rb(1)) and see if it works...

Nope! Blitz's code colorizer doesn't seem to recognize GetMass as a command! I've come this far without help, but now I'm totally stuck.

Global worldgravity=-10

Function SphereGravity()

vx#= 0-(TOKRB_GetX(rb(i)))
vy#= 0-(TOKRB_GetY(rb(i)))
vz#= 0-(TOKRB_GetZ(rb(i)))


TOKRB_SetForce (rb(i),vx#*(WorldGravity)*Mass,vy#*(WorldGravity)*Mass,vz#*(WorldGravity)*Mass)
End Function 


Please kindly take it from here, if you could, Sweenie or other Tokamak experts. How do I get the mass of a Tokamak entity?

Also, if anyone has any slick optimizations for the above function, or if I'm doing it all wrong and the above won't work, please post now! :D


WarpZone(Posted 2004) [#2]
Hmmm. Got it sort of working.

Function SphereGravity()
For i=1 To ENTS
vx#= 0-(TOKRB_GetX(rb(i)))
vy#= 0-(TOKRB_GetY(rb(i)))
vz#= 0-(TOKRB_GetZ(rb(i)))
Mass#=.0001
TOKRB_ApplyImpulse (rb(i),vx*WorldGravity*Mass,vy*WorldGravity*Mass,vz*WorldGravity*Mass)
Next
End Function


I'm supposed to be calling this every cycle, right?

I've found that the objects tends to speed up like crazy if they're too far away from the source of gravity, which causes them to go crazy speeds and pass through meshes without colliding properly, etc. Even with the extremely small value for Mass, we still get problems if the objects get repulsed to the edges of the world, and then someone reverses gravity. They form way-too-extreme orbitals instead of packing together nicely into a cluster like they do if they spawn near the center and collapse.

I am thinking what this needs is good old fashioned terminal velocity. Let's see... that means I need to determine the length of the vector, and shorten said length if it's too long.

I'll try If xy>10 then xy=10, and the inverse, for each of the three values, but I'm thinking there might be a better way to go about it, probably based on high school geometry. :P

Any suggestions?

Also, I'm still wanting to know if tokamak entities have intrinsic mass, and if so, how to access that data?


Sweenie(Posted 2004) [#3]
Try this...
Const FPS=90

Graphics3D 800,600,0,2
SetBuffer BackBuffer()

camera = CreateCamera()
PositionEntity camera,0,0,-100

ENTS=100
GRAVITY#=-9.8
SPHEREMASS#=1.0	 

TOKSIM_SetRigidBodiesCount ENTS
TOKSIM_SetGeometriesCount ENTS
TOKSIM_SetOverlappedPairsCount (ENTS*(ENTS-1))/2 

TOKSIM_CreateSimulator(0,0,0)

SeedRnd MilliSecs()  

; Visualise the gravi-sphere
sphere=CreateSphere(32)
ScaleMesh sphere,50,50,50
EntityAlpha sphere,0.3
EntityColor sphere,150,150,250

Dim obj_mesh(ENTS)
Dim obj_rb(ENTS)

For i=1 To ENTS
 obj_mesh(i) = CreateSphere()
 obj_rb(i) = TOKRB_Create()
 TOKRB_AddSphere obj_rb(i),2.0
 TOKRB_SetLinearDamping obj_rb(i),0.001
 TOKRB_SetAngularDamping obj_rb(i),0.02
 TOKRB_SetMass obj_rb(i),SPHEREMASS#
 TOKRB_SetSphereInertiaTensor obj_rb(i),2.0,SPHEREMASS#  
 TOKRB_SetPosition obj_rb(i),Rnd(-5.0,5.0),Rnd(-5.0,5.0),Rnd(-5.0,5.0)
 EntityColor obj_mesh(i),Rnd(100,230),Rnd(100,230),Rnd(100,230) 
Next

Centerpivot = CreatePivot()

light=CreateLight()
PositionEntity light,255,255,-255
PointEntity light,Centerpivot

period=1000/FPS
time=MilliSecs()-period

; MainLoop
While Not KeyHit(1)

	Repeat
		elapsed=MilliSecs()-time
	Until elapsed

	ticks=elapsed/period
	tween#=Float(elapsed Mod period)/Float(period)

	For k=1 To ticks
		time=time+period
		If k=ticks Then CaptureWorld

		TOKSIM_Advance(1.5/FPS,1)

	For i=1 To ENTS

	 ;Get the directionvector
	 diffx#=0.0-TOKRB_GetX#(obj_rb(i))
	 diffy#=0.0-TOKRB_GetY#(obj_rb(i))
	 diffz#=0.0-TOKRB_GetZ#(obj_rb(i))
	 Length#=Sqr(diffx#*diffx#+diffy#*diffy#+diffz#*diffz#)	; distance from center
	 	
	 If Length#=0 Then Length#=0.001 ; To prevent divizion by zero
	
	 normx#=diffx#/Length#	; Normalize the directionvector
	 normy#=diffy#/Length#
	 normz#=diffz#/Length#
	
	 ;Prevent bodies to leave the sphere by moving them inside the sphere
	 ;and then invert their velocityvector with a little damping(0.7) to make them bounce
	 If Length#>50.0 Then
	  TOKRB_SetPosition obj_rb(i),-normx#*49.9,-normy#*49.9,-normz#*49.9
	  TOKRB_SetVelocity obj_rb(i),-TOKRB_GetVelocityX#(obj_rb(i))*0.7,-TOKRB_GetVelocityY#(obj_rb(i))*0.7,-TOKRB_GetVelocityZ#(obj_rb(i))*0.7
	 EndIf

	 ;Apply gravital force
     TOKRB_SetForce obj_rb(i),normx#*GRAVITY#*SPHEREMASS#,normy#*GRAVITY#*SPHEREMASS#,normz#*GRAVITY#*SPHEREMASS#
	
	 ;Update visible meshes
     PositionEntity obj_mesh(i),TOKRB_GetX(obj_rb(i)),TOKRB_GetY(obj_rb(i)),TOKRB_GetZ(obj_rb(i)) 
     RotateEntity obj_mesh(i),TOKRB_GetPitch(obj_rb(i)),TOKRB_GetYaw(obj_rb(i)),TOKRB_GetRoll(obj_rb(i)),False

	Next

	UpdateWorld

	Next

; Press space to invert gravity
If KeyHit(57) Then 
 Switch=1-Switch
 If Switch=0 Then GRAVITY#=-9.8
 If Switch=1 Then GRAVITY#=9.8
EndIf


	RenderWorld tween
	Text 0,10,"Press SPACE to invert gravity"
	Flip 

Wend

TOKSIM_DestroySimulator()

End




WarpZone(Posted 2004) [#4]
Played around with the various arbitrary values I was using for Mass and Gravity. Things were still going through walls occasionally, even with a terminal velocity implemented.

Finally, I figured out that I could just turn up the substeps. At about 10 substeps, things seem to finally be working the way I want them to in order for it to look like "real" crates and oil drums falling at 1 gee, without any noticible clipping errors so far.

Currently, the game is trying to run at 50fps, is spending 8ms on physics and another 12-18ms on rendering. It was less than 1ms for physics using the demo's default settings for substeps. Basically, I just kept increasing it until I could make the stuff fall fast without piles of stuff pushing each other out of the world through the corners.

It works pretty well, all things considered. And using the techniques I'd picked up while implementing this, I also created a surreal little day/night cycle using 2 dynamic spotlights attached to a pivot. I feel like I'm starting to get the hang of Blitz for the first time since buying it.

Regarding Tokamak, is there any way to make the entities stop moving when they get close enough to "at rest?" They do that automatically on a flat surface with the built-in gravity active, but I guess I'd have to implement it manually using Active and Isactive, coupled with in-game triggers such as "this object has been sitting around idling, minding its own business, but it just got touched by a player."

I'm still eager to hear if there's anything I can do to read an entity's mass.

to summarize: That's the secret, folks! If you want Tokamak to do thigs it wasn't designed to do, you have to script the gravity yourself manually. If you want manually scripted physics to look nice and use all the Tokamak trimmings, you have to set the the TOKSIM_Advance command's substep value RIDICULOUSLY HIGH, like(1.5/FPS,10) or something. And if you do this, it slows down your game's FPS noticibly.

In the end, it's up to you to decide how badly you want your weird little special effects, and what you're willing to sacrifice to achieve them. For my game, which I'm planning to be pretty high-concept, I think it might be worth it to make sure the physics are both convincing and dynamic. For an FPS (First Person Shooter, this time, not Frames Per Second,) on the other hand, I'd probably lay the graphics on heavier and worry less about physics.

Say, if I post the entire code so far, would you guys be willing to help me optimize things...? :)


WarpZone(Posted 2004) [#5]
OO;

N...nevermind...

Wow.


WarpZone(Posted 2004) [#6]
I take back the wow.

Your implementation looked really nice and really accurate, until I replaced the completely mathematical sphere with an roundish planetoid mesh of arbitrary complexity, then things started falling through the floor once they'ed settled in the corners again.

That said, your code was still very useful to me. It showed me how to get a distance between two points, and it might be useful for creating a maximum distance, beyond which wayward objects could be destroyed and respawned.

It looks like the only real way to achieve my particular vision for this game is to max out the TOKSIM_Advance substep, however I must thank you for showing me a relatively painless way to abstract out a perfect sphere at substep 1.

I guess that's the trick to next-gen games. Figure out what you're willing to abstract out or figure out how you can store the complexities in a different format.

I will probably be using a substep of at least 5 and probably closer to 10, and just give the player (or the server admin, if multiplayer, since physics would need to be the same across all clients) the option of using a lower substep value, with the understanding that stuff WILL sink into the ground if you use a low value for performance reasons, and if that happens, a new one will just spawn in its starting point.

Hopefully it won't occur that often...

*edit* Woah. Increasing the substep in my modified version of sweeny's demo causes rendertime to inexplicably go up to the 2 second range very quickly once the program gets going. I don't know if it's the collisions causing it or it's just a plain old memory leak, but it's pretty bad. All of these things: reversing gravity, wall collisions, and clustering all the balls in the center, add to the strain when running with higher substep values.

*edit again* I changed your SetForce to a ApplyImpulse, and reduced the gravity value from 9.8 to .98. (Thanks for using "real" gravity numbers, by the way, though it's meaningless without properly scaled models.) I also took out the loadmesh which I think may have been causing problems, though I'm not sure why. The rendertime still skyrockets in response to physics events, but at least it now seems to level out at 109ms. Thanks for your help, Sweeny, but I think I'm going to go with my original code, unless you can tell me what I did wrong when hacking your code to include a loadmesh:


Const FPS=50 

Graphics3D 800,600,0,2
SetBuffer BackBuffer()

Global camera
Global cam_speed#=1
camera = CreateCamera()
PositionEntity camera,0,10,-50
PositionEntity camera,0,0,-100

ENTS=100
GRAVITY#=-.98
SPHEREMASS#=1.0	 

TOKSIM_SetRigidBodiesCount ENTS
TOKSIM_SetGeometriesCount ENTS
TOKSIM_SetOverlappedPairsCount (ENTS*(ENTS-1))/2 

TOKSIM_CreateSimulator(0,0,0)

;Load Mesh and implement it in Tokamak
Global vertices=CreateBank(0),triangles=CreateBank(0)
Global offsett,offsetv,tric,ttlvert,ttltris,cvt
 
Dim tname$(20),tMindex(20)
Global cur=0


;terrain = LoadMesh("worlds/lush/world.b3d")
;ScaleMesh terrain,100,100,100
;TOK_AddMesh terrain
;TOK_SetMesh

SeedRnd MilliSecs()  

; Visualise the gravi-sphere
;sphere=CreateSphere(32)
;ScaleMesh sphere,50,50,50
;EntityAlpha sphere,0.3
;EntityColor sphere,150,150,250




Dim obj_mesh(ENTS)
Dim obj_rb(ENTS)

For i=1 To ENTS
 obj_mesh(i) = CreateSphere()
 obj_rb(i) = TOKRB_Create()
 TOKRB_AddSphere obj_rb(i),2.0
 TOKRB_SetLinearDamping obj_rb(i),0.001
 TOKRB_SetAngularDamping obj_rb(i),0.02
 TOKRB_SetMass obj_rb(i),SPHEREMASS#
 TOKRB_SetSphereInertiaTensor obj_rb(i),2.0,SPHEREMASS#  
 TOKRB_SetPosition obj_rb(i),Rnd(-5.0,5.0),Rnd(-5.0,5.0),Rnd(-5.0,5.0)
 EntityColor obj_mesh(i),Rnd(100,230),Rnd(100,230),Rnd(100,230) 
Next

Centerpivot = CreatePivot()

light=CreateLight()
PositionEntity light,255,255,-255
PointEntity light,Centerpivot

period=1000/FPS
time=MilliSecs()-period

; MainLoop
While Not KeyHit(1)

	Repeat
		elapsed=MilliSecs()-time
	Until elapsed

	ticks=elapsed/period
	tween#=Float(elapsed Mod period)/Float(period)

	For k=1 To ticks
		time=time+period
		If k=ticks Then CaptureWorld

		TOKSIM_Advance(1.5/FPS,10)

	For i=1 To ENTS

	 ;Get the directionvector
	 diffx#=0.0-TOKRB_GetX#(obj_rb(i))
	 diffy#=0.0-TOKRB_GetY#(obj_rb(i))
	 diffz#=0.0-TOKRB_GetZ#(obj_rb(i))
	 Length#=Sqr(diffx#*diffx#+diffy#*diffy#+diffz#*diffz#)	; distance from center
	 	
	 If Length#=0 Then Length#=0.001 ; To prevent divizion by zero
	
	 normx#=diffx#/Length#	; Normalize the directionvector
	 normy#=diffy#/Length#
	 normz#=diffz#/Length#
	
	 ;Prevent bodies to leave the sphere by moving them inside the sphere
	 ;and then invert their velocityvector with a little damping(0.7) to make them bounce
;	 If Length#>50.0 Then
;	  TOKRB_SetPosition obj_rb(i),-normx#*49.9,-normy#*49.9,-normz#*49.9
;	  TOKRB_SetVelocity obj_rb(i),-TOKRB_GetVelocityX#(obj_rb(i))*0.7,-TOKRB_GetVelocityY#(obj_rb(i))*0.7,-TOKRB_GetVelocityZ#(obj_rb(i))*0.7
;	 EndIf

	 ;Apply gravital force
     TOKRB_ApplyImpulse obj_rb(i),normx#*GRAVITY#*SPHEREMASS#,normy#*GRAVITY#*SPHEREMASS#,normz#*GRAVITY#*SPHEREMASS#
	
	 ;Update visible meshes
     PositionEntity obj_mesh(i),TOKRB_GetX(obj_rb(i)),TOKRB_GetY(obj_rb(i)),TOKRB_GetZ(obj_rb(i)) 
     RotateEntity obj_mesh(i),TOKRB_GetPitch(obj_rb(i)),TOKRB_GetYaw(obj_rb(i)),TOKRB_GetRoll(obj_rb(i)),False

	Next

	UpdateWorld

	Next

; Press space to invert gravity
If KeyHit(57) Then 
 Switch=1-Switch
 If Switch=0 Then GRAVITY#=-9.8
 If Switch=1 Then GRAVITY#=9.8
EndIf


RenderWorld tween

Text 0,0,"Physics Time:"+TOKSIM_GetPhysicsTime()*1000.0+ " milliseconds"
Text 0,10,"Render Time:"+Str(elapsed)+ " milliseconds"

	Text 0,30,"Press SPACE to invert gravity"
	Flip 
UpdateFreeCamera()
Wend

TOKSIM_DestroySimulator()

End

Function UpdateFreeCamera()

	;
	;	Camera Control
	;


	; Mouse look
	; ----------

	; Mouse x and y speed
	mxs=MouseXSpeed()/2
	mys=MouseYSpeed()/2
	
	; Mouse shake (total mouse movement)
	mouse_shake=Abs(((mxs+mys)/2)/1000.0)

	; Destination camera angle x and y values
	dest_cam_yaw#=dest_cam_yaw#-mxs
	dest_cam_pitch#=dest_cam_pitch#+mys

	; Current camera angle x and y values
	cam_yaw#=EntityYaw(camera)+((dest_cam_yaw-cam_yaw)/5)
	cam_pitch#=EntityPitch(camera)+((dest_cam_pitch-cam_pitch)/5)
	
	RotateEntity camera,cam_pitch#,cam_yaw#,0
	
	; Rest mouse position to centre of screen
	MoveMouse GraphicsWidth()/2,GraphicsHeight()/2
	

	; Camera move
	; -----------
	
	; Forward/backwards - destination camera move z values
	If KeyDown(200)=True Then MoveEntity camera,0,0,cam_speed#
	If KeyDown(208)=True Then MoveEntity camera,0,0,-cam_speed#

	; Strafe - destination camera move x values
	If KeyDown(205)=True Then MoveEntity camera,cam_speed#,0,0
	If KeyDown(203)=True Then MoveEntity camera,-cam_speed#,0,0


	; Press A to speed up or Z to slow down
	If KeyDown(30)=True Then cam_speed#=cam_speed#+0.2
	If KeyDown(44)=True Then cam_speed#=cam_speed#-0.2
End Function


Function TOK_SetTextureMaterial(fil$,Mindex)
 tname$(cur)=fil$
 tMindex(cur)=Mindex
 cur=cur+1
End Function

Function TOK_AddMesh(mesh,recurse=0,mat=-1,textureindex=0)
 scount=CountSurfaces(mesh)
 For ind=1 To scount
  surface=GetSurface(mesh,ind)
  ttltris=ttltris+CountTriangles(surface)
  ttlvert=ttlvert+CountVertices(surface)
 Next
 ResizeBank triangles,ttltris*24
 ResizeBank vertices,ttlvert*16
 For ind=1 To scount
  surface = GetSurface(mesh,ind)
  bru=GetSurfaceBrush(surface)
  tex=GetBrushTexture(bru,textureindex)
  nam$=strippath$(TextureName$(tex))
  fo=0
  For a=0 To cur-1
   If tname$(a)=nam$ Then mindex=tMindex(a):fo=1:Exit
  Next
  If fo=0 Then mindex=0 
  FreeBrush bru
  FreeTexture tex
  ctr=CountTriangles(surface)
  tric=tric+cvt 
  cvt=CountVertices(surface)
  ;add vertices to bank
  For v=0 To cvt-1 
   TFormPoint VertexX#(surface,v),VertexY#(surface,v),VertexZ#(surface,v),mesh,0
   PokeFloat vertices,offsetv,TFormedX()
   PokeFloat vertices,offsetv+4,TFormedY()
   PokeFloat vertices,offsetv+8,TFormedZ()
   PokeFloat vertices,offsetv+12,0.0
   offsetv=offsetv+16 
  Next
  ;fill bank with triangles 
  For v=0 To ctr-1 
   PokeInt triangles,offsett,tric+TriangleVertex(surface,v,0)
   PokeInt triangles,offsett+4,tric+TriangleVertex(surface,v,1)
   PokeInt triangles,offsett+8,tric+TriangleVertex(surface,v,2)
   If mat=-1 Then PokeInt triangles,offsett+12,mindex ElseIf mat>-1 Then PokeInt triangles,offsett+12,mat Else PokeInt triangles,offsett+12,-2-mat
   PokeInt triangles,offsett+16,0
   PokeInt triangles,offsett+20,0
   offsett=offsett+24
  Next
 Next
 If recurse Then 
  children=CountChildren(mesh)
  If children>0 Then
   For childcount = 1 To children
    child = GetChild(entity,childcount)
    TOK_AddMesh child,recurse,mat  
   Next 
  EndIf
 EndIf
End Function

Function TOK_SetMesh()
 ;Hand over the terrain data to Tokamak
 TOKSIM_SetStaticMesh vertices,ttlvert,triangles,ttltris
 ; Now we can free the banks as Tokamak has copied all data
 FreeBank vertices
 FreeBank triangles
End Function

Function StripPath$(file$) 
 If Len(file$)>0 
  For i=Len(file$) To 1 Step -1 
   mi$=Mid$(file$,i,1) 
   If mi$="\" Or mi$="/" Then Return name$ Else name$=mi$+name$ 
  Next 
 EndIf 
 Return name$ 
End Function 

Function TOK_ReInitializeBanks()
 vertices=CreateBank(0)
 triangles=CreateBank(0)
 offsett=0
 offsetv=0
 tric=0
 ttlvert=0
 ttltris=0
End Function



Sweenie(Posted 2004) [#7]
The reason I used a "logical sphere" instead of a physical mesh is because of Tokamak's somewhat "simple" collisionroutines.

If the body travels so fast that it in one step moves past one of the mesh triangles, it will fall through.
A better collisionsystem would have detected the triangle collision even if the body really never intersected it.

One way would be to disable Tokamaks built in collisiondetection and do the collisionbit yourself.
But apart from just detecting a collision you would also have to apply the proper collisionforces and torques.


WarpZone(Posted 2004) [#8]
Ooh! Ooh! Wait a minute! Is THIS sort of like what you were talking about?

(Code originally submitted by BotBuilder at http://playerfactory.proboards25.com/index.cgi?board=tokamak2&action=display&num=1077666832)

Hmmm... now what do I DO with it...?

;************************
;Functions to access tokamak collision data

Function TOKCOL_bodyA(bank,index)
Return PeekInt(bank,index*104)
End Function

Function TOKCOL_bodyB(bank,index)
Return PeekInt(bank,index*104+4)
End Function

Function TOKCOL_TypeA(bank,index)
Return PeekInt(bank,index*104+8)
End Function

Function TOKCOL_TypeB(bank,index)
Return PeekInt(bank,index*104+12)
End Function

Function TOKCOL_GeometryA(bank,index)
Return PeekInt(bank,index*104+16)
End Function

Function TOKCOL_GeometryB(bank,index)
Return PeekInt(bank,index*104+20)
End Function

Function TOKCOL_MaterialIdA(bank,index)
Return PeekInt(bank,index*104+24)
End Function

Function TOKCOL_MaterialIdB(bank,index)
Return PeekInt(bank,index*104+28)
End Function

Function TOKCOL_BodyContactPointAX#(bank,index)
Return PeekFloat(bank,index*104+32)
End Function

Function TOKCOL_BodyContactPointAY#(bank,index)
Return PeekFloat(bank,index*104+36)
End Function

Function TOKCOL_BodyContactPointAZ#(bank,index)
Return PeekFloat(bank,index*104+40)
End Function

Function TOKCOL_BodyContactPointBX#(bank,index)
Return PeekFloat(bank,index*104+44)
End Function

Function TOKCOL_BodyContactPointBY#(bank,index)
Return PeekFloat(bank,index*104+48)
End Function

Function TOKCOL_BodyContactPointBZ#(bank,index)
Return PeekFloat(bank,index*104+52)
End Function

Function TOKCOL_WorldContactPointAX#(bank,index)
Return PeekFloat(bank,index*104+56)
End Function

Function TOKCOL_WorldContactPointAY#(bank,index)
Return PeekFloat(bank,index*104+60)
End Function

Function TOKCOL_WorldContactPointAZ#(bank,index)
Return PeekFloat(bank,index*104+64)
End Function

Function TOKCOL_WorldContactPointBX#(bank,index)
Return PeekFloat(bank,index*104+68)
End Function

Function TOKCOL_WorldContactPointBY#(bank,index)
Return PeekFloat(bank,index*104+72)
End Function

Function TOKCOL_WorldContactPointBZ#(bank,index)
Return PeekFloat(bank,index*104+76)
End Function

Function TOKCOL_RelativeVelocityX#(bank,index)
Return PeekFloat(bank,index*104+80)
End Function

Function TOKCOL_RelativeVelocityY#(bank,index)
Return PeekFloat(bank,index*104+84)
End Function

Function TOKCOL_RelativeVelocityZ#(bank,index)
Return PeekFloat(bank,index*104+88)
End Function

Function TOKCOL_CollisionNormalX#(bank,index)
Return PeekFloat(bank,index*104+92)
End Function

Function TOKCOL_CollisionNormalY#(bank,index)
Return PeekFloat(bank,index*104+96)
End Function

Function TOKCOL_CollisionNormalZ#(bank,index)
Return PeekFloat(bank,index*104+100)
End Function