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
 |