320 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			320 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Bullet Continuous Collision Detection and Physics Library
							 | 
						||
| 
								 | 
							
								Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This software is provided 'as-is', without any express or implied warranty.
							 | 
						||
| 
								 | 
							
								In no event will the authors be held liable for any damages arising from the use of this software.
							 | 
						||
| 
								 | 
							
								Permission is granted to anyone to use this software for any purpose,
							 | 
						||
| 
								 | 
							
								including commercial applications, and to alter it and redistribute it freely,
							 | 
						||
| 
								 | 
							
								subject to the following restrictions:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
							 | 
						||
| 
								 | 
							
								2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
							 | 
						||
| 
								 | 
							
								3. This notice may not be removed or altered from any source distribution.
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								///btSparseSdf implementation by Nathanael Presson
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifndef BT_SPARSE_SDF_H
							 | 
						||
| 
								 | 
							
								#define BT_SPARSE_SDF_H
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
							 | 
						||
| 
								 | 
							
								#include "BulletCollision/NarrowPhaseCollision/btGjkEpa2.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Modified Paul Hsieh hash
							 | 
						||
| 
								 | 
							
								template <const int DWORDLEN>
							 | 
						||
| 
								 | 
							
								unsigned int HsiehHash(const void* pdata)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									const unsigned short*	data=(const unsigned short*)pdata;
							 | 
						||
| 
								 | 
							
									unsigned				hash=DWORDLEN<<2,tmp;
							 | 
						||
| 
								 | 
							
									for(int i=0;i<DWORDLEN;++i)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										hash	+=	data[0];
							 | 
						||
| 
								 | 
							
										tmp		=	(data[1]<<11)^hash;
							 | 
						||
| 
								 | 
							
										hash	=	(hash<<16)^tmp;
							 | 
						||
| 
								 | 
							
										data	+=	2;
							 | 
						||
| 
								 | 
							
										hash	+=	hash>>11;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									hash^=hash<<3;hash+=hash>>5;
							 | 
						||
| 
								 | 
							
									hash^=hash<<4;hash+=hash>>17;
							 | 
						||
| 
								 | 
							
									hash^=hash<<25;hash+=hash>>6;
							 | 
						||
| 
								 | 
							
									return(hash);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								template <const int CELLSIZE>
							 | 
						||
| 
								 | 
							
								struct	btSparseSdf
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									//
							 | 
						||
| 
								 | 
							
									// Inner types
							 | 
						||
| 
								 | 
							
									//
							 | 
						||
| 
								 | 
							
									struct IntFrac
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										int					b;
							 | 
						||
| 
								 | 
							
										int					i;
							 | 
						||
| 
								 | 
							
										btScalar			f;
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									struct	Cell
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										btScalar			d[CELLSIZE+1][CELLSIZE+1][CELLSIZE+1];
							 | 
						||
| 
								 | 
							
										int					c[3];
							 | 
						||
| 
								 | 
							
										int					puid;
							 | 
						||
| 
								 | 
							
										unsigned			hash;
							 | 
						||
| 
								 | 
							
										const btCollisionShape*	pclient;
							 | 
						||
| 
								 | 
							
										Cell*				next;
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									//
							 | 
						||
| 
								 | 
							
									// Fields
							 | 
						||
| 
								 | 
							
									//
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									btAlignedObjectArray<Cell*>		cells;	
							 | 
						||
| 
								 | 
							
									btScalar						voxelsz;
							 | 
						||
| 
								 | 
							
									int								puid;
							 | 
						||
| 
								 | 
							
									int								ncells;
							 | 
						||
| 
								 | 
							
									int								m_clampCells;
							 | 
						||
| 
								 | 
							
									int								nprobes;
							 | 
						||
| 
								 | 
							
									int								nqueries;	
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									//
							 | 
						||
| 
								 | 
							
									// Methods
							 | 
						||
| 
								 | 
							
									//
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									//
							 | 
						||
| 
								 | 
							
									void					Initialize(int hashsize=2383, int clampCells = 256*1024)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										//avoid a crash due to running out of memory, so clamp the maximum number of cells allocated
							 | 
						||
| 
								 | 
							
										//if this limit is reached, the SDF is reset (at the cost of some performance during the reset)
							 | 
						||
| 
								 | 
							
										m_clampCells = clampCells;
							 | 
						||
| 
								 | 
							
										cells.resize(hashsize,0);
							 | 
						||
