forked from LeenkxTeam/LNXSDK
		
	
		
			
	
	
		
			392 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			392 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|  | /*
 | ||
|  | Bullet Continuous Collision Detection and Physics Library | ||
|  | Copyright (c) 2003-2009 Erwin Coumans  http://bulletphysics.org
 | ||
|  | 
 | ||
|  | 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. | ||
|  | */ | ||
|  | 
 | ||
|  | 
 | ||
|  | #include "btOptimizedBvh.h"
 | ||
|  | #include "btStridingMeshInterface.h"
 | ||
|  | #include "LinearMath/btAabbUtil2.h"
 | ||
|  | #include "LinearMath/btIDebugDraw.h"
 | ||
|  | 
 | ||
|  | 
 | ||
|  | btOptimizedBvh::btOptimizedBvh() | ||
|  | {  | ||
|  | } | ||
|  | 
 | ||
|  | btOptimizedBvh::~btOptimizedBvh() | ||
|  | { | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | void btOptimizedBvh::build(btStridingMeshInterface* triangles, bool useQuantizedAabbCompression, const btVector3& bvhAabbMin, const btVector3& bvhAabbMax) | ||
|  | { | ||
|  | 	m_useQuantization = useQuantizedAabbCompression; | ||
|  | 
 | ||
|  | 
 | ||
|  | 	// NodeArray	triangleNodes;
 | ||
|  | 
 | ||
|  | 	struct	NodeTriangleCallback : public btInternalTriangleIndexCallback | ||
|  | 	{ | ||
|  | 
 | ||
|  | 		NodeArray&	m_triangleNodes; | ||
|  | 
 | ||
|  | 		NodeTriangleCallback& operator=(NodeTriangleCallback& other) | ||
|  | 		{ | ||
|  | 			m_triangleNodes.copyFromArray(other.m_triangleNodes); | ||
|  | 			return *this; | ||
|  | 		} | ||
|  | 		 | ||
|  | 		NodeTriangleCallback(NodeArray&	triangleNodes) | ||
|  | 			:m_triangleNodes(triangleNodes) | ||
|  | 		{ | ||
|  | 		} | ||
|  | 
 | ||
|  | 		virtual void internalProcessTriangleIndex(btVector3* triangle,int partId,int  triangleIndex) | ||
|  | 		{ | ||
|  | 			btOptimizedBvhNode node; | ||
|  | 			btVector3	aabbMin,aabbMax; | ||
|  | 			aabbMin.setValue(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); | ||
|  | 			aabbMax.setValue(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT));  | ||
|  | 			aabbMin.setMin(triangle[0]); | ||
|  | 			aabbMax.setMax(triangle[0]); | ||
|  | 			aabbMin.setMin(triangle[1]); | ||
|  | 			aabbMax.setMax(triangle[1]); | ||
|  | 			aabbMin.setMin(triangle[2]); | ||
|  | 			aabbMax.setMax(triangle[2]); | ||
|  | 
 | ||
|  | 			//with quantization?
 | ||
|  | 			node.m_aabbMinOrg = aabbMin; | ||
|  | 			node.m_aabbMaxOrg = aabbMax; | ||
|  | 
 | ||
|  | 			node.m_escapeIndex = -1; | ||
|  | 	 | ||
|  | 			//for child nodes
 | ||
|  | 			node.m_subPart = partId; | ||
|  | 			node.m_triangleIndex = triangleIndex; | ||
|  | 			m_triangleNodes.push_back(node); | ||
|  | 		} | ||
|  | 	}; | ||
|  | 	struct	QuantizedNodeTriangleCallback : public btInternalTriangleIndexCallback | ||
|  | 	{ | ||
|  | 		QuantizedNodeArray&	m_triangleNodes; | ||
|  | 		const btQuantizedBvh* m_optimizedTree; // for quantization
 | ||
|  | 
 | ||
|  | 		QuantizedNodeTriangleCallback& operator=(QuantizedNodeTriangleCallback& other) | ||
|  | 		{ | ||
|  | 			m_triangleNodes.copyFromArray(other.m_triangleNodes); | ||
|  | 			m_optimizedTree = other.m_optimizedTree; | ||
|  | 			return *this; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		QuantizedNodeTriangleCallback(QuantizedNodeArray&	triangleNodes,const btQuantizedBvh* tree) | ||
|  | 			:m_triangleNodes(triangleNodes),m_optimizedTree(tree) | ||
|  | 		{ | ||
|  | 		} | ||
|  | 
 | ||
|  | 		virtual void internalProcessTriangleIndex(btVector3* triangle,int partId,int  triangleIndex) | ||
|  | 		{ | ||
|  | 			// The partId and triangle index must fit in the same (positive) integer
 | ||
|  | 			btAssert(partId < (1<<MAX_NUM_PARTS_IN_BITS)); | ||
|  | 			btAssert(triangleIndex < (1<<(31-MAX_NUM_PARTS_IN_BITS))); | ||
|  | 			//negative indices are reserved for escapeIndex
 | ||
|  | 			btAssert(triangleIndex>=0); | ||
|  | 
 | ||
|  | 			btQuantizedBvhNode node; | ||
|  | 			btVector3	aabbMin,aabbMax; | ||
|  | 			aabbMin.setValue(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); | ||
|  | 			aabbMax.setValue(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT));  | ||
|  | 			aabbMin.setMin(triangle[0]); | ||
|  | 			aabbMax.setMax(triangle[0]); | ||
|  | 			aabbMin.setMin(triangle[1]); | ||
|  | 			aabbMax.setMax(triangle[1]); | ||
|  | 			aabbMin.setMin(triangle[2]); | ||
|  | 			aabbMax.setMax(triangle[2]); | ||
|  | 
 | ||
|  | 			//PCK: add these checks for zero dimensions of aabb
 | ||
|  | 			const btScalar MIN_AABB_DIMENSION = btScalar(0.002); | ||
|  | 			const btScalar MIN_AABB_HALF_DIMENSION = btScalar(0.001); | ||
|  | 			if (aabbMax.x() - aabbMin.x() < MIN_AABB_DIMENSION) | ||
|  | 			{ | ||
|  | 				aabbMax.setX(aabbMax.x() + MIN_AABB_HALF_DIMENSION); | ||
|  | 				aabbMin.setX(aabbMin.x() - MIN_AABB_HALF_DIMENSION); | ||
|  | 			} | ||
|  | 			if (aabbMax.y() - aabbMin.y() < MIN_AABB_DIMENSION) | ||
|  | 			{ | ||
|  | 				aabbMax.setY(aabbMax.y() + MIN_AABB_HALF_DIMENSION); | ||
|  | 				aabbMin.setY(aabbMin.y() - MIN_AABB_HALF_DIMENSION); | ||
|  | 			} | ||
|  | 			if (aabbMax.z() - aabbMin.z() < MIN_AABB_DIMENSION) | ||
|  | 			{ | ||
|  | 				aabbMax.setZ(aabbMax.z() + MIN_AABB_HALF_DIMENSION); | ||
|  | 				aabbMin.setZ(aabbMin.z() - MIN_AABB_HALF_DIMENSION); | ||
|  | 			} | ||
|  | 
 | ||
|  | 			m_optimizedTree->quantize(&node.m_quantizedAabbMin[0],aabbMin,0); | ||
|  | 			m_optimizedTree->quantize(&node.m_quantizedAabbMax[0],aabbMax,1); | ||
|  | 
 | ||
|  | 			node.m_escapeIndexOrTriangleIndex = (partId<<(31-MAX_NUM_PARTS_IN_BITS)) | triangleIndex; | ||
|  | 
 | ||
|  | 			m_triangleNodes.push_back(node); | ||
|  | 		} | ||
|  | 	}; | ||
|  | 	 | ||
|  | 
 | ||
|  | 
 | ||
|  | 	int numLeafNodes = 0; | ||
|  | 
 | ||
|  | 	 | ||
|  | 	if (m_useQuantization) | ||
|  | 	{ | ||
|  | 
 | ||
|  | 		//initialize quantization values
 | ||
|  | 		setQuantizationValues(bvhAabbMin,bvhAabbMax); | ||
|  | 
 | ||
|  | 		QuantizedNodeTriangleCallback	callback(m_quantizedLeafNodes,this); | ||
|  | 
 | ||
|  | 	 | ||
|  | 		triangles->InternalProcessAllTriangles(&callback,m_bvhAabbMin,m_bvhAabbMax); | ||
|  | 
 | ||
|  | 		//now we have an array of leafnodes in m_leafNodes
 | ||
|  | 		numLeafNodes = m_quantizedLeafNodes.size(); | ||
|  | 
 | ||
|  | 
 | ||
|  | 		m_quantizedContiguousNodes.resize(2*numLeafNodes); | ||
|  | 
 | ||
|  | 
 | ||
|  | 	} else | ||
|  | 	{ | ||
|  | 		NodeTriangleCallback	callback(m_leafNodes); | ||
|  | 
 | ||
|  | 		btVector3 aabbMin(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT)); | ||
|  | 		btVector3 aabbMax(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); | ||
|  | 
 | ||
|  | 		triangles->InternalProcessAllTriangles(&callback,aabbMin,aabbMax); | ||
|  | 
 | ||
|  | 		//now we have an array of leafnodes in m_leafNodes
 | ||
|  | 		numLeafNodes = m_leafNodes.size(); | ||
|  | 
 | ||
|  | 		m_contiguousNodes.resize(2*numLeafNodes); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	m_curNodeIndex = 0; | ||
|  | 
 | ||
|  | 	buildTree(0,numLeafNodes); | ||
|  | 
 | ||
|  | 	///if the entire tree is small then subtree size, we need to create a header info for the tree
 | ||
|  | 	if(m_useQuantization && !m_SubtreeHeaders.size()) | ||
|  | 	{ | ||
|  | 		btBvhSubtreeInfo& subtree = m_SubtreeHeaders.expand(); | ||
|  | 		subtree.setAabbFromQuantizeNode(m_quantizedContiguousNodes[0]); | ||
|  | 		subtree.m_rootNodeIndex = 0; | ||
|  | 		subtree.m_subtreeSize = m_quantizedContiguousNodes[0].isLeafNode() ? 1 : m_quantizedContiguousNodes[0].getEscapeIndex(); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	//PCK: update the copy of the size
 | ||
|  | 	m_subtreeHeaderCount = m_SubtreeHeaders.size(); | ||
|  | 
 | ||
|  | 	//PCK: clear m_quantizedLeafNodes and m_leafNodes, they are temporary
 | ||
|  | 	m_quantizedLeafNodes.clear(); | ||
|  | 	m_leafNodes.clear(); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | void	btOptimizedBvh::refit(btStridingMeshInterface* meshInterface,const btVector3& aabbMin,const btVector3& aabbMax) | ||
|  | { | ||
|  | 	if (m_useQuantization) | ||
|  | 	{ | ||
|  | 
 | ||
|  | 		setQuantizationValues(aabbMin,aabbMax); | ||
|  | 
 | ||
|  | 		updateBvhNodes(meshInterface,0,m_curNodeIndex,0); | ||
|  | 
 | ||
|  | 		///now update all subtree headers
 | ||
|  | 
 | ||
|  | 		int i; | ||
|  | 		for (i=0;i<m_SubtreeHeaders.size();i++) | ||
|  | 		{ | ||
|  | 			btBvhSubtreeInfo& subtree = m_SubtreeHeaders[i]; | ||
|  | 			subtree.setAabbFromQuantizeNode(m_quantizedContiguousNodes[subtree.m_rootNodeIndex]); | ||
|  | 		} | ||
|  | 
 | ||
|  | 	} else | ||
|  | 	{ | ||
|  | 
 | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | void	btOptimizedBvh::refitPartial(btStridingMeshInterface* meshInterface,const btVector3& aabbMin,const btVector3& aabbMax) | ||
|  | { | ||
|  | 	//incrementally initialize quantization values
 | ||
|  | 	btAssert(m_useQuantization); | ||
|  | 
 | ||
|  | 	btAssert(aabbMin.getX() > m_bvhAabbMin.getX()); | ||
|  | 	btAssert(aabbMin.getY() > m_bvhAabbMin.getY()); | ||
|  | 	btAssert(aabbMin.getZ() > m_bvhAabbMin.getZ()); | ||
|  | 
 | ||
|  | 	btAssert(aabbMax.getX() < m_bvhAabbMax.getX()); | ||
|  | 	btAssert(aabbMax.getY() < m_bvhAabbMax.getY()); | ||
|  | 	btAssert(aabbMax.getZ() < m_bvhAabbMax.getZ()); | ||
|  | 
 | ||
|  | 	///we should update all quantization values, using updateBvhNodes(meshInterface);
 | ||
|  | 	///but we only update chunks that overlap the given aabb
 | ||
|  | 	 | ||
|  | 	unsigned short	quantizedQueryAabbMin[3]; | ||
|  | 	unsigned short	quantizedQueryAabbMax[3]; | ||
|  | 
 | ||
|  | 	quantize(&quantizedQueryAabbMin[0],aabbMin,0); | ||
|  | 	quantize(&quantizedQueryAabbMax[0],aabbMax,1); | ||
|  | 
 | ||
|  | 	int i; | ||
|  | 	for (i=0;i<this->m_SubtreeHeaders.size();i++) | ||
|  | 	{ | ||
|  | 		btBvhSubtreeInfo& subtree = m_SubtreeHeaders[i]; | ||
|  | 
 | ||
|  | 		//PCK: unsigned instead of bool
 | ||
|  | 		unsigned overlap = testQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin,quantizedQueryAabbMax,subtree.m_quantizedAabbMin,subtree.m_quantizedAabbMax); | ||
|  | 		if (overlap != 0) | ||
|  | 		{ | ||
|  | 			updateBvhNodes(meshInterface,subtree.m_rootNodeIndex,subtree.m_rootNodeIndex+subtree.m_subtreeSize,i); | ||
|  | 
 | ||
|  | 			subtree.setAabbFromQuantizeNode(m_quantizedContiguousNodes[subtree.m_rootNodeIndex]); | ||
|  | 		} | ||
|  | 	} | ||
|  | 	 | ||
|  | } | ||
|  | 
 | ||
|  | void	btOptimizedBvh::updateBvhNodes(btStridingMeshInterface* meshInterface,int firstNode,int endNode,int index) | ||
|  | { | ||
|  | 	(void)index; | ||
|  | 
 | ||
|  | 	btAssert(m_useQuantization); | ||
|  | 
 | ||
|  | 	int curNodeSubPart=-1; | ||
|  | 
 | ||
|  | 	//get access info to trianglemesh data
 | ||
|  | 		const unsigned char *vertexbase = 0; | ||
|  | 		int numverts = 0; | ||
|  | 		PHY_ScalarType type = PHY_INTEGER; | ||
|  | 		int stride = 0; | ||
|  | 		const unsigned char *indexbase = 0; | ||
|  | 		int indexstride = 0; | ||
|  | 		int numfaces = 0; | ||
|  | 		PHY_ScalarType indicestype = PHY_INTEGER; | ||
|  | 
 | ||
|  | 		btVector3	triangleVerts[3]; | ||
|  | 		btVector3	aabbMin,aabbMax; | ||
|  | 		const btVector3& meshScaling = meshInterface->getScaling(); | ||
|  | 		 | ||
|  | 		int i; | ||
|  | 		for (i=endNode-1;i>=firstNode;i--) | ||
|  | 		{ | ||
|  | 
 | ||
|  | 
 | ||
|  | 			btQuantizedBvhNode& curNode = m_quantizedContiguousNodes[i]; | ||
|  | 			if (curNode.isLeafNode()) | ||
|  | 			{ | ||
|  | 				//recalc aabb from triangle data
 | ||
|  | 				int nodeSubPart = curNode.getPartId(); | ||
|  | 				int nodeTriangleIndex = curNode.getTriangleIndex(); | ||
|  | 				if (nodeSubPart != curNodeSubPart) | ||
|  | 				{ | ||
|  | 					if (curNodeSubPart >= 0) | ||
|  | 						meshInterface->unLockReadOnlyVertexBase(curNodeSubPart); | ||
|  | 					meshInterface->getLockedReadOnlyVertexIndexBase(&vertexbase,numverts,	type,stride,&indexbase,indexstride,numfaces,indicestype,nodeSubPart); | ||
|  | 
 | ||
|  | 					curNodeSubPart = nodeSubPart; | ||
|  | 					btAssert(indicestype==PHY_INTEGER||indicestype==PHY_SHORT); | ||
|  | 				} | ||
|  | 				//triangles->getLockedReadOnlyVertexIndexBase(vertexBase,numVerts,
 | ||
|  | 
 | ||
|  | 				unsigned int* gfxbase = (unsigned int*)(indexbase+nodeTriangleIndex*indexstride); | ||
|  | 				 | ||
|  | 				 | ||
|  | 				for (int j=2;j>=0;j--) | ||
|  | 				{ | ||
|  | 					 | ||
|  | 					int graphicsindex = indicestype==PHY_SHORT?((unsigned short*)gfxbase)[j]:gfxbase[j]; | ||
|  | 					if (type == PHY_FLOAT) | ||
|  | 					{ | ||
|  | 						float* graphicsbase = (float*)(vertexbase+graphicsindex*stride); | ||
|  | 						triangleVerts[j] = btVector3( | ||
|  | 							graphicsbase[0]*meshScaling.getX(), | ||
|  | 							graphicsbase[1]*meshScaling.getY(), | ||
|  | 							graphicsbase[2]*meshScaling.getZ()); | ||
|  | 					} | ||
|  | 					else | ||
|  | 					{ | ||
|  | 						double* graphicsbase = (double*)(vertexbase+graphicsindex*stride); | ||
|  | 						triangleVerts[j] = btVector3( btScalar(graphicsbase[0]*meshScaling.getX()), btScalar(graphicsbase[1]*meshScaling.getY()), btScalar(graphicsbase[2]*meshScaling.getZ())); | ||
|  | 					} | ||
|  | 				} | ||
|  | 
 | ||
|  | 
 | ||
|  | 				 | ||
|  | 				aabbMin.setValue(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); | ||
|  | 				aabbMax.setValue(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT));  | ||
|  | 				aabbMin.setMin(triangleVerts[0]); | ||
|  | 				aabbMax.setMax(triangleVerts[0]); | ||
|  | 				aabbMin.setMin(triangleVerts[1]); | ||
|  | 				aabbMax.setMax(triangleVerts[1]); | ||
|  | 				aabbMin.setMin(triangleVerts[2]); | ||
|  | 				aabbMax.setMax(triangleVerts[2]); | ||
|  | 
 | ||
|  | 				quantize(&curNode.m_quantizedAabbMin[0],aabbMin,0); | ||
|  | 				quantize(&curNode.m_quantizedAabbMax[0],aabbMax,1); | ||
|  | 				 | ||
|  | 			} else | ||
|  | 			{ | ||
|  | 				//combine aabb from both children
 | ||
|  | 
 | ||
|  | 				btQuantizedBvhNode* leftChildNode = &m_quantizedContiguousNodes[i+1]; | ||
|  | 				 | ||
|  | 				btQuantizedBvhNode* rightChildNode = leftChildNode->isLeafNode() ? &m_quantizedContiguousNodes[i+2] : | ||
|  | 					&m_quantizedContiguousNodes[i+1+leftChildNode->getEscapeIndex()]; | ||
|  | 				 | ||
|  | 
 | ||
|  | 				{ | ||
|  | 					for (int i=0;i<3;i++) | ||
|  | 					{ | ||
|  | 						curNode.m_quantizedAabbMin[i] = leftChildNode->m_quantizedAabbMin[i]; | ||
|  | 						if (curNode.m_quantizedAabbMin[i]>rightChildNode->m_quantizedAabbMin[i]) | ||
|  | 							curNode.m_quantizedAabbMin[i]=rightChildNode->m_quantizedAabbMin[i]; | ||
|  | 
 | ||
|  | 						curNode.m_quantizedAabbMax[i] = leftChildNode->m_quantizedAabbMax[i]; | ||
|  | 						if (curNode.m_quantizedAabbMax[i] < rightChildNode->m_quantizedAabbMax[i]) | ||
|  | 							curNode.m_quantizedAabbMax[i] = rightChildNode->m_quantizedAabbMax[i]; | ||
|  | 					} | ||
|  | 				} | ||
|  | 			} | ||
|  | 
 | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if (curNodeSubPart >= 0) | ||
|  | 			meshInterface->unLockReadOnlyVertexBase(curNodeSubPart); | ||
|  | 
 | ||
|  | 		 | ||
|  | } | ||
|  | 
 | ||
|  | ///deSerializeInPlace loads and initializes a BVH from a buffer in memory 'in place'
 | ||
|  | btOptimizedBvh* btOptimizedBvh::deSerializeInPlace(void *i_alignedDataBuffer, unsigned int i_dataBufferSize, bool i_swapEndian) | ||
|  | { | ||
|  | 	btQuantizedBvh* bvh = btQuantizedBvh::deSerializeInPlace(i_alignedDataBuffer,i_dataBufferSize,i_swapEndian); | ||
|  | 	 | ||
|  | 	//we don't add additional data so just do a static upcast
 | ||
|  | 	return static_cast<btOptimizedBvh*>(bvh); | ||
|  | } |