1344 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1344 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
| Bullet Continuous Collision Detection and Physics Library
 | |
| Copyright (c) 2003-2007 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.
 | |
| */
 | |
| ///btDbvt implementation by Nathanael Presson
 | |
| 
 | |
| #ifndef BT_DYNAMIC_BOUNDING_VOLUME_TREE_H
 | |
| #define BT_DYNAMIC_BOUNDING_VOLUME_TREE_H
 | |
| 
 | |
| #include "LinearMath/btAlignedObjectArray.h"
 | |
| #include "LinearMath/btVector3.h"
 | |
| #include "LinearMath/btTransform.h"
 | |
| #include "LinearMath/btAabbUtil2.h"
 | |
| 
 | |
| //
 | |
| // Compile time configuration
 | |
| //
 | |
| 
 | |
| 
 | |
| // Implementation profiles
 | |
| #define DBVT_IMPL_GENERIC		0	// Generic implementation	
 | |
| #define DBVT_IMPL_SSE			1	// SSE
 | |
| 
 | |
| // Template implementation of ICollide
 | |
| #ifdef _WIN32
 | |
| #if (defined (_MSC_VER) && _MSC_VER >= 1400)
 | |
| #define	DBVT_USE_TEMPLATE		1
 | |
| #else
 | |
| #define	DBVT_USE_TEMPLATE		0
 | |
| #endif
 | |
| #else
 | |
| #define	DBVT_USE_TEMPLATE		0
 | |
| #endif
 | |
| 
 | |
| // Use only intrinsics instead of inline asm
 | |
| #define DBVT_USE_INTRINSIC_SSE	1
 | |
| 
 | |
| // Using memmov for collideOCL
 | |
| #define DBVT_USE_MEMMOVE		1
 | |
| 
 | |
| // Enable benchmarking code
 | |
| #define	DBVT_ENABLE_BENCHMARK	0
 | |
| 
 | |
| // Inlining
 | |
| #define DBVT_INLINE				SIMD_FORCE_INLINE
 | |
| 
 | |
| // Specific methods implementation
 | |
| 
 | |
| //SSE gives errors on a MSVC 7.1
 | |
| #if defined (BT_USE_SSE) //&& defined (_WIN32)
 | |
| #define DBVT_SELECT_IMPL		DBVT_IMPL_SSE
 | |
| #define DBVT_MERGE_IMPL			DBVT_IMPL_SSE
 | |
| #define DBVT_INT0_IMPL			DBVT_IMPL_SSE
 | |
| #else
 | |
| #define DBVT_SELECT_IMPL		DBVT_IMPL_GENERIC
 | |
| #define DBVT_MERGE_IMPL			DBVT_IMPL_GENERIC
 | |
| #define DBVT_INT0_IMPL			DBVT_IMPL_GENERIC
 | |
| #endif
 | |
| 
 | |
| #if	(DBVT_SELECT_IMPL==DBVT_IMPL_SSE)||	\
 | |
| 	(DBVT_MERGE_IMPL==DBVT_IMPL_SSE)||	\
 | |
| 	(DBVT_INT0_IMPL==DBVT_IMPL_SSE)
 | |
| #include <emmintrin.h>
 | |
| #endif
 | |
| 
 | |
| //
 | |
| // Auto config and checks
 | |
| //
 | |
| 
 | |
| #if DBVT_USE_TEMPLATE
 | |
| #define	DBVT_VIRTUAL
 | |
| #define DBVT_VIRTUAL_DTOR(a)
 | |
| #define DBVT_PREFIX					template <typename T>
 | |
| #define DBVT_IPOLICY				T& policy
 | |
| #define DBVT_CHECKTYPE				static const ICollide&	typechecker=*(T*)1;(void)typechecker;
 | |
| #else
 | |
| #define	DBVT_VIRTUAL_DTOR(a)		virtual ~a() {}
 | |
| #define DBVT_VIRTUAL				virtual
 | |
| #define DBVT_PREFIX
 | |
| #define DBVT_IPOLICY				ICollide& policy
 | |
| #define DBVT_CHECKTYPE
 | |
| #endif
 | |
| 
 | |
| #if DBVT_USE_MEMMOVE
 | |
| #if !defined( __CELLOS_LV2__) && !defined(__MWERKS__)
 | |
| #include <memory.h>
 | |
| #endif
 | |
| #include <string.h>
 | |
| #endif
 | |
| 
 | |
| #ifndef DBVT_USE_TEMPLATE
 | |
| #error "DBVT_USE_TEMPLATE undefined"
 | |
| #endif
 | |
| 
 | |
| #ifndef DBVT_USE_MEMMOVE
 | |
| #error "DBVT_USE_MEMMOVE undefined"
 | |
| #endif
 | |
| 
 | |
| #ifndef DBVT_ENABLE_BENCHMARK
 | |
| #error "DBVT_ENABLE_BENCHMARK undefined"
 | |
| #endif
 | |
| 
 | |
| #ifndef DBVT_SELECT_IMPL
 | |
| #error "DBVT_SELECT_IMPL undefined"
 | |
| #endif
 | |
| 
 | |
| #ifndef DBVT_MERGE_IMPL
 | |
| #error "DBVT_MERGE_IMPL undefined"
 | |
| #endif
 | |
| 
 | |
| #ifndef DBVT_INT0_IMPL
 | |
| #error "DBVT_INT0_IMPL undefined"
 | |
| #endif
 | |
| 
 | |
| 
 | |
| //
 | |
| // Defaults volumes
 | |
| //
 | |
| 
 | |
| /* btDbvtAabbMm			*/ 
 | |
| struct	btDbvtAabbMm
 | |
| {
 | |
| 	DBVT_INLINE btVector3			Center() const	{ return((mi+mx)/2); }
 | |
| 	DBVT_INLINE btVector3			Lengths() const	{ return(mx-mi); }
 | |
| 	DBVT_INLINE btVector3			Extents() const	{ return((mx-mi)/2); }
 | |
| 	DBVT_INLINE const btVector3&	Mins() const	{ return(mi); }
 | |
| 	DBVT_INLINE const btVector3&	Maxs() const	{ return(mx); }
 | |
| 	static inline btDbvtAabbMm		FromCE(const btVector3& c,const btVector3& e);
 | |
| 	static inline btDbvtAabbMm		FromCR(const btVector3& c,btScalar r);
 | |
| 	static inline btDbvtAabbMm		FromMM(const btVector3& mi,const btVector3& mx);
 | |
| 	static inline btDbvtAabbMm		FromPoints(const btVector3* pts,int n);
 | |
| 	static inline btDbvtAabbMm		FromPoints(const btVector3** ppts,int n);
 | |
| 	DBVT_INLINE void				Expand(const btVector3& e);
 | |
| 	DBVT_INLINE void				SignedExpand(const btVector3& e);
 | |
| 	DBVT_INLINE bool				Contain(const btDbvtAabbMm& a) const;
 | |
| 	DBVT_INLINE int					Classify(const btVector3& n,btScalar o,int s) const;
 | |
| 	DBVT_INLINE btScalar			ProjectMinimum(const btVector3& v,unsigned signs) const;
 | |
| 	DBVT_INLINE friend bool			Intersect(	const btDbvtAabbMm& a,
 | |
| 		const btDbvtAabbMm& b);
 | |
| 	
 | |
| 	DBVT_INLINE friend bool			Intersect(	const btDbvtAabbMm& a,
 | |
| 		const btVector3& b);
 | |
| 
 | |
| 	DBVT_INLINE friend btScalar		Proximity(	const btDbvtAabbMm& a,
 | |
| 		const btDbvtAabbMm& b);
 | |
| 	DBVT_INLINE friend int			Select(		const btDbvtAabbMm& o,
 | |
| 		const btDbvtAabbMm& a,
 | |
| 		const btDbvtAabbMm& b);
 | |
| 	DBVT_INLINE friend void			Merge(		const btDbvtAabbMm& a,
 | |
| 		const btDbvtAabbMm& b,
 | |
| 		btDbvtAabbMm& r);
 | |
| 	DBVT_INLINE friend bool			NotEqual(	const btDbvtAabbMm& a,
 | |
| 		const btDbvtAabbMm& b);
 | |
|     
 | |
|     DBVT_INLINE btVector3&	tMins()	{ return(mi); }
 | |
| 	DBVT_INLINE btVector3&	tMaxs()	{ return(mx); }
 | |
|     
 | |
| private:
 | |
| 	DBVT_INLINE void				AddSpan(const btVector3& d,btScalar& smi,btScalar& smx) const;
 | |
| private:
 | |
| 	btVector3	mi,mx;
 | |
| };
 | |