| 
								 | 
							
										Reset();
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									//
							 | 
						||
| 
								 | 
							
									void					Reset()
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										for(int i=0,ni=cells.size();i<ni;++i)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											Cell*	pc=cells[i];
							 | 
						||
| 
								 | 
							
											cells[i]=0;
							 | 
						||
| 
								 | 
							
											while(pc)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												Cell*	pn=pc->next;
							 | 
						||
| 
								 | 
							
												delete pc;
							 | 
						||
| 
								 | 
							
												pc=pn;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										voxelsz		=0.25;
							 | 
						||
| 
								 | 
							
										puid		=0;
							 | 
						||
| 
								 | 
							
										ncells		=0;
							 | 
						||
| 
								 | 
							
										nprobes		=1;
							 | 
						||
| 
								 | 
							
										nqueries	=1;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									//
							 | 
						||
| 
								 | 
							
									void					GarbageCollect(int lifetime=256)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										const int life=puid-lifetime;
							 | 
						||
| 
								 | 
							
										for(int i=0;i<cells.size();++i)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											Cell*&	root=cells[i];
							 | 
						||
| 
								 | 
							
											Cell*	pp=0;
							 | 
						||
| 
								 | 
							
											Cell*	pc=root;
							 | 
						||
| 
								 | 
							
											while(pc)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												Cell*	pn=pc->next;
							 | 
						||
| 
								 | 
							
												if(pc->puid<life)
							 | 
						||
