forked from LeenkxTeam/LNXSDK
		
	
		
			
	
	
		
			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
 |