| 
 | |
| // Types	
 | |
| typedef	btDbvtAabbMm	btDbvtVolume;
 | |
| 
 | |
| /* btDbvtNode				*/ 
 | |
| struct	btDbvtNode
 | |
| {
 | |
| 	btDbvtVolume	volume;
 | |
| 	btDbvtNode*		parent;
 | |
| 	DBVT_INLINE bool	isleaf() const		{ return(childs[1]==0); }
 | |
| 	DBVT_INLINE bool	isinternal() const	{ return(!isleaf()); }
 | |
| 	union
 | |
| 	{
 | |
| 		btDbvtNode*	childs[2];
 | |
| 		void*	data;
 | |
| 		int		dataAsInt;
 | |
| 	};
 | |
| };
 | |
| 
 | |
| typedef btAlignedObjectArray<const btDbvtNode*> btNodeStack;
 | |
| 
 | |
| 
 | |
| ///The btDbvt class implements a fast dynamic bounding volume tree based on axis aligned bounding boxes (aabb tree).
 | |
| ///This btDbvt is used for soft body collision detection and for the btDbvtBroadphase. It has a fast insert, remove and update of nodes.
 | |
| ///Unlike the btQuantizedBvh, nodes can be dynamically moved around, which allows for change in topology of the underlying data structure.
 | |
| struct	btDbvt
 | |
| {
 | |
| 	/* Stack element	*/ 
 | |
| 	struct	sStkNN
 | |
| 	{
 | |
| 		const btDbvtNode*	a;
 | |
| 		const btDbvtNode*	b;
 | |
| 		sStkNN() {}
 | |
| 		sStkNN(const btDbvtNode* na,const btDbvtNode* nb) : a(na),b(nb) {}
 | |
| 	};
 | |
| 	struct	sStkNP
 | |
| 	{
 | |
| 		const btDbvtNode*	node;
 | |
| 		int			mask;
 | |
| 		sStkNP(const btDbvtNode* n,unsigned m) : node(n),mask(m) {}
 | |
| 	};
 | |
| 	struct	sStkNPS
 | |
| 	{
 | |
| 		const btDbvtNode*	node;
 | |
| 		int			mask;
 | |
| 		btScalar	value;
 | |
| 		sStkNPS() {}
 | |
| 		sStkNPS(const btDbvtNode* n,unsigned m,btScalar v) : node(n),mask(m),value(v) {}
 | |
| 	};
 | |
| 	struct	sStkCLN
 | |
| 	{
 | |
| 		const btDbvtNode*	node;
 | |
| 		btDbvtNode*		parent;
 | |
| 		sStkCLN(const btDbvtNode* n,btDbvtNode* p) : node(n),parent(p) {}
 | |
| 	};
 | |
| 	// Policies/Interfaces
 | |
| 
 | |
| 	/* ICollide	*/ 
 | |
| 	struct	ICollide
 | |
| 	{		
 | |
| 		DBVT_VIRTUAL_DTOR(ICollide)
 | |
| 			DBVT_VIRTUAL void	Process(const btDbvtNode*,const btDbvtNode*)		{}
 | |
| 		DBVT_VIRTUAL void	Process(const btDbvtNode*)					{}
 | |
| 		DBVT_VIRTUAL void	Process(const btDbvtNode* n,btScalar)			{ Process(n); }
 | |
| 		DBVT_VIRTUAL bool	Descent(const btDbvtNode*)					{ return(true); }
 | |
| 		DBVT_VIRTUAL bool	AllLeaves(const btDbvtNode*)					{ return(true); }
 | |
| 	};
 | |
| 	/* IWriter	*/ 
 | |
| 	struct	IWriter
 | |
| 	{
 | |
| 		virtual ~IWriter() {}
 | |
| 		virtual void		Prepare(const btDbvtNode* root,int numnodes)=0;
 | |
| 		virtual void		WriteNode(const btDbvtNode*,int index,int parent,int child0,int child1)=0;
 | |
| 		virtual void		WriteLeaf(const btDbvtNode*,int index,int parent)=0;
 | |
| 	};
 | |
| 	/* IClone	*/ 
 | |
| 	struct	IClone
 | |
| 	{
 | |
| 		virtual ~IClone()	{}
 | |
| 		virtual void		CloneLeaf(btDbvtNode*) {}
 | |
| 	};
 | |
| 
 | |
| 	// Constants
 | |
| 	enum	{
 | |
| 		SIMPLE_STACKSIZE	=	64,
 | |
| 		DOUBLE_STACKSIZE	=	SIMPLE_STACKSIZE*2
 | |
| 	};
 | |
| 
 | |
| 	// Fields
 | |
| 	btDbvtNode*		m_root;
 | |
| 	btDbvtNode*		m_free;
 | |
| 	int				m_lkhd;
 | |
| 	int				m_leaves;
 | |
| 	unsigned		m_opath;
 | |
| 
 | |
| 	
 | |
| 	btAlignedObjectArray<sStkNN>	m_stkStack;
 | |
| 
 | |
| 
 | |
| 	// Methods
 | |
| 	btDbvt();
 | |
| 	~btDbvt();
 | |
| 	void			clear();
 | |
| 	bool			empty() const { return(0==m_root); }
 | |
| 	void			optimizeBottomUp();
 | |
| 	void			optimizeTopDown(int bu_treshold=128);
 | |
| 	void			optimizeIncremental(int passes);
 | |
| 	btDbvtNode*		insert(const btDbvtVolume& box,void* data);
 | |
| 	void			update(btDbvtNode* leaf,int lookahead=-1);
 | |
| 	void			update(btDbvtNode* leaf,btDbvtVolume& volume);
 | |
| 	bool			update(btDbvtNode* leaf,btDbvtVolume& volume,const btVector3& velocity,btScalar margin);
 | |
| 	bool			update(btDbvtNode* leaf,btDbvtVolume& volume,const btVector3& velocity);
 | |
| 	bool			update(btDbvtNode* leaf,btDbvtVolume& volume,btScalar margin);	
 | |
| 	void			remove(btDbvtNode* leaf);
 | |
| 	void			write(IWriter* iwriter) const;
 | |
| 	void			clone(btDbvt& dest,IClone* iclone=0) const;
 | |
| 	static int		maxdepth(const btDbvtNode* node);
 | |
| 	static int		countLeaves(const btDbvtNode* node);
 | |
| 	static void		extractLeaves(const btDbvtNode* node,btAlignedObjectArray<const btDbvtNode*>& leaves);
 | |
| #if DBVT_ENABLE_BENCHMARK
 | |
| 	static void		benchmark();
 | |
| #else
 | |
| 	static void		benchmark(){}
 | |
| #endif
 | |
| 	// DBVT_IPOLICY must support ICollide policy/interface
 | |
| 	DBVT_PREFIX
 | |
| 		static void		enumNodes(	const btDbvtNode* root,
 | |
| 		DBVT_IPOLICY);
 | |
| 	DBVT_PREFIX
 | |
| 		static void		enumLeaves(	const btDbvtNode* root,
 | |
| 		DBVT_IPOLICY);
 | |
| 	DBVT_PREFIX
 | |
| 		void		collideTT(	const btDbvtNode* root0,
 | |
| 		const btDbvtNode* root1,
 | |
| 		DBVT_IPOLICY);
 | |
| 
 | |
| 	DBVT_PREFIX
 | |
| 		void		collideTTpersistentStack(	const btDbvtNode* root0,
 | |
| 		  const btDbvtNode* root1,
 | |
| 		  DBVT_IPOLICY);
 | |
| #if 0
 | |
| 	DBVT_PREFIX
 | |
| 		void		collideTT(	const btDbvtNode* root0,
 | |
| 		const btDbvtNode* root1,
 | |
| 		const btTransform& xform,
 | |
| 		DBVT_IPOLICY);
 | |
| 	DBVT_PREFIX
 | |
| 		void		collideTT(	const btDbvtNode* root0,
 | |
| 		const btTransform& xform0,
 | |
| 		const btDbvtNode* root1,
 | |
| 		const btTransform& xform1,
 | |
| 		DBVT_IPOLICY);
 | |
| #endif
 | |
| 
 | |
| 	DBVT_PREFIX
 | |
| 		void		collideTV(	const btDbvtNode* root,
 | |
| 		const btDbvtVolume& volume,
 | |
| 		DBVT_IPOLICY) const;
 | |
| 	
 | |
| 	DBVT_PREFIX
 | |
| 	void		collideTVNoStackAlloc(	const btDbvtNode* root,
 | |
| 						  const btDbvtVolume& volume,
 | |
| 						  btNodeStack& stack,
 | |
| 						  DBVT_IPOLICY) const;
 | |
| 	
 | |
| 	
 | |
| 	
 | |
| 	
 | |
| 	///rayTest is a re-entrant ray test, and can be called in parallel as long as the btAlignedAlloc is thread-safe (uses locking etc)
 | |
| 	///rayTest is slower than rayTestInternal, because it builds a local stack, using memory allocations, and it recomputes signs/rayDirectionInverses each time
 | |
| 	DBVT_PREFIX
 | |
| 		static void		rayTest(	const btDbvtNode* root,
 | |
| 		const btVector3& rayFrom,
 | |
| 		const btVector3& rayTo,
 | |
| 		DBVT_IPOLICY);
 | |
| 	///rayTestInternal is faster than rayTest, because it uses a persistent stack (to reduce dynamic memory allocations to a minimum) and it uses precomputed signs/rayInverseDirections
 | |
| 	///rayTestInternal is used by btDbvtBroadphase to accelerate world ray casts
 | |
| 	DBVT_PREFIX
 | |
| 		void		rayTestInternal(	const btDbvtNode* root,
 | |
| 								const btVector3& rayFrom,
 | |
| 								const btVector3& rayTo,
 | |
| 								const btVector3& rayDirectionInverse,
 | |
| 								unsigned int signs[3],
 | |
| 								btScalar lambda_max,
 | |
| 								const btVector3& aabbMin,
 | |
| 								const btVector3& aabbMax,
 | |
|                                 btAlignedObjectArray<const btDbvtNode*>& stack,
 | |
| 								DBVT_IPOLICY) const;
 | |
| 
 | |
| 	DBVT_PREFIX
 | |
| 		static void		collideKDOP(const btDbvtNode* root,
 | |
| 		const btVector3* normals,
 | |
| 		const btScalar* offsets,
 | |
| 		int count,
 | |
| 		DBVT_IPOLICY);
 | |
| 	DBVT_PREFIX
 | |
| 		static void		collideOCL(	const btDbvtNode* root,
 | |
| 		const btVector3* normals,
 | |
| 		const btScalar* offsets,
 | |
| 		const btVector3& sortaxis,
 | |
| 		int count,								
 | |
| 		DBVT_IPOLICY,
 | |
| 		bool fullsort=true);
 | |
| 	DBVT_PREFIX
 | |
| 		static void		collideTU(	const btDbvtNode* root,
 | |
| 		DBVT_IPOLICY);
 | |
| 	// Helpers	
 | |
| 	static DBVT_INLINE int	nearest(const int* i,const btDbvt::sStkNPS* a,btScalar v,int l,int h)
 | |
| 	{
 | |
| 		int	m=0;
 | |
| 		while(l<h)
 | |
| 		{
 | |
| 			m=(l+h)>>1;
 | |
| 			if(a[i[m]].value>=v) l=m+1; else h=m;
 | |
| 		}
 | |
| 		return(h);
 | |
| 	}
 | |
| 	static DBVT_INLINE int	allocate(	btAlignedObjectArray<int>& ifree,
 | |
| 		btAlignedObjectArray<sStkNPS>& stock,
 | |
| 		const sStkNPS& value)
 | |
| 	{
 | |
| 		int	i;
 | |
| 		if(ifree.size()>0)
 | |
| 		{ i=ifree[ifree.size()-1];ifree.pop_back();stock[i]=value; }
 | |
| 		else
 | |
| 		{ i=stock.size();stock.push_back(value); }
 | |
| 		return(i); 
 | |
| 	}
 | |
| 	//
 | |
| private:
 | |
| 	btDbvt(const btDbvt&)	{}	
 | |
| };
 | |
