forked from LeenkxTeam/LNXSDK
		
	
		
			
				
	
	
		
			501 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			501 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.
 | |
| */
 | |
| #if defined (_WIN32) || defined (__i386__)
 | |
| #define BT_USE_SSE_IN_API
 | |
| #endif
 | |
| 
 | |
| #include "BulletCollision/CollisionShapes/btPolyhedralConvexShape.h"
 | |
| #include "btConvexPolyhedron.h"
 | |
| #include "LinearMath/btConvexHullComputer.h"
 | |
| #include <new>
 | |
| #include "LinearMath/btGeometryUtil.h"
 | |
| #include "LinearMath/btGrahamScan2dConvexHull.h"
 | |
| 
 | |
| 
 | |
| btPolyhedralConvexShape::btPolyhedralConvexShape() :btConvexInternalShape(),
 | |
| m_polyhedron(0)
 | |
| {
 | |
| 
 | |
| }
 | |
| 
 | |
| btPolyhedralConvexShape::~btPolyhedralConvexShape()
 | |
| {
 | |
| 	if (m_polyhedron)
 | |
| 	{
 | |
| 		m_polyhedron->~btConvexPolyhedron();
 | |
| 		btAlignedFree(m_polyhedron);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| bool	btPolyhedralConvexShape::initializePolyhedralFeatures(int shiftVerticesByMargin)
 | |
| {
 | |
| 
 | |
| 	if (m_polyhedron)
 | |
| 	{
 | |
| 		m_polyhedron->~btConvexPolyhedron();
 | |
| 		btAlignedFree(m_polyhedron);
 | |
| 	}
 | |
| 	
 | |
| 	void* mem = btAlignedAlloc(sizeof(btConvexPolyhedron),16);
 | |
| 	m_polyhedron = new (mem) btConvexPolyhedron;
 | |
| 
 | |
| 	btAlignedObjectArray<btVector3> orgVertices;
 | |
| 
 | |
| 	for (int i=0;i<getNumVertices();i++)
 | |
| 	{
 | |
| 		btVector3& newVertex = orgVertices.expand();
 | |
| 		getVertex(i,newVertex);
 | |
| 	}
 | |
| 	
 | |
| 	btConvexHullComputer conv;
 | |
| 	
 | |
| 	if (shiftVerticesByMargin)
 | |
| 	{
 | |
| 		btAlignedObjectArray<btVector3> planeEquations;
 | |
| 		btGeometryUtil::getPlaneEquationsFromVertices(orgVertices,planeEquations);
 | |
| 
 | |
| 		btAlignedObjectArray<btVector3> shiftedPlaneEquations;
 | |
| 		for (int p=0;p<planeEquations.size();p++)
 | |
| 		{
 | |
| 			   btVector3 plane = planeEquations[p];
 | |
| 		//	   btScalar margin = getMargin();
 | |
| 			   plane[3] -= getMargin();
 | |
| 			   shiftedPlaneEquations.push_back(plane);
 | |
| 		}
 | |
| 
 | |
| 		btAlignedObjectArray<btVector3> tmpVertices;
 | |
| 
 | |
| 		btGeometryUtil::getVerticesFromPlaneEquations(shiftedPlaneEquations,tmpVertices);
 | |
| 	
 | |
| 		conv.compute(&tmpVertices[0].getX(), sizeof(btVector3),tmpVertices.size(),0.f,0.f);
 | |
| 	} else
 | |
| 	{
 | |
| 		
 | |
| 		conv.compute(&orgVertices[0].getX(), sizeof(btVector3),orgVertices.size(),0.f,0.f);
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 
 | |
| 	btAlignedObjectArray<btVector3> faceNormals;
 | |
| 	int numFaces = conv.faces.size();
 | |
| 	faceNormals.resize(numFaces);
 | |
| 	btConvexHullComputer* convexUtil = &conv;
 | |
| 
 | |
| 	
 | |
| 	btAlignedObjectArray<btFace>	tmpFaces;
 | |
| 	tmpFaces.resize(numFaces);
 | |
| 
 | |
| 	int numVertices = convexUtil->vertices.size();
 | |
| 	m_polyhedron->m_vertices.resize(numVertices);
 | |
| 	for (int p=0;p<numVertices;p++)
 | |
| 	{
 | |
| 		m_polyhedron->m_vertices[p] = convexUtil->vertices[p];
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 	for (int i=0;i<numFaces;i++)
 | |
| 	{
 | |
| 		int face = convexUtil->faces[i];
 | |
| 		//printf("face=%d\n",face);
 | |
| 		const btConvexHullComputer::Edge*  firstEdge = &convexUtil->edges[face];
 | |
| 		const btConvexHullComputer::Edge*  edge = firstEdge;
 | |
| 
 | |
| 		btVector3 edges[3];
 | |
| 		int numEdges = 0;
 | |
| 		//compute face normals
 | |
| 
 | |
| 		do
 | |
| 		{
 | |
| 			
 | |
| 			int src = edge->getSourceVertex();
 | |
| 			tmpFaces[i].m_indices.push_back(src);
 | |
| 			int targ = edge->getTargetVertex();
 | |
| 			btVector3 wa = convexUtil->vertices[src];
 | |
| 
 | |
| 			btVector3 wb = convexUtil->vertices[targ];
 | |
| 			btVector3 newEdge = wb-wa;
 | |
| 			newEdge.normalize();
 | |
| 			if (numEdges<2)
 | |
| 				edges[numEdges++] = newEdge;
 | |
| 
 | |
| 			edge = edge->getNextEdgeOfFace();
 | |
| 		} while (edge!=firstEdge);
 | |
| 
 | |
| 		btScalar planeEq = 1e30f;
 | |
| 
 | |
| 		
 | |
| 		if (numEdges==2)
 | |
| 		{
 | |
| 			faceNormals[i] = edges[0].cross(edges[1]);
 | |
| 			faceNormals[i].normalize();
 | |
| 			tmpFaces[i].m_plane[0] = faceNormals[i].getX();
 | |
| 			tmpFaces[i].m_plane[1] = faceNormals[i].getY();
 | |
| 			tmpFaces[i].m_plane[2] = faceNormals[i].getZ();
 | |
| 			tmpFaces[i].m_plane[3] = planeEq;
 | |
| 
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			btAssert(0);//degenerate?
 | |
| 			faceNormals[i].setZero();
 | |
| 		}
 | |
| 
 | |
| 		for (int v=0;v<tmpFaces[i].m_indices.size();v++)
 | |
| 		{
 | |
| 			btScalar eq = m_polyhedron->m_vertices[tmpFaces[i].m_indices[v]].dot(faceNormals[i]);
 | |
| 			if (planeEq>eq)
 | |
| 			{
 | |
| 				planeEq=eq;
 | |
| 			}
 | |
| 		}
 | |
| 		tmpFaces[i].m_plane[3] = -planeEq;
 | |
| 	}
 | |
| 
 | |
| 	//merge coplanar faces and copy them to m_polyhedron
 | |
| 
 | |
| 	btScalar faceWeldThreshold= 0.999f;
 | |
| 	btAlignedObjectArray<int> todoFaces;
 | |
| 	for (int i=0;i<tmpFaces.size();i++)
 | |
| 		todoFaces.push_back(i);
 | |
| 
 | |
| 	while (todoFaces.size())
 | |
| 	{
 | |
| 		btAlignedObjectArray<int> coplanarFaceGroup;
 | |
| 		int refFace = todoFaces[todoFaces.size()-1];
 | |
| 
 | |
| 		coplanarFaceGroup.push_back(refFace);
 | |
| 		btFace& faceA = tmpFaces[refFace];
 | |
| 		todoFaces.pop_back();
 | |
| 
 | |
| 		btVector3 faceNormalA(faceA.m_plane[0],faceA.m_plane[1],faceA.m_plane[2]);
 | |
| 		for (int j=todoFaces.size()-1;j>=0;j--)
 | |
| 		{
 | |
| 			int i = todoFaces[j];
 | |
| 			btFace& faceB = tmpFaces[i];
 | |
| 			btVector3 faceNormalB(faceB.m_plane[0],faceB.m_plane[1],faceB.m_plane[2]);
 | |
| 			if (faceNormalA.dot(faceNormalB)>faceWeldThreshold)
 | |
| 			{
 | |
| 				coplanarFaceGroup.push_back(i);
 | |
| 				todoFaces.remove(i);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		bool did_merge = false;
 | |
| 		if (coplanarFaceGroup.size()>1)
 | |
| 		{
 | |
| 			//do the merge: use Graham Scan 2d convex hull
 | |
| 
 | |
| 			btAlignedObjectArray<GrahamVector3> orgpoints;
 | |
| 			btVector3 averageFaceNormal(0,0,0);
 | |
| 
 | |
| 			for (int i=0;i<coplanarFaceGroup.size();i++)
 | |
| 			{
 | |
| //				m_polyhedron->m_faces.push_back(tmpFaces[coplanarFaceGroup[i]]);
 | |
| 
 | |
| 				btFace& face = tmpFaces[coplanarFaceGroup[i]];
 | |
| 				btVector3 faceNormal(face.m_plane[0],face.m_plane[1],face.m_plane[2]);
 | |
| 				averageFaceNormal+=faceNormal;
 | |
| 				for (int f=0;f<face.m_indices.size();f++)
 | |
| 				{
 | |
| 					int orgIndex = face.m_indices[f];
 | |
| 					btVector3 pt = m_polyhedron->m_vertices[orgIndex];
 | |
| 					
 | |
| 					bool found = false;
 | |
| 
 | |
| 					for (int i=0;i<orgpoints.size();i++)
 | |
| 					{
 | |
| 						//if ((orgpoints[i].m_orgIndex == orgIndex) || ((rotatedPt-orgpoints[i]).length2()<0.0001))
 | |
| 						if (orgpoints[i].m_orgIndex == orgIndex)
 | |
| 						{
 | |
| 							found=true;
 | |
| 							break;
 | |
| 						}
 | |
| 					}
 | |
| 					if (!found)
 | |
| 						orgpoints.push_back(GrahamVector3(pt,orgIndex));
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			
 | |
| 
 | |
| 			btFace combinedFace;
 | |
| 			for (int i=0;i<4;i++)
 | |
| 				combinedFace.m_plane[i] = tmpFaces[coplanarFaceGroup[0]].m_plane[i];
 | |
| 
 | |
| 			btAlignedObjectArray<GrahamVector3> hull;
 | |
| 
 | |
| 			averageFaceNormal.normalize();
 | |
| 			GrahamScanConvexHull2D(orgpoints,hull,averageFaceNormal);
 | |
| 
 | |
| 			for (int i=0;i<hull.size();i++)
 | |
| 			{
 | |
| 				combinedFace.m_indices.push_back(hull[i].m_orgIndex);
 | |
| 				for(int k = 0; k < orgpoints.size(); k++) 
 | |
| 				{
 | |
| 					if(orgpoints[k].m_orgIndex == hull[i].m_orgIndex) 
 | |
| 					{
 | |
| 						orgpoints[k].m_orgIndex = -1; // invalidate...
 | |
| 						break;
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			// are there rejected vertices?
 | |
| 			bool reject_merge = false;
 | |
| 			
 | |
| 
 | |
| 
 | |
| 			for(int i = 0; i < orgpoints.size(); i++) {
 | |
| 				if(orgpoints[i].m_orgIndex == -1)
 | |
| 					continue; // this is in the hull...
 | |
| 				// this vertex is rejected -- is anybody else using this vertex?
 | |
| 				for(int j = 0; j < tmpFaces.size(); j++) {
 | |
| 					
 | |
| 					btFace& face = tmpFaces[j];
 | |
| 					// is this a face of the current coplanar group?
 | |
| 					bool is_in_current_group = false;
 | |
| 					for(int k = 0; k < coplanarFaceGroup.size(); k++) {
 | |
| 						if(coplanarFaceGroup[k] == j) {
 | |
| 							is_in_current_group = true;
 | |
| 							break;
 | |
| 						}
 | |
| 					}
 | |
| 					if(is_in_current_group) // ignore this face...
 | |
| 						continue;
 | |
| 					// does this face use this rejected vertex?
 | |
| 					for(int v = 0; v < face.m_indices.size(); v++) {
 | |
| 						if(face.m_indices[v] == orgpoints[i].m_orgIndex) {
 | |
| 							// this rejected vertex is used in another face -- reject merge
 | |
| 							reject_merge = true;
 | |
| 							break;
 | |
| 						}
 | |
| 					}
 | |
| 					if(reject_merge)
 | |
| 						break;
 | |
| 				}
 | |
| 				if(reject_merge)
 | |
| 					break;
 | |
| 			}
 | |
| 
 | |
| 			if (!reject_merge)
 | |
| 			{
 | |
| 				// do this merge!
 | |
| 				did_merge = true;
 | |
| 				m_polyhedron->m_faces.push_back(combinedFace);
 | |
| 			}
 | |
| 		}
 | |
| 		if(!did_merge)
 | |
| 		{
 | |
| 			for (int i=0;i<coplanarFaceGroup.size();i++)
 | |
| 			{
 | |
| 				btFace face = tmpFaces[coplanarFaceGroup[i]];
 | |
| 				m_polyhedron->m_faces.push_back(face);
 | |
| 			}
 | |
| 
 | |
| 		} 
 | |
| 
 | |
| 
 | |
| 
 | |
| 	}
 | |
| 	
 | |
| 	m_polyhedron->initialize();
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| #ifndef MIN
 | |
|     #define MIN(_a, _b)     ((_a) < (_b) ? (_a) : (_b))
 | |
| #endif
 | |
| 
 | |
| btVector3	btPolyhedralConvexShape::localGetSupportingVertexWithoutMargin(const btVector3& vec0)const
 | |
| {
 | |
| 
 | |
| 
 | |
| 	btVector3 supVec(0,0,0);
 | |
| #ifndef __SPU__
 | |
| 	int i;
 | |
| 	btScalar maxDot(btScalar(-BT_LARGE_FLOAT));
 | |
| 
 | |
| 	btVector3 vec = vec0;
 | |
| 	btScalar lenSqr = vec.length2();
 | |
| 	if (lenSqr < btScalar(0.0001))
 | |
| 	{
 | |
| 		vec.setValue(1,0,0);
 | |
| 	} else
 | |
| 	{
 | |
| 		btScalar rlen = btScalar(1.) / btSqrt(lenSqr );
 | |
| 		vec *= rlen;
 | |
| 	}
 | |
| 
 | |
| 	btVector3 vtx;
 | |
| 	btScalar newDot;
 | |
| 
 | |
|     for( int k = 0; k < getNumVertices(); k += 128 )
 | |
|     {
 | |
|         btVector3 temp[128];
 | |
|         int inner_count = MIN(getNumVertices() - k, 128);
 | |
|         for( i = 0; i < inner_count; i++ )
 | |
|             getVertex(i,temp[i]); 
 | |
|         i = (int) vec.maxDot( temp, inner_count, newDot);
 | |
| 		if (newDot > maxDot)
 | |
| 		{
 | |
| 			maxDot = newDot;
 | |
| 			supVec = temp[i];
 | |
| 		}        
 | |
|     }
 | |
| 	
 | |
| #endif //__SPU__
 | |
| 	return supVec;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void	btPolyhedralConvexShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const
 | |
| {
 | |
| #ifndef __SPU__
 | |
| 	int i;
 | |
| 
 | |
| 	btVector3 vtx;
 | |
| 	btScalar newDot;
 | |
| 
 | |
| 	for (i=0;i<numVectors;i++)
 | |
| 	{
 | |
| 		supportVerticesOut[i][3] = btScalar(-BT_LARGE_FLOAT);
 | |
| 	}
 | |
| 
 | |
| 	for (int j=0;j<numVectors;j++)
 | |
| 	{
 | |
|         const btVector3& vec = vectors[j];
 | |
|         
 | |
|         for( int k = 0; k < getNumVertices(); k += 128 )
 | |
|         {
 | |
|             btVector3 temp[128];
 | |
|             int inner_count = MIN(getNumVertices() - k, 128);
 | |
|             for( i = 0; i < inner_count; i++ )
 | |
|                 getVertex(i,temp[i]); 
 | |
|             i = (int) vec.maxDot( temp, inner_count, newDot);
 | |
|             if (newDot > supportVerticesOut[j][3])
 | |
|             {
 | |
| 				supportVerticesOut[j] = temp[i];
 | |
| 				supportVerticesOut[j][3] = newDot;
 | |
|             }        
 | |
|         }
 | |
|     }
 | |
| 
 | |
| #endif //__SPU__
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void	btPolyhedralConvexShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const
 | |
| {
 | |
| #ifndef __SPU__
 | |
| 	//not yet, return box inertia
 | |
| 
 | |
| 	btScalar margin = getMargin();
 | |
| 
 | |
| 	btTransform ident;
 | |
| 	ident.setIdentity();
 | |
| 	btVector3 aabbMin,aabbMax;
 | |
| 	getAabb(ident,aabbMin,aabbMax);
 | |
| 	btVector3 halfExtents = (aabbMax-aabbMin)*btScalar(0.5);
 | |
| 
 | |
| 	btScalar lx=btScalar(2.)*(halfExtents.x()+margin);
 | |
| 	btScalar ly=btScalar(2.)*(halfExtents.y()+margin);
 | |
| 	btScalar lz=btScalar(2.)*(halfExtents.z()+margin);
 | |
| 	const btScalar x2 = lx*lx;
 | |
| 	const btScalar y2 = ly*ly;
 | |
| 	const btScalar z2 = lz*lz;
 | |
| 	const btScalar scaledmass = mass * btScalar(0.08333333);
 | |
| 
 | |
| 	inertia = scaledmass * (btVector3(y2+z2,x2+z2,x2+y2));
 | |
| #endif //__SPU__
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void	btPolyhedralConvexAabbCachingShape::setLocalScaling(const btVector3& scaling)
 | |
| {
 | |
| 	btConvexInternalShape::setLocalScaling(scaling);
 | |
| 	recalcLocalAabb();
 | |
| }
 | |
| 
 | |
| btPolyhedralConvexAabbCachingShape::btPolyhedralConvexAabbCachingShape()
 | |
| :btPolyhedralConvexShape(),
 | |
| m_localAabbMin(1,1,1),
 | |
| m_localAabbMax(-1,-1,-1),
 | |
| m_isLocalAabbValid(false)
 | |
| {
 | |
| }
 | |
| 
 | |
| void btPolyhedralConvexAabbCachingShape::getAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax) const
 | |
| {
 | |
| 	getNonvirtualAabb(trans,aabbMin,aabbMax,getMargin());
 | |
| }
 | |
| 
 | |
| void	btPolyhedralConvexAabbCachingShape::recalcLocalAabb()
 | |
| {
 | |
| 	m_isLocalAabbValid = true;
 | |
| 	
 | |
| 	#if 1
 | |
| 	static const btVector3 _directions[] =
 | |
| 	{
 | |
| 		btVector3( 1.,  0.,  0.),
 | |
| 		btVector3( 0.,  1.,  0.),
 | |
| 		btVector3( 0.,  0.,  1.),
 | |
| 		btVector3( -1., 0.,  0.),
 | |
| 		btVector3( 0., -1.,  0.),
 | |
| 		btVector3( 0.,  0., -1.)
 | |
| 	};
 | |
| 	
 | |
| 	btVector3 _supporting[] =
 | |
| 	{
 | |
| 		btVector3( 0., 0., 0.),
 | |
| 		btVector3( 0., 0., 0.),
 | |
| 		btVector3( 0., 0., 0.),
 | |
| 		btVector3( 0., 0., 0.),
 | |
| 		btVector3( 0., 0., 0.),
 | |
| 		btVector3( 0., 0., 0.)
 | |
| 	};
 | |
| 	
 | |
| 	batchedUnitVectorGetSupportingVertexWithoutMargin(_directions, _supporting, 6);
 | |
| 	
 | |
| 	for ( int i = 0; i < 3; ++i )
 | |
| 	{
 | |
| 		m_localAabbMax[i] = _supporting[i][i] + m_collisionMargin;
 | |
| 		m_localAabbMin[i] = _supporting[i + 3][i] - m_collisionMargin;
 | |
| 	}
 | |
| 	
 | |
| 	#else
 | |
| 
 | |
| 	for (int i=0;i<3;i++)
 | |
| 	{
 | |
| 		btVector3 vec(btScalar(0.),btScalar(0.),btScalar(0.));
 | |
| 		vec[i] = btScalar(1.);
 | |
| 		btVector3 tmp = localGetSupportingVertex(vec);
 | |
| 		m_localAabbMax[i] = tmp[i];
 | |
| 		vec[i] = btScalar(-1.);
 | |
| 		tmp = localGetSupportingVertex(vec);
 | |
| 		m_localAabbMin[i] = tmp[i];
 | |
| 	}
 | |
| 	#endif
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 |