Pub.ColDet is now available

BlitzMax Forums/BlitzMax Programming/Pub.ColDet is now available

gman(Posted 2006) [#1]
Pub.ColDet is now available at:

Pub.ColDet Forum

Samples for MiniB3D are soon to follow.


GfK(Posted 2006) [#2]
Erm.... what is it?

Info? Screenshots?


Dreamora(Posted 2006) [#3]
ColDet (at least the B3D version) creates collision volumes for models to use for physics and general collision checks.


Tom(Posted 2006) [#4]
gman:

<NoelCower> I need someone to do something for me, and it's very important
<NoelCower> Post on bb.com telling gman that his coldet module requires all code that uses it to be open source
<NoelCower> Due to the viral nature of the LGPL when using static linking
<NoelCower> In short, he's statically linking to LGPL'd source code when he has to make an import library that makes use of a DLL
<NoelCower> Otherwise people have to release any and all code using the module
<NoelCower> Under the LGPL no less


gman(Posted 2006) [#5]
thx tom (and Noel). ill get it into a DLL this evening.


Kev(Posted 2006) [#6]
thanks gman, MiniB3D and now this what more can we ask.

kev


gman(Posted 2006) [#7]
you are very welcome :) i will release some bindings for MiniB3D probably not tonight now that i need to build a DLL, but hopefully sunday sometime. tomorrow is one of my daughters B-Day so PC is off limits :)


gman(Posted 2006) [#8]
UPDATE: the download is now a DLL based mod. hopefully can get my MiniB3D bindings out tonight with an example.


simonh(Posted 2006) [#9]
Excellent work gman. Looking forward to giving this a go.


gman(Posted 2006) [#10]
this is just an initial design, but it shows some of the possibilities. this builds off the animator MiniB3D addition i posted earlier. again no modifications to MiniB3D. save this to a file called animator.bmx in the same directory as MiniB3D.bmx.
Import "MiniB3D.bmx"
Import Pub.ColDet

' animator.bmx
Type IEntityAnimator Extends TMesh
	Const ORDER_BASE:Int=999999
	
	Method Update()
		Local entity:TEntity=GetParent()
		If entity Then AnimateEntity(entity,MilliSecs()) Else DebugLog("IEntityAnimator: No Entity")
	EndMethod

	' called each update to animate an entity	
	Method AnimateEntity(entity:TEntity,timeMS:Int) Abstract
EndType


Type TColDetCollisionAdapter Extends ICollisionAdapter
	Field model:TCollisionModel3D=Null
	
	Method New()
		model=New TCollisionModel3D
	EndMethod

	Function EntityAddAdapter(entity:TEntity,order:Int=0)		
		Local coll:TColDetCollisionAdapter=TColDetCollisionAdapter.Create(entity)
		' set the order so the animator update is called before the update to the entity
		EntityOrder(coll,(ORDER_BASE-order)) 
	EndFunction
	
	Function create:TColDetCollisionAdapter(parent_ent:TEntity)
		If Not TMesh(parent_ent) Then RuntimeError "TColDetCollisionAdapter.create(): invalid entity passed"
		
		Local coll:TColDetCollisionAdapter=New TColDetCollisionAdapter
		coll.class$="TColDetCollisionAdapter"
		
		coll.AddParent(parent_ent)
		coll.EntityListAdd(entity_list)
		' update matrix
		If coll.parent<>Null
			coll.mat.Overwrite(coll.parent.mat)
			coll.UpdateMat()
		Else
			coll.UpdateMat(True)
		EndIf
		
		' populate the collision model with triangles
		coll.FillCollisionModel()
		
		Return coll
	EndFunction	
	
	' populates the collision model with the mesh triangles
	Method FillCollisionModel()
		Local entity:TMesh=TMesh(getParent())

		' loop through each surface		
		For Local s:Int=1 To entity.CountSurfaces()
			
			Local surf:TSurface=entity.GetSurface(s)
			
			' loop through each triangle of the surface
			For Local t:Int=1 To surf.CountTriangles()

				' add each triangle to the collision model
				model.addTriangle( ..
					surf.VertexX(surf.TriangleVertex(t,0)), ..
					surf.VertexY(surf.TriangleVertex(t,0)), ..
					surf.VertexZ(surf.TriangleVertex(t,0)), ..
					surf.VertexX(surf.TriangleVertex(t,1)), ..
					surf.VertexY(surf.TriangleVertex(t,1)), ..
					surf.VertexZ(surf.TriangleVertex(t,1)), ..
					surf.VertexX(surf.TriangleVertex(t,2)), ..
					surf.VertexY(surf.TriangleVertex(t,2)), ..
					surf.VertexZ(surf.TriangleVertex(t,2)))					
			Next							
		Next
		
		' finalize the model
		model.finalize()
	EndMethod

	Method OnUpdate(entity:TEntity)
		' check for a collision
		For Local mesh:TEntity=EachIn TEntity.entity_list
			If mesh<>Self And mesh.class="TColDetCollisionAdapter"
				If model.Collision(TColDetCollisionAdapter(mesh).model)					
					DebugLog(MilliSecs()+": "+entity.EntityName()+" hit "+mesh.getParent().EntityName())
				EndIf
			EndIf
		Next
	EndMethod

	' because this is a child, this gets called every time the parent is updated	
	Method OnUpdateMat(entity:TEntity)
		' update the model transformation with the parents matrix
		model.setTransform(entity.mat.grid)		
	EndMethod
	
	' 
	Method OnFreeEntity(entity:TEntity)
	EndMethod
EndType

' collision adapter for entity
' this is meant to store/update collision info for an entity and also to 
' allow cleanup via the free entity
' needs to fire after the animators but before the entitys so ORDER_BASE is 10000 lower
Type ICollisionAdapter Extends TMesh

	Const ORDER_BASE:Int=989999

	Method Update()
		Local entity:TEntity=GetParent()
		If entity Then OnUpdate(entity) Else DebugLog("ICollisionAdapter: No Entity")
	EndMethod
	Method UpdateMat(load_identity:Int=False)
		Local entity:TEntity=GetParent()
		If entity Then OnUpdateMat(entity) Else DebugLog("ICollisionAdapter: No Entity")
	EndMethod
	Method FreeEntity()
		Local entity:TEntity=GetParent()
		If entity Then OnFreeEntity(entity) Else DebugLog("ICollisionAdapter: No Entity")
	EndMethod
	
	Method OnUpdate(entity:TEntity) Abstract
	' this updates when the entity updates
	Method OnUpdateMat(entity:TEntity) Abstract
	Method OnFreeEntity(entity:TEntity) Abstract
EndType

now for an implementation. again, this is based on the MiniB3D test-alpha.bmx program. save the following code into test-alpha_anim.bmx in the same directory as test-alpha.bmx
Import "../MiniB3D.bmx"
Import BRL.PNGLoader
Import "../animator.bmx"

Local width=640,height=480,depth=16,mode=0

Graphics3D width,height,depth,mode

Local cam=CreateCamera()
Local light=CreateLight()

Local ent1=CreateCube()

Local tex=LoadTexture("media/test.png")
EntityTexture ent1,tex

Local ent2=CopyEntity(ent1)
Local ent3=CopyEntity(ent1)
Local ent4=CopyEntity(ent1)
Local ent5=CopyEntity(ent1)
Local ent6=CopyEntity(ent1)

' -----------------------------
' add a controller to the cam.  this could just as easily
' be added to one of the cubes
' -----------------------------
TCameraController.EntityAddAnimator(cam,0)
' -----------------------------

' -----------------------------
' create simple rotation animators and add them to 
' ents 1-4
' -----------------------------
TSimpleRotateAnimator.EntityAddAnimator(ent1,.5)
TSimpleRotateAnimator.EntityAddAnimator(ent2,-.5)
TSimpleRotateAnimator.EntityAddAnimator(ent3,1)
TSimpleRotateAnimator.EntityAddAnimator(ent4,-1)

NameEntity(ent1,"ent1")
NameEntity(ent2,"ent2")
NameEntity(ent3,"ent3")
NameEntity(ent4,"ent4")
NameEntity(ent5,"ent5")
NameEntity(ent6,"ent6")

' add some collision detection to all the boxes
TColDetCollisionAdapter.EntityAddAdapter(ent1)
TColDetCollisionAdapter.EntityAddAdapter(ent2)
TColDetCollisionAdapter.EntityAddAdapter(ent3)
TColDetCollisionAdapter.EntityAddAdapter(ent4)
TColDetCollisionAdapter.EntityAddAdapter(ent5)
TColDetCollisionAdapter.EntityAddAdapter(ent6)

' -----------------------------

PositionEntity ent1,0,0,10
PositionEntity ent2,0,0,5
PositionEntity ent3,0,0,20
PositionEntity ent4,0,0,15
PositionEntity ent5,0,0,30
PositionEntity ent6,0,0,25

EntityAlpha ent2,0.5
EntityAlpha ent4,0.5

Local cx#=0
Local cy#=0
Local cz#=0

Local pitch#=0
Local yaw#=0
Local roll#=0

' used by fps code
Local old_ms=MilliSecs()
Local renders
Local fps

While Not KeyDown(KEY_ESCAPE)		

	If KeyHit(KEY_ENTER) Then DebugStop

	RenderWorld
	renders=renders+1
	
	' calculate fps
	If MilliSecs()-old_ms>=1000
		old_ms=MilliSecs()
		fps=renders
		renders=0
	EndIf
	
	GLDrawText "FPS: "+String(fps),0,0

	PositionEntity(ent2,0,0,EntityZ(ent2)+.01)

	Flip
' problem with freeentity
'FreeEntity(ent6)
Wend
End



' -----------------------------
' begin the animator types
' -----------------------------

' conrols a camera (or potentially any entity) via keyboard
' arrows UP/DOWN/LEFT/RIGHT and keys W/A/S/D
Type TCameraController Extends IEntityAnimator

	Field cx#=0
	Field cy#=0
	Field cz#=0

	Field pitch#=0
	Field yaw#=0
	Field roll#=0
		
	Method AnimateEntity(entity:TEntity,timeMS:Int)
		' control camera	
		If KeyDown(KEY_UP) Then cz#=cz#+1.0
		If KeyDown(KEY_LEFT) Then cx#=cx#-1.0
		If KeyDown(KEY_RIGHT) Then cx#=cx#+1.0
		If KeyDown(KEY_DOWN) Then cz#=cz#-1.0
		
		If KeyDown(KEY_W) Then pitch#=pitch#-1.0
		If KeyDown(KEY_A) Then yaw#=yaw#+1.0
		If KeyDown(KEY_S) Then pitch#=pitch#+1.0
		If KeyDown(KEY_D) Then yaw#=yaw#-1.0
	
		entity.MoveEntity(cx#*0.5,cy#*0.5,cz#*0.5)
		entity.RotateEntity(pitch#,yaw#,roll#)

		cx#=0
		cy#=0
		cz#=0
	EndMethod	
	
	Function EntityAddAnimator(entity:TEntity,order:Int=0)		
		Local anim:TCameraController=TCameraController.Create(entity)
		' set the order so the animator update is called before the update to the entity
		EntityOrder(anim,(ORDER_BASE-order)) 
	EndFunction
	
	Function create:TCameraController(parent_ent:TEntity)
		Local piv:TCameraController=New TCameraController
		piv.class$="TCameraController"
		
		piv.AddParent(parent_ent)
		piv.EntityListAdd(entity_list)
		' update matrix
		If piv.parent<>Null
			piv.mat.Overwrite(piv.parent.mat)
			piv.UpdateMat()
		Else
			piv.UpdateMat(True)
		EndIf
		Return piv
	EndFunction	
EndType

Type TSimpleRotateAnimator Extends IEntityAnimator

	Field rate:Float

	Method AnimateEntity(entity:TEntity,timeMS:Int)
		entity.TurnEntity(0,rate,0)
	EndMethod
	
	Function EntityAddAnimator(entity:TEntity,rate:Float,order:Int=0)		
		Local anim:TSimpleRotateAnimator=TSimpleRotateAnimator.Create(entity)
		anim.rate=rate
		' set the order so the animator update is called before the update to the entity
		EntityOrder(anim,(ORDER_BASE-order)) 
	EndFunction
	
	Function create:TSimpleRotateAnimator(parent_ent:TEntity)
		Local piv:TSimpleRotateAnimator=New TSimpleRotateAnimator
		piv.class$="TSimpleRotateAnimator"
		
		piv.AddParent(parent_ent)
		piv.EntityListAdd(entity_list)
		' update matrix
		If piv.parent<>Null
			piv.mat.Overwrite(piv.parent.mat)
			piv.UpdateMat()
		Else
			piv.UpdateMat(True)
		EndIf
		Return piv
	EndFunction
EndType

' -----------------------------
' -----------------------------

in the animator.bmx code, there are two new types, one is a interface type meant to be extended. ICollisionAdapter provides a means to store the collision data with the mesh. due to it being an actual child of the mesh, when the parents matrix is updated so is the childs. i use this to create an event. the implementation uses this event to update the model collision transformation.

the second type is the implementation of ICollisionAdapter i called TColDetCollisionAdapter. it acutally implements the creation of the collision data, the updating of the collision matrix, and the checking for a collision.

NOTE: be sure to run this in debug mode. 2 reasons, first, for some reason you will get an unhandle mem error at the first collision. im not sure why but im waiting till the next version of MiniB3D to check it out. ive manually tested outside of MiniB3D and it seems to work fine in debug or runtime. second, you will see the debug output when the collisions occur. you will see the millisecs, followed by the names of the two entities that collided.

this is very basic stuff but it does show a simple collision detection implementation.

enjoy :)

one more time, a big THANK YOU to simonh. cant wait for v0.3!


JoshK(Posted 2008) [#11]
Would it be possible to produce a version of your ColDet module that does not require a dll? I try to avoid using dlls whenever possible, as they always have potential for causing problems when the program is terminated, and they are a nuisance to have to include with my engine.


plash(Posted 2008) [#12]
Would it be possible to produce a version of your ColDet module that does not require a dll?
Uh...
<NoelCower> I need someone to do something for me, and it's very important
<NoelCower> Post on bb.com telling gman that his coldet module requires all code that uses it to be open source
<NoelCower> Due to the viral nature of the LGPL when using static linking
<NoelCower> In short, he's statically linking to LGPL'd source code when he has to make an import library that makes use of a DLL
<NoelCower> Otherwise people have to release any and all code using the module
<NoelCower> Under the LGPL no less
No?

Unless Leadwerks Engine goes open source ;)


JoshK(Posted 2008) [#13]
The author will probably give me permission to statically link it if I explain it to them.

I have the Newton version and the ColDet version implemented side by side. But ColDet doesn't work. Here I am trying to perform a raycast between point 0 and point 1. The parameters for the raycast method are very confusing. I don't know if the direction is supposed to be normalized or what:
	Method ColDetRayCast:Int(p0:TVec3,p1:TVec3,position:TVec3,normal:TVec3,radius:Float=0.0,closest=True)
		Global direction:Float[3]
		If Not collisionmodel Return
		direction[0]=p1.x-p0.x
		direction[1]=p1.y-p0.y
		direction[2]=p1.z-p0.z
		Local m#=NormalizeVec3(direction,direction)
		If collisionmodel.rayCollision:Int(Varptr p0.x,direction,closest,0,m)
			collisionmodel.getCollisionPoint(Varptr position.x)
			Notify position.tostring()
			Return 1
		Else
			Return 0
		EndIf
	EndMethod



JoshK(Posted 2008) [#14]
I got coldet working right, but it treats triangles as if they are two-sided. Is there a way to disable this?


Chroma(Posted 2008) [#15]
Maybe try the coldet forums.


JoshK(Posted 2008) [#16]
They are defunct.