| 
 | |
| //
 | |
| // Inline's
 | |
| //
 | |
| 
 | |
| //
 | |
| inline btDbvtAabbMm			btDbvtAabbMm::FromCE(const btVector3& c,const btVector3& e)
 | |
| {
 | |
| 	btDbvtAabbMm box;
 | |
| 	box.mi=c-e;box.mx=c+e;
 | |
| 	return(box);
 | |
| }
 | |
| 
 | |
| //
 | |
| inline btDbvtAabbMm			btDbvtAabbMm::FromCR(const btVector3& c,btScalar r)
 | |
| {
 | |
| 	return(FromCE(c,btVector3(r,r,r)));
 | |
| }
 | |
| 
 | |
| //
 | |
| inline btDbvtAabbMm			btDbvtAabbMm::FromMM(const btVector3& mi,const btVector3& mx)
 | |
| {
 | |
| 	btDbvtAabbMm box;
 | |
| 	box.mi=mi;box.mx=mx;
 | |
| 	return(box);
 | |
| }
 | |
| 
 | |
| //
 | |
| inline btDbvtAabbMm			btDbvtAabbMm::FromPoints(const btVector3* pts,int n)
 | |
| {
 | |
| 	btDbvtAabbMm box;
 | |
| 	box.mi=box.mx=pts[0];
 | |
| 	for(int i=1;i<n;++i)
 | |
| 	{
 | |
| 		box.mi.setMin(pts[i]);
 | |
| 		box.mx.setMax(pts[i]);
 | |
| 	}
 | |
| 	return(box);
 | |
| }
 | |
| 
 | |
| //
 | |
| inline btDbvtAabbMm			btDbvtAabbMm::FromPoints(const btVector3** ppts,int n)
 | |
| {
 | |
| 	btDbvtAabbMm box;
 | |
| 	box.mi=box.mx=*ppts[0];
 | |
| 	for(int i=1;i<n;++i)
 | |
| 	{
 | |
| 		box.mi.setMin(*ppts[i]);
 | |
| 		box.mx.setMax(*ppts[i]);
 | |
| 	}
 | |
| 	return(box);
 | |
| }
 | |
| 
 | |
| //
 | |
| DBVT_INLINE void		btDbvtAabbMm::Expand(const btVector3& e)
 | |
| {
 | |
| 	mi-=e;mx+=e;
 | |
| }
 | |
| 
 | |
| //
 | |
| DBVT_INLINE void		btDbvtAabbMm::SignedExpand(const btVector3& e)
 | |
| {
 | |
| 	if(e.x()>0) mx.setX(mx.x()+e[0]); else mi.setX(mi.x()+e[0]);
 | |
| 	if(e.y()>0) mx.setY(mx.y()+e[1]); else mi.setY(mi.y()+e[1]);
 | |
| 	if(e.z()>0) mx.setZ(mx.z()+e[2]); else mi.setZ(mi.z()+e[2]);
 | |
| }
 | |
| 
 | |
| //
 | |
| DBVT_INLINE bool		btDbvtAabbMm::Contain(const btDbvtAabbMm& a) const
 | |
| {
 | |
| 	return(	(mi.x()<=a.mi.x())&&
 | |
| 		(mi.y()<=a.mi.y())&&
 | |
| 		(mi.z()<=a.mi.z())&&
 | |
| 		(mx.x()>=a.mx.x())&&
 | |
| 		(mx.y()>=a.mx.y())&&
 | |
| 		(mx.z()>=a.mx.z()));
 | |
| }
 | |
