#include "std.h" #include "meshcollider.h" static const int MAX_COLL_TRIS=16; static vector tri_centres; extern float stats3d[10]; extern gxRuntime *gx_runtime; static bool triTest( const Vector a[3],const Vector b[3] ){ bool pb0=false,pb1=false,pb2=false; Plane p( a[0],a[1],a[2] ),p0,p1,p2; for( int k=0;k<3;++k ){ Line l( b[k],b[(k+1)%3]-b[k] ); float t=p.t_intersect( l ); if( t<0 || t>1 ) continue; Vector i=l*t; if( !pb0 ){ p0=Plane( a[0]+p.n,a[1],a[0] );pb0=true; } if( p0.distance( i )<0 ) continue; if( !pb1 ){ p1=Plane( a[1]+p.n,a[2],a[1] );pb1=true; } if( p1.distance( i )<0 ) continue; if( !pb2 ){ p2=Plane( a[2]+p.n,a[0],a[2] );pb2=true; } if( p2.distance( i )<0 ) continue; return true; } return false; } static bool trisIntersect( const Vector a[3],const Vector b[3] ){ return triTest( a,b ) || triTest( b,a ); } MeshCollider::MeshCollider( const vector &verts,const vector &tris ): vertices(verts),triangles(tris){ vector ts; tri_centres.clear(); for( int k=0;kbox ) ){ return false; } bool hit=false; if( !node->triangles.size() ){ if( node->left ) hit|=collide( line_box,line,radius,tform,curr_coll,node->left ); if( node->right ) hit|=collide( line_box,line,radius,tform,curr_coll,node->right ); return hit; } stats3d[0]+=node->triangles.size(); for( int k=0;ktriangles.size();++k ){ const Triangle &tri=triangles[node->triangles[k]]; const Vector &t_v0=vertices[ tri.verts[0] ].coords; const Vector &t_v1=vertices[ tri.verts[1] ].coords; const Vector &t_v2=vertices[ tri.verts[2] ].coords; //tri box Box tri_box( t_v0 ); tri_box.update( t_v1 ); tri_box.update( t_v2 ); if( !tri_box.overlaps( line_box ) ) continue; if( !curr_coll->triangleCollide( line,radius,tform*t_v0,tform*t_v1,tform*t_v2 ) ) continue; curr_coll->surface=tri.surface; curr_coll->index=tri.index; hit=true; } return hit; } Box MeshCollider::nodeBox( const vector &tris ){ Box box; for( int k=0;k &tris ){ Node *c=new Node; c->box=nodeBox( tris ); c->triangles=tris; leaves.push_back( c ); return c; } MeshCollider::Node *MeshCollider::createNode( const vector &tris ){ if( tris.size()<=MAX_COLL_TRIS ) return createLeaf( tris ); Node *c=new Node; c->box=nodeBox( tris ); //find longest axis // float max=c->box.width(); if( c->box.height()>max ) max=c->box.height(); if( c->box.depth()>max ) max=c->box.depth(); int axis=0; if( max==c->box.height() ) axis=1; else if( max==c->box.depth() ) axis=2; //sort by axis // int k; multimap axis_map; for( k=0;k p( tri_centres[tris[k]][axis],tris[k] ); axis_map.insert( p ); } //generate left node // vector new_tris; multimap::iterator it=axis_map.begin(); for( k=axis_map.size()/2;k--;++it ){ new_tris.push_back( it->second ); } c->left=createNode( new_tris ); //generate right node // new_tris.clear(); for( ;it!=axis_map.end();++it ){ new_tris.push_back( it->second ); } c->right=createNode( new_tris ); return c; } bool MeshCollider::intersects( const MeshCollider &c,const Transform &t )const{ static Vector a[MAX_COLL_TRIS][3],b[3]; if( !(t * tree->box).overlaps( c.tree->box ) ) return false; for( int k=0;kbox; bool tformed=false; for( int j=0;jbox ) ) continue; if( !tformed ){ for( int n=0;ntriangles.size();++n ){ const Triangle &tri=triangles[p->triangles[n]]; a[n][0]=t * vertices[tri.verts[0]].coords; a[n][1]=t * vertices[tri.verts[1]].coords; a[n][2]=t * vertices[tri.verts[2]].coords; } tformed=true; } for( int n=0;ntriangles.size();++n ){ const Triangle &tri=c.triangles[q->triangles[n]]; b[0]=c.vertices[tri.verts[0]].coords; b[1]=c.vertices[tri.verts[1]].coords; b[2]=c.vertices[tri.verts[2]].coords; for( int t=0;ttriangles.size();++t ){ if( trisIntersect( a[t],b ) ) return true; } } } } return false; }