| 
								 | 
							
												{
							 | 
						||
| 
								 | 
							
													if(pp) pp->next=pn; else root=pn;
							 | 
						||
| 
								 | 
							
													delete pc;pc=pp;--ncells;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												pp=pc;pc=pn;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										//printf("GC[%d]: %d cells, PpQ: %f\r\n",puid,ncells,nprobes/(btScalar)nqueries);
							 | 
						||
| 
								 | 
							
										nqueries=1;
							 | 
						||
| 
								 | 
							
										nprobes=1;
							 | 
						||
| 
								 | 
							
										++puid;	///@todo: Reset puid's when int range limit is reached	*/ 
							 | 
						||
| 
								 | 
							
										/* else setup a priority list...						*/ 
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									//
							 | 
						||
| 
								 | 
							
									int						RemoveReferences(btCollisionShape* pcs)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										int	refcount=0;
							 | 
						||
| 
								 | 
							
										for(int i=0;i<cells.size();++i)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											Cell*&	root=cells[i];
							 | 
						||
| 
								 | 
							
											Cell*	pp=0;
							 | 
						||
| 
								 | 
							
											Cell*	pc=root;
							 | 
						||
| 
								 | 
							
											while(pc)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												Cell*	pn=pc->next;
							 | 
						||
| 
								 | 
							
												if(pc->pclient==pcs)
							 | 
						||
| 
								 | 
							
												{
							 | 
						||
| 
								 | 
							
													if(pp) pp->next=pn; else root=pn;
							 | 
						||
| 
								 | 
							
													delete pc;pc=pp;++refcount;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												pp=pc;pc=pn;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										return(refcount);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									//
							 | 
						||
| 
								 | 
							
									btScalar				Evaluate(	const btVector3& x,
							 | 
						||
| 
								 | 
							
										const btCollisionShape* shape,
							 | 
						||
| 
								 | 
							
										btVector3& normal,
							 | 
						||
| 
								 | 
							
										btScalar margin)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										/* Lookup cell			*/ 
							 | 
						||
| 
								 | 
							
										const btVector3	scx=x/voxelsz;
							 | 
						||
| 
								 | 
							
										const IntFrac	ix=Decompose(scx.x());
							 | 
						||
| 
								 | 
							
										const IntFrac	iy=Decompose(scx.y());
							 | 
						||
| 
								 | 
							
										const IntFrac	iz=Decompose(scx.z());
							 | 
						||
| 
								 | 
							
										const unsigned	h=Hash(ix.b,iy.b,iz.b,shape);
							 | 
						||
| 
								 | 
							
										Cell*&			root=cells[static_cast<int>(h%cells.size())];
							 | 
						||
| 
								 | 
							
										Cell*			c=root;
							 | 
						||
| 
								 | 
							
										++nqueries;
							 | 
						||
| 
								 | 
							
										while(c)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											++nprobes;
							 | 
						||
| 
								 | 
							
											if(	(c->hash==h)	&&
							 | 
						||
| 
								 | 
							
												(c->c[0]==ix.b)	&&
							 | 
						||
| 
								 | 
							
												(c->c[1]==iy.b)	&&
							 | 
						||
| 
								 | 
							
												(c->c[2]==iz.b)	&&
							 | 
						||
| 
								 | 
							
												(c->pclient==shape))
							 | 
						||
| 
								 | 
							
											{ break; }
							 | 
						||
| 
								 | 
							
											else
							 | 
						||
| 
								 | 
							
											{ c=c->next; }
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if(!c)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											++nprobes;		
							 | 
						||
| 
								 | 
							
											++ncells;
							 | 
						||
| 
								 | 
							
											//int sz = sizeof(Cell);
							 | 
						||
| 
								 | 
							
											if (ncells>m_clampCells)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												static int numResets=0;
							 | 
						||
| 
								 | 
							
												numResets++;
							 | 
						||
| 
								 | 
							
								//				printf("numResets=%d\n",numResets);
							 | 
						||
| 
								 | 
							
												Reset();
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											c=new Cell();
							 | 
						||
| 
								 | 
							
											c->next=root;root=c;
							 | 
						||
| 
								 | 
							
											c->pclient=shape;
							 | 
						||
| 
								 | 
							
											c->hash=h;
							 | 
						||
| 
								 | 
							
											c->c[0]=ix.b;c->c[1]=iy.b;c->c[2]=iz.b;
							 | 
						||
| 
								 | 
							
											BuildCell(*c);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										c->puid=puid;
							 | 
						||
| 
								 | 
							
										/* Extract infos		*/ 
							 | 
						||
| 
								 | 
							
										const int		o[]={	ix.i,iy.i,iz.i};
							 | 
						||
| 
								 | 
							
										const btScalar	d[]={	c->d[o[0]+0][o[1]+0][o[2]+0],
							 | 
						||
| 
								 | 
							
											c->d[o[0]+1][o[1]+0][o[2]+0],
							 | 
						||
| 
								 | 
							
											c->d[o[0]+1][o[1]+1][o[2]+0],
							 | 
						||
| 
								 | 
							
											c->d[o[0]+0][o[1]+1][o[2]+0],
							 | 
						||
| 
								 | 
							
											c->d[o[0]+0][o[1]+0][o[2]+1],
							 | 
						||
| 
								 | 
							
											c->d[o[0]+1][o[1]+0][o[2]+1],
							 | 
						||
| 
								 | 
							
											c->d[o[0]+1][o[1]+1][o[2]+1],
							 | 
						||
| 
								 | 
							
											c->d[o[0]+0][o[1]+1][o[2]+1]};
							 | 
						||
| 
								 | 
							
										/* Normal	*/ 
							 | 
						||
| 
								 | 
							
								#if 1
							 | 
						||
| 
								 | 
							
										const btScalar	gx[]={	d[1]-d[0],d[2]-d[3],
							 | 
						||
| 
								 | 
							
											d[5]-d[4],d[6]-d[7]};
							 | 
						||
| 
								 | 
							
										const btScalar	gy[]={	d[3]-d[0],d[2]-d[1],
							 | 
						||
| 
								 | 
							
											d[7]-d[4],d[6]-d[5]};
							 | 
						||
| 
								 | 
							
										const btScalar	gz[]={	d[4]-d[0],d[5]-d[1],
							 | 
						||
| 
								 | 
							
											d[7]-d[3],d[6]-d[2]};
							 | 
						||
| 
								 | 
							
										normal.setX(Lerp(	Lerp(gx[0],gx[1],iy.f),
							 | 
						||
| 
								 | 
							
											Lerp(gx[2],gx[3],iy.f),iz.f));
							 | 
						||
| 
								 | 
							
										normal.setY(Lerp(	Lerp(gy[0],gy[1],ix.f),
							 | 
						||
| 
								 | 
							
											Lerp(gy[2],gy[3],ix.f),iz.f));
							 | 
						||
| 
								 | 
							
										normal.setZ(Lerp(	Lerp(gz[0],gz[1],ix.f),
							 | 
						||
| 
								 | 
							
											Lerp(gz[2],gz[3],ix.f),iy.f));
							 | 
						||
| 
								 | 
							
										normal		=	normal.normalized();
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
										normal		=	btVector3(d[1]-d[0],d[3]-d[0],d[4]-d[0]).normalized();
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
										/* Distance	*/ 
							 | 
						||
| 
								 | 
							
										const btScalar	d0=Lerp(Lerp(d[0],d[1],ix.f),
							 | 
						||
| 
								 | 
							
											Lerp(d[3],d[2],ix.f),iy.f);
							 | 
						||
| 
								 | 
							
										const btScalar	d1=Lerp(Lerp(d[4],d[5],ix.f),
							 | 
						||
| 
								 | 
							
											Lerp(d[7],d[6],ix.f),iy.f);
							 | 
						||
| 
								 | 
							
										return(Lerp(d0,d1,iz.f)-margin);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									//
							 | 
						||
| 
								 | 
							
									void					BuildCell(Cell& c)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										const btVector3	org=btVector3(	(btScalar)c.c[0],
							 | 
						||
| 
								 | 
							
											(btScalar)c.c[1],
							 | 
						||
| 
								 | 
							
											(btScalar)c.c[2])	*
							 | 
						||
| 
								 | 
							
											CELLSIZE*voxelsz;
							 | 
						||
| 
								 | 
							
										for(int k=0;k<=CELLSIZE;++k)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											const btScalar	z=voxelsz*k+org.z();
							 | 
						||
| 
								 | 
							
											for(int j=0;j<=CELLSIZE;++j)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												const btScalar	y=voxelsz*j+org.y();
							 | 
						||
| 
								 | 
							
												for(int i=0;i<=CELLSIZE;++i)
							 | 
						||
| 
								 | 
							
												{
							 | 
						||
| 
								 | 
							
													const btScalar	x=voxelsz*i+org.x();
							 | 
						||
| 
								 | 
							
													c.d[i][j][k]=DistanceToShape(	btVector3(x,y,z),
							 | 
						||
| 
								 | 
							
														c.pclient);
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									//
							 | 
						||
| 
								 | 
							
									static inline btScalar	DistanceToShape(const btVector3& x,
							 | 
						||
| 
								 | 
							
										const btCollisionShape* shape)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										btTransform	unit;
							 | 
						||
| 
								 | 
							
										unit.setIdentity();
							 | 
						||
| 
								 | 
							
										if(shape->isConvex())
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											btGjkEpaSolver2::sResults	res;
							 | 
						||
| 
								 | 
							
											const btConvexShape*				csh=static_cast<const btConvexShape*>(shape);
							 | 
						||
| 
								 | 
							
											return(btGjkEpaSolver2::SignedDistance(x,0,csh,unit,res));
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										return(0);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									//
							 | 
						||
| 
								 | 
							
									static inline IntFrac	Decompose(btScalar x)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										/* That one need a lot of improvements...	*/
							 | 
						||
| 
								 | 
							
										/* Remove test, faster floor...				*/ 
							 | 
						||
| 
								 | 
							
										IntFrac			r;
							 | 
						||
| 
								 | 
							
										x/=CELLSIZE;
							 | 
						||
| 
								 | 
							
										const int		o=x<0?(int)(-x+1):0;
							 | 
						||
| 
								 | 
							
										x+=o;r.b=(int)x;
							 | 
						||
| 
								 | 
							
										const btScalar	k=(x-r.b)*CELLSIZE;
							 | 
						||
| 
								 | 
							
										r.i=(int)k;r.f=k-r.i;r.b-=o;
							 | 
						||
| 
								 | 
							
										return(r);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									//
							 | 
						||
| 
								 | 
							
									static inline btScalar	Lerp(btScalar a,btScalar b,btScalar t)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										return(a+(b-a)*t);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									//
							 | 
						||
| 
								 | 
							
									static inline unsigned int	Hash(int x,int y,int z,const btCollisionShape* shape)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										struct btS
							 | 
						||
| 
								 | 
							
										{ 
							 | 
						||
| 
								 | 
							
											int x,y,z;
							 | 
						||
| 
								 | 
							
											void* p;
							 | 
						||
| 
								 | 
							
										};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										btS myset;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										myset.x=x;myset.y=y;myset.z=z;myset.p=(void*)shape;
							 | 
						||
| 
								 | 
							
										const void* ptr = &myset;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										unsigned int result = HsiehHash<sizeof(btS)/4> (ptr);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return result;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#endif //BT_SPARSE_SDF_H
							 |