| 
 | |
| //
 | |
| DBVT_INLINE int		btDbvtAabbMm::Classify(const btVector3& n,btScalar o,int s) const
 | |
| {
 | |
| 	btVector3			pi,px;
 | |
| 	switch(s)
 | |
| 	{
 | |
| 	case	(0+0+0):	px=btVector3(mi.x(),mi.y(),mi.z());
 | |
| 		pi=btVector3(mx.x(),mx.y(),mx.z());break;
 | |
| 	case	(1+0+0):	px=btVector3(mx.x(),mi.y(),mi.z());
 | |
| 		pi=btVector3(mi.x(),mx.y(),mx.z());break;
 | |
| 	case	(0+2+0):	px=btVector3(mi.x(),mx.y(),mi.z());
 | |
| 		pi=btVector3(mx.x(),mi.y(),mx.z());break;
 | |
| 	case	(1+2+0):	px=btVector3(mx.x(),mx.y(),mi.z());
 | |
| 		pi=btVector3(mi.x(),mi.y(),mx.z());break;
 | |
| 	case	(0+0+4):	px=btVector3(mi.x(),mi.y(),mx.z());
 | |
| 		pi=btVector3(mx.x(),mx.y(),mi.z());break;
 | |
| 	case	(1+0+4):	px=btVector3(mx.x(),mi.y(),mx.z());
 | |
| 		pi=btVector3(mi.x(),mx.y(),mi.z());break;
 | |
| 	case	(0+2+4):	px=btVector3(mi.x(),mx.y(),mx.z());
 | |
| 		pi=btVector3(mx.x(),mi.y(),mi.z());break;
 | |
| 	case	(1+2+4):	px=btVector3(mx.x(),mx.y(),mx.z());
 | |
| 		pi=btVector3(mi.x(),mi.y(),mi.z());break;
 | |
| 	}
 | |
| 	if((btDot(n,px)+o)<0)		return(-1);
 | |
| 	if((btDot(n,pi)+o)>=0)	return(+1);
 | |
| 	return(0);
 | |
| }
 | |
| 
 | |
| //
 | |
| DBVT_INLINE btScalar	btDbvtAabbMm::ProjectMinimum(const btVector3& v,unsigned signs) const
 | |
| {
 | |
| 	const btVector3*	b[]={&mx,&mi};
 | |
| 	const btVector3		p(	b[(signs>>0)&1]->x(),
 | |
| 		b[(signs>>1)&1]->y(),
 | |
| 		b[(signs>>2)&1]->z());
 | |
| 	return(btDot(p,v));
 | |
| }
 | |
| 
 | |
| //
 | |
| DBVT_INLINE void		btDbvtAabbMm::AddSpan(const btVector3& d,btScalar& smi,btScalar& smx) const
 | |
| {
 | |
| 	for(int i=0;i<3;++i)
 | |
| 	{
 | |
| 		if(d[i]<0)
 | |
| 		{ smi+=mx[i]*d[i];smx+=mi[i]*d[i]; }
 | |
| 		else
 | |
| 		{ smi+=mi[i]*d[i];smx+=mx[i]*d[i]; }
 | |
| 	}
 | |
| }
 | |
| 
 | |
| //
 | |
| DBVT_INLINE bool		Intersect(	const btDbvtAabbMm& a,
 | |
| 								  const btDbvtAabbMm& b)
 | |
| {
 | |
| #if	DBVT_INT0_IMPL == DBVT_IMPL_SSE
 | |
| 	const __m128	rt(_mm_or_ps(	_mm_cmplt_ps(_mm_load_ps(b.mx),_mm_load_ps(a.mi)),
 | |
| 		_mm_cmplt_ps(_mm_load_ps(a.mx),_mm_load_ps(b.mi))));
 | |
| #if defined (_WIN32)
 | |
| 	const __int32*	pu((const __int32*)&rt);
 | |
| #else
 | |
|     const int*	pu((const int*)&rt);
 | |
| #endif
 | |
| 	return((pu[0]|pu[1]|pu[2])==0);
 | |
| #else
 | |
| 	return(	(a.mi.x()<=b.mx.x())&&
 | |
| 		(a.mx.x()>=b.mi.x())&&
 | |
| 		(a.mi.y()<=b.mx.y())&&
 | |
| 		(a.mx.y()>=b.mi.y())&&
 | |
| 		(a.mi.z()<=b.mx.z())&&		
 | |
| 		(a.mx.z()>=b.mi.z()));
 | |
| #endif
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| //
 | |
| DBVT_INLINE bool		Intersect(	const btDbvtAabbMm& a,
 | |
| 								  const btVector3& b)
 | |
| {
 | |
| 	return(	(b.x()>=a.mi.x())&&
 | |
| 		(b.y()>=a.mi.y())&&
 | |
| 		(b.z()>=a.mi.z())&&
 | |
| 		(b.x()<=a.mx.x())&&
 | |
| 		(b.y()<=a.mx.y())&&
 | |
| 		(b.z()<=a.mx.z()));
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| //////////////////////////////////////
 | |
| 
 | |
| 
 | |
| //
 | |
| DBVT_INLINE btScalar	Proximity(	const btDbvtAabbMm& a,
 | |
| 								  const btDbvtAabbMm& b)
 | |
| {
 | |
| 	const btVector3	d=(a.mi+a.mx)-(b.mi+b.mx);
 | |
| 	return(btFabs(d.x())+btFabs(d.y())+btFabs(d.z()));
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| //
 | |
| DBVT_INLINE int			Select(	const btDbvtAabbMm& o,
 | |
| 							   const btDbvtAabbMm& a,
 | |
| 							   const btDbvtAabbMm& b)
 | |
| {
 | |
| #if	DBVT_SELECT_IMPL == DBVT_IMPL_SSE
 | |
|     
 | |
| #if defined (_WIN32)
 | |
| 	static ATTRIBUTE_ALIGNED16(const unsigned __int32)	mask[]={0x7fffffff,0x7fffffff,0x7fffffff,0x7fffffff};
 | |
| #else
 | |
|     static ATTRIBUTE_ALIGNED16(const unsigned int)	mask[]={0x7fffffff,0x7fffffff,0x7fffffff,0x00000000 /*0x7fffffff*/};
 | |
| #endif
 | |
| 	///@todo: the intrinsic version is 11% slower
 | |
| #if DBVT_USE_INTRINSIC_SSE
 | |
| 
 | |
| 	union btSSEUnion ///NOTE: if we use more intrinsics, move btSSEUnion into the LinearMath directory
 | |
| 	{
 | |
| 	   __m128		ssereg;
 | |
| 	   float		floats[4];
 | |
| 	   int			ints[4];
 | |
| 	};
 | |
| 
 | |
| 	__m128	omi(_mm_load_ps(o.mi));
 | |
| 	omi=_mm_add_ps(omi,_mm_load_ps(o.mx));
 | |
| 	__m128	ami(_mm_load_ps(a.mi));
 | |
| 	ami=_mm_add_ps(ami,_mm_load_ps(a.mx));
 | |
| 	ami=_mm_sub_ps(ami,omi);
 | |
| 	ami=_mm_and_ps(ami,_mm_load_ps((const float*)mask));
 | |
| 	__m128	bmi(_mm_load_ps(b.mi));
 | |
| 	bmi=_mm_add_ps(bmi,_mm_load_ps(b.mx));
 | |
| 	bmi=_mm_sub_ps(bmi,omi);
 | |
| 	bmi=_mm_and_ps(bmi,_mm_load_ps((const float*)mask));
 | |
| 	__m128	t0(_mm_movehl_ps(ami,ami));
 | |
| 	ami=_mm_add_ps(ami,t0);
 | |
| 	ami=_mm_add_ss(ami,_mm_shuffle_ps(ami,ami,1));
 | |
| 	__m128 t1(_mm_movehl_ps(bmi,bmi));
 | |
| 	bmi=_mm_add_ps(bmi,t1);
 | |
| 	bmi=_mm_add_ss(bmi,_mm_shuffle_ps(bmi,bmi,1));
 | |
| 	
 | |
| 	btSSEUnion tmp;
 | |
| 	tmp.ssereg = _mm_cmple_ss(bmi,ami);
 | |
| 	return tmp.ints[0]&1;
 | |
| 
 | |
| #else
 | |
| 	ATTRIBUTE_ALIGNED16(__int32	r[1]);
 | |
| 	__asm
 | |
| 	{
 | |
| 		mov		eax,o
 | |
| 			mov		ecx,a
 | |
| 			mov		edx,b
 | |
| 			movaps	xmm0,[eax]
 | |
| 		movaps	xmm5,mask
 | |
| 			addps	xmm0,[eax+16]	
 | |
| 		movaps	xmm1,[ecx]
 | |
| 		movaps	xmm2,[edx]
 | |
| 		addps	xmm1,[ecx+16]
 | |
| 		addps	xmm2,[edx+16]
 | |
| 		subps	xmm1,xmm0
 | |
| 			subps	xmm2,xmm0
 | |
| 			andps	xmm1,xmm5
 | |
| 			andps	xmm2,xmm5
 | |
| 			movhlps	xmm3,xmm1
 | |
| 			movhlps	xmm4,xmm2
 | |
| 			addps	xmm1,xmm3
 | |
| 			addps	xmm2,xmm4
 | |
| 			pshufd	xmm3,xmm1,1
 | |
| 			pshufd	xmm4,xmm2,1
 | |
| 			addss	xmm1,xmm3
 | |
| 			addss	xmm2,xmm4
 | |
| 			cmpless	xmm2,xmm1
 | |
| 			movss	r,xmm2
 | |
| 	}
 | |
| 	return(r[0]&1);
 | |
| #endif
 | |
| #else
 | |
| 	return(Proximity(o,a)<Proximity(o,b)?0:1);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| //
 | |
| DBVT_INLINE void		Merge(	const btDbvtAabbMm& a,
 | |
| 							  const btDbvtAabbMm& b,
 | |
| 							  btDbvtAabbMm& r)
 | |
| {
 | |
| #if DBVT_MERGE_IMPL==DBVT_IMPL_SSE
 | |
| 	__m128	ami(_mm_load_ps(a.mi));
 | |
| 	__m128	amx(_mm_load_ps(a.mx));
 | |
| 	__m128	bmi(_mm_load_ps(b.mi));
 | |
| 	__m128	bmx(_mm_load_ps(b.mx));
 | |
| 	ami=_mm_min_ps(ami,bmi);
 | |
| 	amx=_mm_max_ps(amx,bmx);
 | |
| 	_mm_store_ps(r.mi,ami);
 | |
| 	_mm_store_ps(r.mx,amx);
 | |
| #else
 | |
| 	for(int i=0;i<3;++i)
 | |
| 	{
 | |
| 		if(a.mi[i]<b.mi[i]) r.mi[i]=a.mi[i]; else r.mi[i]=b.mi[i];
 | |
| 		if(a.mx[i]>b.mx[i]) r.mx[i]=a.mx[i]; else r.mx[i]=b.mx[i];
 | |
| 	}
 | |
| #endif
 | |
| }
 | |
| 
 | |
| //
 | |
| DBVT_INLINE bool		NotEqual(	const btDbvtAabbMm& a,
 | |
| 								 const btDbvtAabbMm& b)
 | |
| {
 | |
| 	return(	(a.mi.x()!=b.mi.x())||
 | |
| 		(a.mi.y()!=b.mi.y())||
 | |
| 		(a.mi.z()!=b.mi.z())||
 | |
| 		(a.mx.x()!=b.mx.x())||
 | |
| 		(a.mx.y()!=b.mx.y())||
 | |
| 		(a.mx.z()!=b.mx.z()));
 | |
| }
 | |
| 
 | |
| //
 | |
| // Inline's
 | |
| //
 | |
| 
 | |
| //
 | |
| DBVT_PREFIX
 | |
| inline void		btDbvt::enumNodes(	const btDbvtNode* root,
 | |
| 								  DBVT_IPOLICY)
 | |
| {
 | |
| 	DBVT_CHECKTYPE
 | |
| 		policy.Process(root);
 | |
| 	if(root->isinternal())
 | |
| 	{
 | |
| 		enumNodes(root->childs[0],policy);
 | |
| 		enumNodes(root->childs[1],policy);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| //
 | |
| DBVT_PREFIX
 | |
| inline void		btDbvt::enumLeaves(	const btDbvtNode* root,
 | |
| 								   DBVT_IPOLICY)
 | |
| {
 | |
| 	DBVT_CHECKTYPE
 | |
| 		if(root->isinternal())
 | |
| 		{
 | |
| 			enumLeaves(root->childs[0],policy);
 | |
| 			enumLeaves(root->childs[1],policy);
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			policy.Process(root);
 | |
| 		}
 | |
| }
 | |
| 
 | |
| //
 | |
| DBVT_PREFIX
 | |
| inline void		btDbvt::collideTT(	const btDbvtNode* root0,
 | |
| 								  const btDbvtNode* root1,
 | |
| 								  DBVT_IPOLICY)
 | |
| {
 | |
| 	DBVT_CHECKTYPE
 | |
| 		if(root0&&root1)
 | |
| 		{
 | |
| 			int								depth=1;
 | |
| 			int								treshold=DOUBLE_STACKSIZE-4;
 | |
| 			btAlignedObjectArray<sStkNN>	stkStack;
 | |
| 			stkStack.resize(DOUBLE_STACKSIZE);
 | |
| 			stkStack[0]=sStkNN(root0,root1);
 | |
| 			do	{		
 | |
| 				sStkNN	p=stkStack[--depth];
 | |
| 				if(depth>treshold)
 | |
| 				{
 | |
| 					stkStack.resize(stkStack.size()*2);
 | |
| 					treshold=stkStack.size()-4;
 | |
| 				}
 | |
| 				if(p.a==p.b)
 | |
| 				{
 | |
| 					if(p.a->isinternal())
 | |
| 					{
 | |
| 						stkStack[depth++]=sStkNN(p.a->childs[0],p.a->childs[0]);
 | |
| 						stkStack[depth++]=sStkNN(p.a->childs[1],p.a->childs[1]);
 | |
| 						stkStack[depth++]=sStkNN(p.a->childs[0],p.a->childs[1]);
 | |
| 					}
 | |
| 				}
 | |
| 				else if(Intersect(p.a->volume,p.b->volume))
 | |
| 				{
 | |
| 					if(p.a->isinternal())
 | |
| 					{
 | |
| 						if(p.b->isinternal())
 | |
| 						{
 | |
| 							stkStack[depth++]=sStkNN(p.a->childs[0],p.b->childs[0]);
 | |
| 							stkStack[depth++]=sStkNN(p.a->childs[1],p.b->childs[0]);
 | |
| 							stkStack[depth++]=sStkNN(p.a->childs[0],p.b->childs[1]);
 | |
| 							stkStack[depth++]=sStkNN(p.a->childs[1],p.b->childs[1]);
 | |
| 						}
 | |
| 						else
 | |
| 						{
 | |
| 							stkStack[depth++]=sStkNN(p.a->childs[0],p.b);
 | |
| 							stkStack[depth++]=sStkNN(p.a->childs[1],p.b);
 | |
| 						}
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						if(p.b->isinternal())
 | |
| 						{
 | |
| 							stkStack[depth++]=sStkNN(p.a,p.b->childs[0]);
 | |
| 							stkStack[depth++]=sStkNN(p.a,p.b->childs[1]);
 | |
| 						}
 | |
| 						else
 | |
| 						{
 | |
| 							policy.Process(p.a,p.b);
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			} while(depth);
 | |
| 		}
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| DBVT_PREFIX
 | |
| inline void		btDbvt::collideTTpersistentStack(	const btDbvtNode* root0,
 | |
| 								  const btDbvtNode* root1,
 | |
| 								  DBVT_IPOLICY)
 | |
| {
 | |
| 	DBVT_CHECKTYPE
 | |
| 		if(root0&&root1)
 | |
| 		{
 | |
| 			int								depth=1;
 | |
| 			int								treshold=DOUBLE_STACKSIZE-4;
 | |
| 			
 | |
| 			m_stkStack.resize(DOUBLE_STACKSIZE);
 | |
| 			m_stkStack[0]=sStkNN(root0,root1);
 | |
| 			do	{		
 | |
| 				sStkNN	p=m_stkStack[--depth];
 | |
| 				if(depth>treshold)
 | |
| 				{
 | |
| 					m_stkStack.resize(m_stkStack.size()*2);
 | |
| 					treshold=m_stkStack.size()-4;
 | |
| 				}
 | |
| 				if(p.a==p.b)
 | |
| 				{
 | |
| 					if(p.a->isinternal())
 | |
| 					{
 | |
| 						m_stkStack[depth++]=sStkNN(p.a->childs[0],p.a->childs[0]);
 | |
| 						m_stkStack[depth++]=sStkNN(p.a->childs[1],p.a->childs[1]);
 | |
| 						m_stkStack[depth++]=sStkNN(p.a->childs[0],p.a->childs[1]);
 | |
| 					}
 | |
| 				}
 | |
| 				else if(Intersect(p.a->volume,p.b->volume))
 | |
| 				{
 | |
| 					if(p.a->isinternal())
 | |
| 					{
 | |
| 						if(p.b->isinternal())
 | |
| 						{
 | |
| 							m_stkStack[depth++]=sStkNN(p.a->childs[0],p.b->childs[0]);
 | |
| 							m_stkStack[depth++]=sStkNN(p.a->childs[1],p.b->childs[0]);
 | |
| 							m_stkStack[depth++]=sStkNN(p.a->childs[0],p.b->childs[1]);
 | |
| 							m_stkStack[depth++]=sStkNN(p.a->childs[1],p.b->childs[1]);
 | |
| 						}
 | |
| 						else
 | |
| 						{
 | |
| 							m_stkStack[depth++]=sStkNN(p.a->childs[0],p.b);
 | |
| 							m_stkStack[depth++]=sStkNN(p.a->childs[1],p.b);
 | |
| 						}
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						if(p.b->isinternal())
 | |
| 						{
 | |
| 							m_stkStack[depth++]=sStkNN(p.a,p.b->childs[0]);
 | |
| 							m_stkStack[depth++]=sStkNN(p.a,p.b->childs[1]);
 | |
| 						}
 | |
| 						else
 | |
| 						{
 | |
| 							policy.Process(p.a,p.b);
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			} while(depth);
 | |
| 		}
 | |
| }
 | |
| 
 | |
| #if 0
 | |
| //
 | |
| DBVT_PREFIX
 | |
| inline void		btDbvt::collideTT(	const btDbvtNode* root0,
 | |
| 								  const btDbvtNode* root1,
 | |
| 								  const btTransform& xform,
 | |
| 								  DBVT_IPOLICY)
 | |
| {
 | |
| 	DBVT_CHECKTYPE
 | |
| 		if(root0&&root1)
 | |
| 		{
 | |
| 			int								depth=1;
 | |
| 			int								treshold=DOUBLE_STACKSIZE-4;
 | |
| 			btAlignedObjectArray<sStkNN>	stkStack;
 | |
| 			stkStack.resize(DOUBLE_STACKSIZE);
 | |
| 			stkStack[0]=sStkNN(root0,root1);
 | |
| 			do	{
 | |
| 				sStkNN	p=stkStack[--depth];
 | |
| 				if(Intersect(p.a->volume,p.b->volume,xform))
 | |
| 				{
 | |
| 					if(depth>treshold)
 | |
| 					{
 | |
| 						stkStack.resize(stkStack.size()*2);
 | |
| 						treshold=stkStack.size()-4;
 | |
| 					}
 | |
| 					if(p.a->isinternal())
 | |
| 					{
 | |
| 						if(p.b->isinternal())
 | |
| 						{					
 | |
| 							stkStack[depth++]=sStkNN(p.a->childs[0],p.b->childs[0]);
 | |
| 							stkStack[depth++]=sStkNN(p.a->childs[1],p.b->childs[0]);
 | |
| 							stkStack[depth++]=sStkNN(p.a->childs[0],p.b->childs[1]);
 | |
| 							stkStack[depth++]=sStkNN(p.a->childs[1],p.b->childs[1]);
 | |
| 						}
 | |
| 						else
 | |
| 						{
 | |
| 							stkStack[depth++]=sStkNN(p.a->childs[0],p.b);
 | |
| 							stkStack[depth++]=sStkNN(p.a->childs[1],p.b);
 | |
| 						}
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						if(p.b->isinternal())
 | |
| 						{
 | |
| 							stkStack[depth++]=sStkNN(p.a,p.b->childs[0]);
 | |
| 							stkStack[depth++]=sStkNN(p.a,p.b->childs[1]);
 | |
| 						}
 | |
| 						else
 | |
| 						{
 | |
| 							policy.Process(p.a,p.b);
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			} while(depth);
 | |
| 		}
 | |
| }
 | |
| //
 | |
| DBVT_PREFIX
 | |
| inline void		btDbvt::collideTT(	const btDbvtNode* root0,
 | |
| 								  const btTransform& xform0,
 | |
| 								  const btDbvtNode* root1,
 | |
| 								  const btTransform& xform1,
 | |
| 								  DBVT_IPOLICY)
 | |
| {
 | |
| 	const btTransform	xform=xform0.inverse()*xform1;
 | |
| 	collideTT(root0,root1,xform,policy);
 | |
| }
 | |
| #endif 
 | |
| 
 | |
| DBVT_PREFIX
 | |
| inline void		btDbvt::collideTV(	const btDbvtNode* root,
 | |
| 								  const btDbvtVolume& vol,
 | |
| 								  DBVT_IPOLICY) const
 | |
| {
 | |
| 	DBVT_CHECKTYPE
 | |
| 	if(root)
 | |
| 	{
 | |
| 		ATTRIBUTE_ALIGNED16(btDbvtVolume)		volume(vol);
 | |
| 		btAlignedObjectArray<const btDbvtNode*>	stack;
 | |
| 		stack.resize(0);
 | |
| #ifndef BT_DISABLE_STACK_TEMP_MEMORY
 | |
| 		char tempmemory[SIMPLE_STACKSIZE*sizeof(const btDbvtNode*)];
 | |
| 		stack.initializeFromBuffer(tempmemory, 0, SIMPLE_STACKSIZE);
 | |
| #else
 | |
| 		stack.reserve(SIMPLE_STACKSIZE);
 | |
| #endif //BT_DISABLE_STACK_TEMP_MEMORY
 | |
| 
 | |
| 		stack.push_back(root);
 | |
| 		do	{
 | |
| 			const btDbvtNode*	n=stack[stack.size()-1];
 | |
| 			stack.pop_back();
 | |
| 			if(Intersect(n->volume,volume))
 | |
| 			{
 | |
| 				if(n->isinternal())
 | |
| 				{
 | |
| 					stack.push_back(n->childs[0]);
 | |
| 					stack.push_back(n->childs[1]);
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					policy.Process(n);
 | |
| 				}
 | |
| 			}
 | |
| 		} while(stack.size()>0);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| //
 | |
| DBVT_PREFIX
 | |
| inline void		btDbvt::collideTVNoStackAlloc(	const btDbvtNode* root,
 | |
| 											 const btDbvtVolume& vol,
 | |
| 											 btNodeStack& stack,
 | |
| 											 DBVT_IPOLICY) const
 | |
| {
 | |
| 	DBVT_CHECKTYPE
 | |
| 	if(root)
 | |
| 	{
 | |
| 		ATTRIBUTE_ALIGNED16(btDbvtVolume)		volume(vol);
 | |
| 		stack.resize(0);
 | |
| 		stack.reserve(SIMPLE_STACKSIZE);
 | |
| 		stack.push_back(root);
 | |
| 		do	{
 | |
| 			const btDbvtNode*	n=stack[stack.size()-1];
 | |
| 			stack.pop_back();
 | |
| 			if(Intersect(n->volume,volume))
 | |
| 			{
 | |
| 				if(n->isinternal())
 | |
| 				{
 | |
| 					stack.push_back(n->childs[0]);
 | |
| 					stack.push_back(n->childs[1]);
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					policy.Process(n);
 | |
| 				}
 | |
| 			}
 | |
| 		} while(stack.size()>0);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| DBVT_PREFIX
 | |
| inline void		btDbvt::rayTestInternal(	const btDbvtNode* root,
 | |
| 								const btVector3& rayFrom,
 | |
| 								const btVector3& rayTo,
 | |
| 								const btVector3& rayDirectionInverse,
 | |
| 								unsigned int signs[3],
 | |
| 								btScalar lambda_max,
 | |
| 								const btVector3& aabbMin,
 | |
| 								const btVector3& aabbMax,
 | |
|                                 btAlignedObjectArray<const btDbvtNode*>& stack,
 | |
|                                 DBVT_IPOLICY ) const
 | |
| {
 | |
|         (void) rayTo;
 | |
| 	DBVT_CHECKTYPE
 | |
| 	if(root)
 | |
| 	{
 | |
| 		btVector3 resultNormal;
 | |
| 
 | |
| 		int								depth=1;
 | |
| 		int								treshold=DOUBLE_STACKSIZE-2;
 | |
| 		stack.resize(DOUBLE_STACKSIZE);
 | |
| 		stack[0]=root;
 | |
| 		btVector3 bounds[2];
 | |
| 		do	
 | |
| 		{
 | |
| 			const btDbvtNode*	node=stack[--depth];
 | |
| 			bounds[0] = node->volume.Mins()-aabbMax;
 | |
| 			bounds[1] = node->volume.Maxs()-aabbMin;
 | |
| 			btScalar tmin=1.f,lambda_min=0.f;
 | |
| 			unsigned int result1=false;
 | |
| 			result1 = btRayAabb2(rayFrom,rayDirectionInverse,signs,bounds,tmin,lambda_min,lambda_max);
 | |
| 			if(result1)
 | |
| 			{
 | |
| 				if(node->isinternal())
 | |
| 				{
 | |
| 					if(depth>treshold)
 | |
| 					{
 | |
| 						stack.resize(stack.size()*2);
 | |
| 						treshold=stack.size()-2;
 | |
| 					}
 | |
| 					stack[depth++]=node->childs[0];
 | |
| 					stack[depth++]=node->childs[1];
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					policy.Process(node);
 | |
| 				}
 | |
| 			}
 | |
| 		} while(depth);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| //
 | |
| DBVT_PREFIX
 | |
| inline void		btDbvt::rayTest(	const btDbvtNode* root,
 | |
| 								const btVector3& rayFrom,
 | |
| 								const btVector3& rayTo,
 | |
| 								DBVT_IPOLICY)
 | |
| {
 | |
| 	DBVT_CHECKTYPE
 | |
| 		if(root)
 | |
| 		{
 | |
| 			btVector3 rayDir = (rayTo-rayFrom);
 | |
| 			rayDir.normalize ();
 | |
| 
 | |
| 			///what about division by zero? --> just set rayDirection[i] to INF/BT_LARGE_FLOAT
 | |
| 			btVector3 rayDirectionInverse;
 | |
| 			rayDirectionInverse[0] = rayDir[0] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[0];
 | |
| 			rayDirectionInverse[1] = rayDir[1] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[1];
 | |
| 			rayDirectionInverse[2] = rayDir[2] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[2];
 | |
| 			unsigned int signs[3] = { rayDirectionInverse[0] < 0.0, rayDirectionInverse[1] < 0.0, rayDirectionInverse[2] < 0.0};
 | |
| 
 | |
| 			btScalar lambda_max = rayDir.dot(rayTo-rayFrom);
 | |
| 
 | |
| 			btVector3 resultNormal;
 | |
| 
 | |
| 			btAlignedObjectArray<const btDbvtNode*>	stack;
 | |
| 
 | |
| 			int								depth=1;
 | |
| 			int								treshold=DOUBLE_STACKSIZE-2;
 | |
| 
 | |
| 			char tempmemory[DOUBLE_STACKSIZE * sizeof(const btDbvtNode*)];
 | |
| #ifndef BT_DISABLE_STACK_TEMP_MEMORY
 | |
| 			stack.initializeFromBuffer(tempmemory, DOUBLE_STACKSIZE, DOUBLE_STACKSIZE);
 | |
| #else//BT_DISABLE_STACK_TEMP_MEMORY
 | |
| 			stack.resize(DOUBLE_STACKSIZE);
 | |
| #endif //BT_DISABLE_STACK_TEMP_MEMORY
 | |
| 			stack[0]=root;
 | |
| 			btVector3 bounds[2];
 | |
| 			do	{
 | |
| 				const btDbvtNode*	node=stack[--depth];
 | |
| 
 | |
| 				bounds[0] = node->volume.Mins();
 | |
| 				bounds[1] = node->volume.Maxs();
 | |
| 				
 | |
| 				btScalar tmin=1.f,lambda_min=0.f;
 | |
| 				unsigned int result1 = btRayAabb2(rayFrom,rayDirectionInverse,signs,bounds,tmin,lambda_min,lambda_max);
 | |
| 
 | |
| #ifdef COMPARE_BTRAY_AABB2
 | |
| 				btScalar param=1.f;
 | |
| 				bool result2 = btRayAabb(rayFrom,rayTo,node->volume.Mins(),node->volume.Maxs(),param,resultNormal);
 | |
| 				btAssert(result1 == result2);
 | |
| #endif //TEST_BTRAY_AABB2
 | |
| 
 | |
| 				if(result1)
 | |
| 				{
 | |
| 					if(node->isinternal())
 | |
| 					{
 | |
| 						if(depth>treshold)
 | |
| 						{
 | |
| 							stack.resize(stack.size()*2);
 | |
| 							treshold=stack.size()-2;
 | |
| 						}
 | |
| 						stack[depth++]=node->childs[0];
 | |
| 						stack[depth++]=node->childs[1];
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						policy.Process(node);
 | |
| 					}
 | |
| 				}
 | |
| 			} while(depth);
 | |
| 
 | |
| 		}
 | |
| }
 | |
| 
 | |
| //
 | |
| DBVT_PREFIX
 | |
| inline void		btDbvt::collideKDOP(const btDbvtNode* root,
 | |
| 									const btVector3* normals,
 | |
| 									const btScalar* offsets,
 | |
| 									int count,
 | |
| 									DBVT_IPOLICY)
 | |
| {
 | |
| 	DBVT_CHECKTYPE
 | |
| 		if(root)
 | |
| 		{
 | |
| 			const int						inside=(1<<count)-1;
 | |
| 			btAlignedObjectArray<sStkNP>	stack;
 | |
| 			int								signs[sizeof(unsigned)*8];
 | |
| 			btAssert(count<int (sizeof(signs)/sizeof(signs[0])));
 | |
| 			for(int i=0;i<count;++i)
 | |
| 			{
 | |
| 				signs[i]=	((normals[i].x()>=0)?1:0)+
 | |
| 					((normals[i].y()>=0)?2:0)+
 | |
| 					((normals[i].z()>=0)?4:0);
 | |
| 			}
 | |
| 			stack.reserve(SIMPLE_STACKSIZE);
 | |
| 			stack.push_back(sStkNP(root,0));
 | |
| 			do	{
 | |
| 				sStkNP	se=stack[stack.size()-1];
 | |
| 				bool	out=false;
 | |
| 				stack.pop_back();
 | |
| 				for(int i=0,j=1;(!out)&&(i<count);++i,j<<=1)
 | |
| 				{
 | |
| 					if(0==(se.mask&j))
 | |
| 					{
 | |
| 						const int	side=se.node->volume.Classify(normals[i],offsets[i],signs[i]);
 | |
| 						switch(side)
 | |
| 						{
 | |
| 						case	-1:	out=true;break;
 | |
| 						case	+1:	se.mask|=j;break;
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 				if(!out)
 | |
| 				{
 | |
| 					if((se.mask!=inside)&&(se.node->isinternal()))
 | |
| 					{
 | |
| 						stack.push_back(sStkNP(se.node->childs[0],se.mask));
 | |
| 						stack.push_back(sStkNP(se.node->childs[1],se.mask));
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						if(policy.AllLeaves(se.node)) enumLeaves(se.node,policy);
 | |
| 					}
 | |
| 				}
 | |
| 			} while(stack.size());
 | |
| 		}
 | |
| }
 | |
| 
 | |
| //
 | |
| DBVT_PREFIX
 | |
| inline void		btDbvt::collideOCL(	const btDbvtNode* root,
 | |
| 								   const btVector3* normals,
 | |
| 								   const btScalar* offsets,
 | |
| 								   const btVector3& sortaxis,
 | |
| 								   int count,
 | |
| 								   DBVT_IPOLICY,
 | |
| 								   bool fsort)
 | |
| {
 | |
| 	DBVT_CHECKTYPE
 | |
| 		if(root)
 | |
| 		{
 | |
| 			const unsigned					srtsgns=(sortaxis[0]>=0?1:0)+
 | |
| 				(sortaxis[1]>=0?2:0)+
 | |
| 				(sortaxis[2]>=0?4:0);
 | |
| 			const int						inside=(1<<count)-1;
 | |
| 			btAlignedObjectArray<sStkNPS>	stock;
 | |
| 			btAlignedObjectArray<int>		ifree;
 | |
| 			btAlignedObjectArray<int>		stack;
 | |
| 			int								signs[sizeof(unsigned)*8];
 | |
| 			btAssert(count<int (sizeof(signs)/sizeof(signs[0])));
 | |
| 			for(int i=0;i<count;++i)
 | |
| 			{
 | |
| 				signs[i]=	((normals[i].x()>=0)?1:0)+
 | |
| 					((normals[i].y()>=0)?2:0)+
 | |
| 					((normals[i].z()>=0)?4:0);
 | |
| 			}
 | |
| 			stock.reserve(SIMPLE_STACKSIZE);
 | |
| 			stack.reserve(SIMPLE_STACKSIZE);
 | |
| 			ifree.reserve(SIMPLE_STACKSIZE);
 | |
| 			stack.push_back(allocate(ifree,stock,sStkNPS(root,0,root->volume.ProjectMinimum(sortaxis,srtsgns))));
 | |
| 			do	{
 | |
| 				const int	id=stack[stack.size()-1];
 | |
| 				sStkNPS		se=stock[id];
 | |
| 				stack.pop_back();ifree.push_back(id);
 | |
| 				if(se.mask!=inside)
 | |
| 				{
 | |
| 					bool	out=false;
 | |
| 					for(int i=0,j=1;(!out)&&(i<count);++i,j<<=1)
 | |
| 					{
 | |
| 						if(0==(se.mask&j))
 | |
| 						{
 | |
| 							const int	side=se.node->volume.Classify(normals[i],offsets[i],signs[i]);
 | |
| 							switch(side)
 | |
| 							{
 | |
| 							case	-1:	out=true;break;
 | |
| 							case	+1:	se.mask|=j;break;
 | |
| 							}
 | |
| 						}
 | |
| 					}
 | |
| 					if(out) continue;
 | |
| 				}
 | |
| 				if(policy.Descent(se.node))
 | |
| 				{
 | |
| 					if(se.node->isinternal())
 | |
| 					{
 | |
| 						const btDbvtNode* pns[]={	se.node->childs[0],se.node->childs[1]};
 | |
| 						sStkNPS		nes[]={	sStkNPS(pns[0],se.mask,pns[0]->volume.ProjectMinimum(sortaxis,srtsgns)),
 | |
| 							sStkNPS(pns[1],se.mask,pns[1]->volume.ProjectMinimum(sortaxis,srtsgns))};
 | |
| 						const int	q=nes[0].value<nes[1].value?1:0;				
 | |
| 						int			j=stack.size();
 | |
| 						if(fsort&&(j>0))
 | |
| 						{
 | |
| 							/* Insert 0	*/ 
 | |
| 							j=nearest(&stack[0],&stock[0],nes[q].value,0,stack.size());
 | |
| 							stack.push_back(0);
 | |
| 							
 | |
| 							//void * memmove ( void * destination, const void * source, size_t num );
 | |
| 							
 | |
| #if DBVT_USE_MEMMOVE
 | |
|                      {
 | |
|                      int num_items_to_move = stack.size()-1-j;
 | |
|                      if(num_items_to_move > 0)
 | |
|                         memmove(&stack[j+1],&stack[j],sizeof(int)*num_items_to_move);
 | |
|                      }
 | |
| #else
 | |
|                      for(int k=stack.size()-1;k>j;--k) {
 | |
| 								stack[k]=stack[k-1];
 | |
|                      }
 | |
| #endif
 | |
| 							stack[j]=allocate(ifree,stock,nes[q]);
 | |
| 							/* Insert 1	*/ 
 | |
| 							j=nearest(&stack[0],&stock[0],nes[1-q].value,j,stack.size());
 | |
| 							stack.push_back(0);
 | |
| #if DBVT_USE_MEMMOVE
 | |
|                      {
 | |
|                      int num_items_to_move = stack.size()-1-j;
 | |
|                      if(num_items_to_move > 0)
 | |
|                         memmove(&stack[j+1],&stack[j],sizeof(int)*num_items_to_move);
 | |
|                      }
 | |
| #else
 | |
|                      for(int k=stack.size()-1;k>j;--k) {
 | |
|                         stack[k]=stack[k-1];
 | |
|                      }
 | |
| #endif
 | |
| 							stack[j]=allocate(ifree,stock,nes[1-q]);
 | |
| 						}
 | |
| 						else
 | |
| 						{
 | |
| 							stack.push_back(allocate(ifree,stock,nes[q]));
 | |
| 							stack.push_back(allocate(ifree,stock,nes[1-q]));
 | |
| 						}
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						policy.Process(se.node,se.value);
 | |
| 					}
 | |
| 				}
 | |
| 			} while(stack.size());
 | |
| 		}
 | |
| }
 | |
| 
 | |
| //
 | |
| DBVT_PREFIX
 | |
| inline void		btDbvt::collideTU(	const btDbvtNode* root,
 | |
| 								  DBVT_IPOLICY)
 | |
| {
 | |
| 	DBVT_CHECKTYPE
 | |
| 		if(root)
 | |
| 		{
 | |
| 			btAlignedObjectArray<const btDbvtNode*>	stack;
 | |
| 			stack.reserve(SIMPLE_STACKSIZE);
 | |
| 			stack.push_back(root);
 | |
| 			do	{
 | |
| 				const btDbvtNode*	n=stack[stack.size()-1];
 | |
| 				stack.pop_back();
 | |
| 				if(policy.Descent(n))
 | |
| 				{
 | |
| 					if(n->isinternal())
 | |
| 					{ stack.push_back(n->childs[0]);stack.push_back(n->childs[1]); }
 | |
| 					else
 | |
| 					{ policy.Process(n); }
 | |
| 				}
 | |
| 			} while(stack.size()>0);
 | |
| 		}
 | |
| }
 | |
| 
 | |
| //
 | |
| // PP Cleanup
 | |
| //
 | |
| 
 | |
| #undef DBVT_USE_MEMMOVE
 | |
| #undef DBVT_USE_TEMPLATE
 | |
| #undef DBVT_VIRTUAL_DTOR
 | |
| #undef DBVT_VIRTUAL
 | |
| #undef DBVT_PREFIX
 | |
| #undef DBVT_IPOLICY
 | |
| #undef DBVT_CHECKTYPE
 | |
| #undef DBVT_IMPL_GENERIC
 | |
| #undef DBVT_IMPL_SSE
 | |
| #undef DBVT_USE_INTRINSIC_SSE
 | |
| #undef DBVT_SELECT_IMPL
 | |
| #undef DBVT_MERGE_IMPL
 | |
| #undef DBVT_INT0_IMPL
 | |
| 
 | |
| #endif
 |