00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include <string.h>
00017
00018 #include "btConvexHull.h"
00019 #include "btAlignedObjectArray.h"
00020 #include "btMinMax.h"
00021 #include "btVector3.h"
00022
00023
00024
00025 template <class T>
00026 void Swap(T &a,T &b)
00027 {
00028 T tmp = a;
00029 a=b;
00030 b=tmp;
00031 }
00032
00033
00034
00035
00036 class int3
00037 {
00038 public:
00039 int x,y,z;
00040 int3(){};
00041 int3(int _x,int _y, int _z){x=_x;y=_y;z=_z;}
00042 const int& operator[](int i) const {return (&x)[i];}
00043 int& operator[](int i) {return (&x)[i];}
00044 };
00045
00046
00047
00048
00049
00050 inline btPlane PlaneFlip(const btPlane &plane){return btPlane(-plane.normal,-plane.dist);}
00051 inline int operator==( const btPlane &a, const btPlane &b ) { return (a.normal==b.normal && a.dist==b.dist); }
00052 inline int coplanar( const btPlane &a, const btPlane &b ) { return (a==b || a==PlaneFlip(b)); }
00053
00054
00055
00056
00057 btVector3 PlaneLineIntersection(const btPlane &plane, const btVector3 &p0, const btVector3 &p1);
00058 btVector3 PlaneProject(const btPlane &plane, const btVector3 &point);
00059
00060 btVector3 ThreePlaneIntersection(const btPlane &p0,const btPlane &p1, const btPlane &p2);
00061 btVector3 ThreePlaneIntersection(const btPlane &p0,const btPlane &p1, const btPlane &p2)
00062 {
00063 btVector3 N1 = p0.normal;
00064 btVector3 N2 = p1.normal;
00065 btVector3 N3 = p2.normal;
00066
00067 btVector3 n2n3; n2n3 = N2.cross(N3);
00068 btVector3 n3n1; n3n1 = N3.cross(N1);
00069 btVector3 n1n2; n1n2 = N1.cross(N2);
00070
00071 btScalar quotient = (N1.dot(n2n3));
00072
00073 btAssert(btFabs(quotient) > btScalar(0.000001));
00074
00075 quotient = btScalar(-1.) / quotient;
00076 n2n3 *= p0.dist;
00077 n3n1 *= p1.dist;
00078 n1n2 *= p2.dist;
00079 btVector3 potentialVertex = n2n3;
00080 potentialVertex += n3n1;
00081 potentialVertex += n1n2;
00082 potentialVertex *= quotient;
00083
00084 btVector3 result(potentialVertex.getX(),potentialVertex.getY(),potentialVertex.getZ());
00085 return result;
00086
00087 }
00088
00089 btScalar DistanceBetweenLines(const btVector3 &ustart, const btVector3 &udir, const btVector3 &vstart, const btVector3 &vdir, btVector3 *upoint=NULL, btVector3 *vpoint=NULL);
00090 btVector3 TriNormal(const btVector3 &v0, const btVector3 &v1, const btVector3 &v2);
00091 btVector3 NormalOf(const btVector3 *vert, const int n);
00092
00093
00094 btVector3 PlaneLineIntersection(const btPlane &plane, const btVector3 &p0, const btVector3 &p1)
00095 {
00096
00097 static btVector3 dif;
00098 dif = p1-p0;
00099 btScalar dn= btDot(plane.normal,dif);
00100 btScalar t = -(plane.dist+btDot(plane.normal,p0) )/dn;
00101 return p0 + (dif*t);
00102 }
00103
00104 btVector3 PlaneProject(const btPlane &plane, const btVector3 &point)
00105 {
00106 return point - plane.normal * (btDot(point,plane.normal)+plane.dist);
00107 }
00108
00109 btVector3 TriNormal(const btVector3 &v0, const btVector3 &v1, const btVector3 &v2)
00110 {
00111
00112
00113 btVector3 cp=btCross(v1-v0,v2-v1);
00114 btScalar m=cp.length();
00115 if(m==0) return btVector3(1,0,0);
00116 return cp*(btScalar(1.0)/m);
00117 }
00118
00119
00120 btScalar DistanceBetweenLines(const btVector3 &ustart, const btVector3 &udir, const btVector3 &vstart, const btVector3 &vdir, btVector3 *upoint, btVector3 *vpoint)
00121 {
00122 static btVector3 cp;
00123 cp = btCross(udir,vdir).normalized();
00124
00125 btScalar distu = -btDot(cp,ustart);
00126 btScalar distv = -btDot(cp,vstart);
00127 btScalar dist = (btScalar)fabs(distu-distv);
00128 if(upoint)
00129 {
00130 btPlane plane;
00131 plane.normal = btCross(vdir,cp).normalized();
00132 plane.dist = -btDot(plane.normal,vstart);
00133 *upoint = PlaneLineIntersection(plane,ustart,ustart+udir);
00134 }
00135 if(vpoint)
00136 {
00137 btPlane plane;
00138 plane.normal = btCross(udir,cp).normalized();
00139 plane.dist = -btDot(plane.normal,ustart);
00140 *vpoint = PlaneLineIntersection(plane,vstart,vstart+vdir);
00141 }
00142 return dist;
00143 }
00144
00145
00146
00147
00148
00149
00150
00151 #define COPLANAR (0)
00152 #define UNDER (1)
00153 #define OVER (2)
00154 #define SPLIT (OVER|UNDER)
00155 #define PAPERWIDTH (btScalar(0.001))
00156
00157 btScalar planetestepsilon = PAPERWIDTH;
00158
00159
00160
00161 typedef ConvexH::HalfEdge HalfEdge;
00162
00163 ConvexH::ConvexH(int vertices_size,int edges_size,int facets_size)
00164 {
00165 vertices.resize(vertices_size);
00166 edges.resize(edges_size);
00167 facets.resize(facets_size);
00168 }
00169
00170
00171 int PlaneTest(const btPlane &p, const btVector3 &v);
00172 int PlaneTest(const btPlane &p, const btVector3 &v) {
00173 btScalar a = btDot(v,p.normal)+p.dist;
00174 int flag = (a>planetestepsilon)?OVER:((a<-planetestepsilon)?UNDER:COPLANAR);
00175 return flag;
00176 }
00177
00178 int SplitTest(ConvexH &convex,const btPlane &plane);
00179 int SplitTest(ConvexH &convex,const btPlane &plane) {
00180 int flag=0;
00181 for(int i=0;i<convex.vertices.size();i++) {
00182 flag |= PlaneTest(plane,convex.vertices[i]);
00183 }
00184 return flag;
00185 }
00186
00187 class VertFlag
00188 {
00189 public:
00190 unsigned char planetest;
00191 unsigned char junk;
00192 unsigned char undermap;
00193 unsigned char overmap;
00194 };
00195 class EdgeFlag
00196 {
00197 public:
00198 unsigned char planetest;
00199 unsigned char fixes;
00200 short undermap;
00201 short overmap;
00202 };
00203 class PlaneFlag
00204 {
00205 public:
00206 unsigned char undermap;
00207 unsigned char overmap;
00208 };
00209 class Coplanar{
00210 public:
00211 unsigned short ea;
00212 unsigned char v0;
00213 unsigned char v1;
00214 };
00215
00216
00217
00218
00219
00220
00221
00222
00223 template<class T>
00224 int maxdirfiltered(const T *p,int count,const T &dir,btAlignedObjectArray<int> &allow)
00225 {
00226 btAssert(count);
00227 int m=-1;
00228 for(int i=0;i<count;i++)
00229 if(allow[i])
00230 {
00231 if(m==-1 || btDot(p[i],dir)>btDot(p[m],dir))
00232 m=i;
00233 }
00234 btAssert(m!=-1);
00235 return m;
00236 }
00237
00238 btVector3 orth(const btVector3 &v);
00239 btVector3 orth(const btVector3 &v)
00240 {
00241 btVector3 a=btCross(v,btVector3(0,0,1));
00242 btVector3 b=btCross(v,btVector3(0,1,0));
00243 if (a.length() > b.length())
00244 {
00245 return a.normalized();
00246 } else {
00247 return b.normalized();
00248 }
00249 }
00250
00251
00252 template<class T>
00253 int maxdirsterid(const T *p,int count,const T &dir,btAlignedObjectArray<int> &allow)
00254 {
00255 int m=-1;
00256 while(m==-1)
00257 {
00258 m = maxdirfiltered(p,count,dir,allow);
00259 if(allow[m]==3) return m;
00260 T u = orth(dir);
00261 T v = btCross(u,dir);
00262 int ma=-1;
00263 for(btScalar x = btScalar(0.0) ; x<= btScalar(360.0) ; x+= btScalar(45.0))
00264 {
00265 btScalar s = btSin(SIMD_RADS_PER_DEG*(x));
00266 btScalar c = btCos(SIMD_RADS_PER_DEG*(x));
00267 int mb = maxdirfiltered(p,count,dir+(u*s+v*c)*btScalar(0.025),allow);
00268 if(ma==m && mb==m)
00269 {
00270 allow[m]=3;
00271 return m;
00272 }
00273 if(ma!=-1 && ma!=mb)
00274 {
00275 int mc = ma;
00276 for(btScalar xx = x-btScalar(40.0) ; xx <= x ; xx+= btScalar(5.0))
00277 {
00278 btScalar s = btSin(SIMD_RADS_PER_DEG*(xx));
00279 btScalar c = btCos(SIMD_RADS_PER_DEG*(xx));
00280 int md = maxdirfiltered(p,count,dir+(u*s+v*c)*btScalar(0.025),allow);
00281 if(mc==m && md==m)
00282 {
00283 allow[m]=3;
00284 return m;
00285 }
00286 mc=md;
00287 }
00288 }
00289 ma=mb;
00290 }
00291 allow[m]=0;
00292 m=-1;
00293 }
00294 btAssert(0);
00295 return m;
00296 }
00297
00298
00299
00300
00301 int operator ==(const int3 &a,const int3 &b);
00302 int operator ==(const int3 &a,const int3 &b)
00303 {
00304 for(int i=0;i<3;i++)
00305 {
00306 if(a[i]!=b[i]) return 0;
00307 }
00308 return 1;
00309 }
00310
00311
00312 int above(btVector3* vertices,const int3& t, const btVector3 &p, btScalar epsilon);
00313 int above(btVector3* vertices,const int3& t, const btVector3 &p, btScalar epsilon)
00314 {
00315 btVector3 n=TriNormal(vertices[t[0]],vertices[t[1]],vertices[t[2]]);
00316 return (btDot(n,p-vertices[t[0]]) > epsilon);
00317 }
00318 int hasedge(const int3 &t, int a,int b);
00319 int hasedge(const int3 &t, int a,int b)
00320 {
00321 for(int i=0;i<3;i++)
00322 {
00323 int i1= (i+1)%3;
00324 if(t[i]==a && t[i1]==b) return 1;
00325 }
00326 return 0;
00327 }
00328 int hasvert(const int3 &t, int v);
00329 int hasvert(const int3 &t, int v)
00330 {
00331 return (t[0]==v || t[1]==v || t[2]==v) ;
00332 }
00333 int shareedge(const int3 &a,const int3 &b);
00334 int shareedge(const int3 &a,const int3 &b)
00335 {
00336 int i;
00337 for(i=0;i<3;i++)
00338 {
00339 int i1= (i+1)%3;
00340 if(hasedge(a,b[i1],b[i])) return 1;
00341 }
00342 return 0;
00343 }
00344
00345 class btHullTriangle;
00346
00347
00348
00349 class btHullTriangle : public int3
00350 {
00351 public:
00352 int3 n;
00353 int id;
00354 int vmax;
00355 btScalar rise;
00356 btHullTriangle(int a,int b,int c):int3(a,b,c),n(-1,-1,-1)
00357 {
00358 vmax=-1;
00359 rise = btScalar(0.0);
00360 }
00361 ~btHullTriangle()
00362 {
00363 }
00364 int &neib(int a,int b);
00365 };
00366
00367
00368 int &btHullTriangle::neib(int a,int b)
00369 {
00370 static int er=-1;
00371 int i;
00372 for(i=0;i<3;i++)
00373 {
00374 int i1=(i+1)%3;
00375 int i2=(i+2)%3;
00376 if((*this)[i]==a && (*this)[i1]==b) return n[i2];
00377 if((*this)[i]==b && (*this)[i1]==a) return n[i2];
00378 }
00379 btAssert(0);
00380 return er;
00381 }
00382 void HullLibrary::b2bfix(btHullTriangle* s,btHullTriangle*t)
00383 {
00384 int i;
00385 for(i=0;i<3;i++)
00386 {
00387 int i1=(i+1)%3;
00388 int i2=(i+2)%3;
00389 int a = (*s)[i1];
00390 int b = (*s)[i2];
00391 btAssert(m_tris[s->neib(a,b)]->neib(b,a) == s->id);
00392 btAssert(m_tris[t->neib(a,b)]->neib(b,a) == t->id);
00393 m_tris[s->neib(a,b)]->neib(b,a) = t->neib(b,a);
00394 m_tris[t->neib(b,a)]->neib(a,b) = s->neib(a,b);
00395 }
00396 }
00397
00398 void HullLibrary::removeb2b(btHullTriangle* s,btHullTriangle*t)
00399 {
00400 b2bfix(s,t);
00401 deAllocateTriangle(s);
00402
00403 deAllocateTriangle(t);
00404 }
00405
00406 void HullLibrary::checkit(btHullTriangle *t)
00407 {
00408 (void)t;
00409
00410 int i;
00411 btAssert(m_tris[t->id]==t);
00412 for(i=0;i<3;i++)
00413 {
00414 int i1=(i+1)%3;
00415 int i2=(i+2)%3;
00416 int a = (*t)[i1];
00417 int b = (*t)[i2];
00418
00419
00420 (void)i1;
00421 (void)i2;
00422 (void)a;
00423 (void)b;
00424
00425 btAssert(a!=b);
00426 btAssert( m_tris[t->n[i]]->neib(b,a) == t->id);
00427 }
00428 }
00429
00430 btHullTriangle* HullLibrary::allocateTriangle(int a,int b,int c)
00431 {
00432 void* mem = btAlignedAlloc(sizeof(btHullTriangle),16);
00433 btHullTriangle* tr = new (mem)btHullTriangle(a,b,c);
00434 tr->id = m_tris.size();
00435 m_tris.push_back(tr);
00436
00437 return tr;
00438 }
00439
00440 void HullLibrary::deAllocateTriangle(btHullTriangle* tri)
00441 {
00442 btAssert(m_tris[tri->id]==tri);
00443 m_tris[tri->id]=NULL;
00444 tri->~btHullTriangle();
00445 btAlignedFree(tri);
00446 }
00447
00448
00449 void HullLibrary::extrude(btHullTriangle *t0,int v)
00450 {
00451 int3 t= *t0;
00452 int n = m_tris.size();
00453 btHullTriangle* ta = allocateTriangle(v,t[1],t[2]);
00454 ta->n = int3(t0->n[0],n+1,n+2);
00455 m_tris[t0->n[0]]->neib(t[1],t[2]) = n+0;
00456 btHullTriangle* tb = allocateTriangle(v,t[2],t[0]);
00457 tb->n = int3(t0->n[1],n+2,n+0);
00458 m_tris[t0->n[1]]->neib(t[2],t[0]) = n+1;
00459 btHullTriangle* tc = allocateTriangle(v,t[0],t[1]);
00460 tc->n = int3(t0->n[2],n+0,n+1);
00461 m_tris[t0->n[2]]->neib(t[0],t[1]) = n+2;
00462 checkit(ta);
00463 checkit(tb);
00464 checkit(tc);
00465 if(hasvert(*m_tris[ta->n[0]],v)) removeb2b(ta,m_tris[ta->n[0]]);
00466 if(hasvert(*m_tris[tb->n[0]],v)) removeb2b(tb,m_tris[tb->n[0]]);
00467 if(hasvert(*m_tris[tc->n[0]],v)) removeb2b(tc,m_tris[tc->n[0]]);
00468 deAllocateTriangle(t0);
00469
00470 }
00471
00472 btHullTriangle* HullLibrary::extrudable(btScalar epsilon)
00473 {
00474 int i;
00475 btHullTriangle *t=NULL;
00476 for(i=0;i<m_tris.size();i++)
00477 {
00478 if(!t || (m_tris[i] && t->rise<m_tris[i]->rise))
00479 {
00480 t = m_tris[i];
00481 }
00482 }
00483 return (t->rise >epsilon)?t:NULL ;
00484 }
00485
00486
00487
00488
00489 int4 HullLibrary::FindSimplex(btVector3 *verts,int verts_count,btAlignedObjectArray<int> &allow)
00490 {
00491 btVector3 basis[3];
00492 basis[0] = btVector3( btScalar(0.01), btScalar(0.02), btScalar(1.0) );
00493 int p0 = maxdirsterid(verts,verts_count, basis[0],allow);
00494 int p1 = maxdirsterid(verts,verts_count,-basis[0],allow);
00495 basis[0] = verts[p0]-verts[p1];
00496 if(p0==p1 || basis[0]==btVector3(0,0,0))
00497 return int4(-1,-1,-1,-1);
00498 basis[1] = btCross(btVector3( btScalar(1),btScalar(0.02), btScalar(0)),basis[0]);
00499 basis[2] = btCross(btVector3(btScalar(-0.02), btScalar(1), btScalar(0)),basis[0]);
00500 if (basis[1].length() > basis[2].length())
00501 {
00502 basis[1].normalize();
00503 } else {
00504 basis[1] = basis[2];
00505 basis[1].normalize ();
00506 }
00507 int p2 = maxdirsterid(verts,verts_count,basis[1],allow);
00508 if(p2 == p0 || p2 == p1)
00509 {
00510 p2 = maxdirsterid(verts,verts_count,-basis[1],allow);
00511 }
00512 if(p2 == p0 || p2 == p1)
00513 return int4(-1,-1,-1,-1);
00514 basis[1] = verts[p2] - verts[p0];
00515 basis[2] = btCross(basis[1],basis[0]).normalized();
00516 int p3 = maxdirsterid(verts,verts_count,basis[2],allow);
00517 if(p3==p0||p3==p1||p3==p2) p3 = maxdirsterid(verts,verts_count,-basis[2],allow);
00518 if(p3==p0||p3==p1||p3==p2)
00519 return int4(-1,-1,-1,-1);
00520 btAssert(!(p0==p1||p0==p2||p0==p3||p1==p2||p1==p3||p2==p3));
00521 if(btDot(verts[p3]-verts[p0],btCross(verts[p1]-verts[p0],verts[p2]-verts[p0])) <0) {Swap(p2,p3);}
00522 return int4(p0,p1,p2,p3);
00523 }
00524
00525 int HullLibrary::calchullgen(btVector3 *verts,int verts_count, int vlimit)
00526 {
00527 if(verts_count <4) return 0;
00528 if(vlimit==0) vlimit=1000000000;
00529 int j;
00530 btVector3 bmin(*verts),bmax(*verts);
00531 btAlignedObjectArray<int> isextreme;
00532 isextreme.reserve(verts_count);
00533 btAlignedObjectArray<int> allow;
00534 allow.reserve(verts_count);
00535
00536 for(j=0;j<verts_count;j++)
00537 {
00538 allow.push_back(1);
00539 isextreme.push_back(0);
00540 bmin.setMin (verts[j]);
00541 bmax.setMax (verts[j]);
00542 }
00543 btScalar epsilon = (bmax-bmin).length() * btScalar(0.001);
00544 btAssert (epsilon != 0.0);
00545
00546
00547 int4 p = FindSimplex(verts,verts_count,allow);
00548 if(p.x==-1) return 0;
00549
00550
00551
00552 btVector3 center = (verts[p[0]]+verts[p[1]]+verts[p[2]]+verts[p[3]]) / btScalar(4.0);
00553 btHullTriangle *t0 = allocateTriangle(p[2],p[3],p[1]); t0->n=int3(2,3,1);
00554 btHullTriangle *t1 = allocateTriangle(p[3],p[2],p[0]); t1->n=int3(3,2,0);
00555 btHullTriangle *t2 = allocateTriangle(p[0],p[1],p[3]); t2->n=int3(0,1,3);
00556 btHullTriangle *t3 = allocateTriangle(p[1],p[0],p[2]); t3->n=int3(1,0,2);
00557 isextreme[p[0]]=isextreme[p[1]]=isextreme[p[2]]=isextreme[p[3]]=1;
00558 checkit(t0);checkit(t1);checkit(t2);checkit(t3);
00559
00560 for(j=0;j<m_tris.size();j++)
00561 {
00562 btHullTriangle *t=m_tris[j];
00563 btAssert(t);
00564 btAssert(t->vmax<0);
00565 btVector3 n=TriNormal(verts[(*t)[0]],verts[(*t)[1]],verts[(*t)[2]]);
00566 t->vmax = maxdirsterid(verts,verts_count,n,allow);
00567 t->rise = btDot(n,verts[t->vmax]-verts[(*t)[0]]);
00568 }
00569 btHullTriangle *te;
00570 vlimit-=4;
00571 while(vlimit >0 && ((te=extrudable(epsilon)) != 0))
00572 {
00573 int3 ti=*te;
00574 int v=te->vmax;
00575 btAssert(v != -1);
00576 btAssert(!isextreme[v]);
00577 isextreme[v]=1;
00578
00579 j=m_tris.size();
00580 while(j--) {
00581 if(!m_tris[j]) continue;
00582 int3 t=*m_tris[j];
00583 if(above(verts,t,verts[v],btScalar(0.01)*epsilon))
00584 {
00585 extrude(m_tris[j],v);
00586 }
00587 }
00588
00589 j=m_tris.size();
00590 while(j--)
00591 {
00592 if(!m_tris[j]) continue;
00593 if(!hasvert(*m_tris[j],v)) break;
00594 int3 nt=*m_tris[j];
00595 if(above(verts,nt,center,btScalar(0.01)*epsilon) || btCross(verts[nt[1]]-verts[nt[0]],verts[nt[2]]-verts[nt[1]]).length()< epsilon*epsilon*btScalar(0.1) )
00596 {
00597 btHullTriangle *nb = m_tris[m_tris[j]->n[0]];
00598 btAssert(nb);btAssert(!hasvert(*nb,v));btAssert(nb->id<j);
00599 extrude(nb,v);
00600 j=m_tris.size();
00601 }
00602 }
00603 j=m_tris.size();
00604 while(j--)
00605 {
00606 btHullTriangle *t=m_tris[j];
00607 if(!t) continue;
00608 if(t->vmax>=0) break;
00609 btVector3 n=TriNormal(verts[(*t)[0]],verts[(*t)[1]],verts[(*t)[2]]);
00610 t->vmax = maxdirsterid(verts,verts_count,n,allow);
00611 if(isextreme[t->vmax])
00612 {
00613 t->vmax=-1;
00614 }
00615 else
00616 {
00617 t->rise = btDot(n,verts[t->vmax]-verts[(*t)[0]]);
00618 }
00619 }
00620 vlimit --;
00621 }
00622 return 1;
00623 }
00624
00625 int HullLibrary::calchull(btVector3 *verts,int verts_count, TUIntArray& tris_out, int &tris_count,int vlimit)
00626 {
00627 int rc=calchullgen(verts,verts_count, vlimit) ;
00628 if(!rc) return 0;
00629 btAlignedObjectArray<int> ts;
00630 int i;
00631
00632 for(i=0;i<m_tris.size();i++)
00633 {
00634 if(m_tris[i])
00635 {
00636 for(int j=0;j<3;j++)
00637 ts.push_back((*m_tris[i])[j]);
00638 deAllocateTriangle(m_tris[i]);
00639 }
00640 }
00641 tris_count = ts.size()/3;
00642 tris_out.resize(ts.size());
00643
00644 for (i=0;i<ts.size();i++)
00645 {
00646 tris_out[i] = static_cast<unsigned int>(ts[i]);
00647 }
00648 m_tris.resize(0);
00649
00650 return 1;
00651 }
00652
00653
00654
00655
00656
00657 bool HullLibrary::ComputeHull(unsigned int vcount,const btVector3 *vertices,PHullResult &result,unsigned int vlimit)
00658 {
00659
00660 int tris_count;
00661 int ret = calchull( (btVector3 *) vertices, (int) vcount, result.m_Indices, tris_count, static_cast<int>(vlimit) );
00662 if(!ret) return false;
00663 result.mIndexCount = (unsigned int) (tris_count*3);
00664 result.mFaceCount = (unsigned int) tris_count;
00665 result.mVertices = (btVector3*) vertices;
00666 result.mVcount = (unsigned int) vcount;
00667 return true;
00668
00669 }
00670
00671
00672 void ReleaseHull(PHullResult &result);
00673 void ReleaseHull(PHullResult &result)
00674 {
00675 if ( result.m_Indices.size() )
00676 {
00677 result.m_Indices.clear();
00678 }
00679
00680 result.mVcount = 0;
00681 result.mIndexCount = 0;
00682 result.mVertices = 0;
00683 }
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698 HullError HullLibrary::CreateConvexHull(const HullDesc &desc,
00699 HullResult &result)
00700 {
00701 HullError ret = QE_FAIL;
00702
00703
00704 PHullResult hr;
00705
00706 unsigned int vcount = desc.mVcount;
00707 if ( vcount < 8 ) vcount = 8;
00708
00709 btAlignedObjectArray<btVector3> vertexSource;
00710 vertexSource.resize(static_cast<int>(vcount));
00711
00712 btVector3 scale;
00713
00714 unsigned int ovcount;
00715
00716 bool ok = CleanupVertices(desc.mVcount,desc.mVertices, desc.mVertexStride, ovcount, &vertexSource[0], desc.mNormalEpsilon, scale );
00717
00718 if ( ok )
00719 {
00720
00721
00722
00723 {
00724 for (unsigned int i=0; i<ovcount; i++)
00725 {
00726 btVector3& v = vertexSource[static_cast<int>(i)];
00727 v[0]*=scale[0];
00728 v[1]*=scale[1];
00729 v[2]*=scale[2];
00730 }
00731 }
00732
00733 ok = ComputeHull(ovcount,&vertexSource[0],hr,desc.mMaxVertices);
00734
00735 if ( ok )
00736 {
00737
00738
00739 btAlignedObjectArray<btVector3> vertexScratch;
00740 vertexScratch.resize(static_cast<int>(hr.mVcount));
00741
00742 BringOutYourDead(hr.mVertices,hr.mVcount, &vertexScratch[0], ovcount, &hr.m_Indices[0], hr.mIndexCount );
00743
00744 ret = QE_OK;
00745
00746 if ( desc.HasHullFlag(QF_TRIANGLES) )
00747 {
00748 result.mPolygons = false;
00749 result.mNumOutputVertices = ovcount;
00750 result.m_OutputVertices.resize(static_cast<int>(ovcount));
00751 result.mNumFaces = hr.mFaceCount;
00752 result.mNumIndices = hr.mIndexCount;
00753
00754 result.m_Indices.resize(static_cast<int>(hr.mIndexCount));
00755
00756 memcpy(&result.m_OutputVertices[0], &vertexScratch[0], sizeof(btVector3)*ovcount );
00757
00758 if ( desc.HasHullFlag(QF_REVERSE_ORDER) )
00759 {
00760
00761 const unsigned int *source = &hr.m_Indices[0];
00762 unsigned int *dest = &result.m_Indices[0];
00763
00764 for (unsigned int i=0; i<hr.mFaceCount; i++)
00765 {
00766 dest[0] = source[2];
00767 dest[1] = source[1];
00768 dest[2] = source[0];
00769 dest+=3;
00770 source+=3;
00771 }
00772
00773 }
00774 else
00775 {
00776 memcpy(&result.m_Indices[0], &hr.m_Indices[0], sizeof(unsigned int)*hr.mIndexCount);
00777 }
00778 }
00779 else
00780 {
00781 result.mPolygons = true;
00782 result.mNumOutputVertices = ovcount;
00783 result.m_OutputVertices.resize(static_cast<int>(ovcount));
00784 result.mNumFaces = hr.mFaceCount;
00785 result.mNumIndices = hr.mIndexCount+hr.mFaceCount;
00786 result.m_Indices.resize(static_cast<int>(result.mNumIndices));
00787 memcpy(&result.m_OutputVertices[0], &vertexScratch[0], sizeof(btVector3)*ovcount );
00788
00789
00790 {
00791 const unsigned int *source = &hr.m_Indices[0];
00792 unsigned int *dest = &result.m_Indices[0];
00793 for (unsigned int i=0; i<hr.mFaceCount; i++)
00794 {
00795 dest[0] = 3;
00796 if ( desc.HasHullFlag(QF_REVERSE_ORDER) )
00797 {
00798 dest[1] = source[2];
00799 dest[2] = source[1];
00800 dest[3] = source[0];
00801 }
00802 else
00803 {
00804 dest[1] = source[0];
00805 dest[2] = source[1];
00806 dest[3] = source[2];
00807 }
00808
00809 dest+=4;
00810 source+=3;
00811 }
00812 }
00813 }
00814 ReleaseHull(hr);
00815 }
00816 }
00817
00818 return ret;
00819 }
00820
00821
00822
00823 HullError HullLibrary::ReleaseResult(HullResult &result)
00824 {
00825 if ( result.m_OutputVertices.size())
00826 {
00827 result.mNumOutputVertices=0;
00828 result.m_OutputVertices.clear();
00829 }
00830 if ( result.m_Indices.size() )
00831 {
00832 result.mNumIndices=0;
00833 result.m_Indices.clear();
00834 }
00835 return QE_OK;
00836 }
00837
00838
00839 static void addPoint(unsigned int &vcount,btVector3 *p,btScalar x,btScalar y,btScalar z)
00840 {
00841
00842 btVector3& dest = p[vcount];
00843 dest[0] = x;
00844 dest[1] = y;
00845 dest[2] = z;
00846 vcount++;
00847 }
00848
00849 btScalar GetDist(btScalar px,btScalar py,btScalar pz,const btScalar *p2);
00850 btScalar GetDist(btScalar px,btScalar py,btScalar pz,const btScalar *p2)
00851 {
00852
00853 btScalar dx = px - p2[0];
00854 btScalar dy = py - p2[1];
00855 btScalar dz = pz - p2[2];
00856
00857 return dx*dx+dy*dy+dz*dz;
00858 }
00859
00860
00861
00862 bool HullLibrary::CleanupVertices(unsigned int svcount,
00863 const btVector3 *svertices,
00864 unsigned int stride,
00865 unsigned int &vcount,
00866 btVector3 *vertices,
00867 btScalar normalepsilon,
00868 btVector3& scale)
00869 {
00870 if ( svcount == 0 ) return false;
00871
00872 m_vertexIndexMapping.resize(0);
00873
00874
00875 #define EPSILON btScalar(0.000001)
00876
00877 vcount = 0;
00878
00879 btScalar recip[3]={0.f,0.f,0.f};
00880
00881 if ( scale )
00882 {
00883 scale[0] = 1;
00884 scale[1] = 1;
00885 scale[2] = 1;
00886 }
00887
00888 btScalar bmin[3] = { FLT_MAX, FLT_MAX, FLT_MAX };
00889 btScalar bmax[3] = { -FLT_MAX, -FLT_MAX, -FLT_MAX };
00890
00891 const char *vtx = (const char *) svertices;
00892
00893
00894 {
00895 for (unsigned int i=0; i<svcount; i++)
00896 {
00897 const btScalar *p = (const btScalar *) vtx;
00898
00899 vtx+=stride;
00900
00901 for (int j=0; j<3; j++)
00902 {
00903 if ( p[j] < bmin[j] ) bmin[j] = p[j];
00904 if ( p[j] > bmax[j] ) bmax[j] = p[j];
00905 }
00906 }
00907 }
00908
00909 btScalar dx = bmax[0] - bmin[0];
00910 btScalar dy = bmax[1] - bmin[1];
00911 btScalar dz = bmax[2] - bmin[2];
00912
00913 btVector3 center;
00914
00915 center[0] = dx*btScalar(0.5) + bmin[0];
00916 center[1] = dy*btScalar(0.5) + bmin[1];
00917 center[2] = dz*btScalar(0.5) + bmin[2];
00918
00919 if ( dx < EPSILON || dy < EPSILON || dz < EPSILON || svcount < 3 )
00920 {
00921
00922 btScalar len = FLT_MAX;
00923
00924 if ( dx > EPSILON && dx < len ) len = dx;
00925 if ( dy > EPSILON && dy < len ) len = dy;
00926 if ( dz > EPSILON && dz < len ) len = dz;
00927
00928 if ( len == FLT_MAX )
00929 {
00930 dx = dy = dz = btScalar(0.01);
00931 }
00932 else
00933 {
00934 if ( dx < EPSILON ) dx = len * btScalar(0.05);
00935 if ( dy < EPSILON ) dy = len * btScalar(0.05);
00936 if ( dz < EPSILON ) dz = len * btScalar(0.05);
00937 }
00938
00939 btScalar x1 = center[0] - dx;
00940 btScalar x2 = center[0] + dx;
00941
00942 btScalar y1 = center[1] - dy;
00943 btScalar y2 = center[1] + dy;
00944
00945 btScalar z1 = center[2] - dz;
00946 btScalar z2 = center[2] + dz;
00947
00948 addPoint(vcount,vertices,x1,y1,z1);
00949 addPoint(vcount,vertices,x2,y1,z1);
00950 addPoint(vcount,vertices,x2,y2,z1);
00951 addPoint(vcount,vertices,x1,y2,z1);
00952 addPoint(vcount,vertices,x1,y1,z2);
00953 addPoint(vcount,vertices,x2,y1,z2);
00954 addPoint(vcount,vertices,x2,y2,z2);
00955 addPoint(vcount,vertices,x1,y2,z2);
00956
00957 return true;
00958
00959
00960 }
00961 else
00962 {
00963 if ( scale )
00964 {
00965 scale[0] = dx;
00966 scale[1] = dy;
00967 scale[2] = dz;
00968
00969 recip[0] = 1 / dx;
00970 recip[1] = 1 / dy;
00971 recip[2] = 1 / dz;
00972
00973 center[0]*=recip[0];
00974 center[1]*=recip[1];
00975 center[2]*=recip[2];
00976
00977 }
00978
00979 }
00980
00981
00982
00983 vtx = (const char *) svertices;
00984
00985 for (unsigned int i=0; i<svcount; i++)
00986 {
00987 const btVector3 *p = (const btVector3 *)vtx;
00988 vtx+=stride;
00989
00990 btScalar px = p->getX();
00991 btScalar py = p->getY();
00992 btScalar pz = p->getZ();
00993
00994 if ( scale )
00995 {
00996 px = px*recip[0];
00997 py = py*recip[1];
00998 pz = pz*recip[2];
00999 }
01000
01001
01002 {
01003 unsigned int j;
01004
01005 for (j=0; j<vcount; j++)
01006 {
01008 btVector3& v = vertices[j];
01009
01010 btScalar x = v[0];
01011 btScalar y = v[1];
01012 btScalar z = v[2];
01013
01014 btScalar dx = btFabs(x - px );
01015 btScalar dy = btFabs(y - py );
01016 btScalar dz = btFabs(z - pz );
01017
01018 if ( dx < normalepsilon && dy < normalepsilon && dz < normalepsilon )
01019 {
01020
01021
01022
01023
01024 btScalar dist1 = GetDist(px,py,pz,center);
01025 btScalar dist2 = GetDist(v[0],v[1],v[2],center);
01026
01027 if ( dist1 > dist2 )
01028 {
01029 v[0] = px;
01030 v[1] = py;
01031 v[2] = pz;
01032
01033 }
01034
01035 break;
01036 }
01037 }
01038
01039 if ( j == vcount )
01040 {
01041 btVector3& dest = vertices[vcount];
01042 dest[0] = px;
01043 dest[1] = py;
01044 dest[2] = pz;
01045 vcount++;
01046 }
01047 m_vertexIndexMapping.push_back(j);
01048 }
01049 }
01050
01051
01052
01053 {
01054 btScalar bmin[3] = { FLT_MAX, FLT_MAX, FLT_MAX };
01055 btScalar bmax[3] = { -FLT_MAX, -FLT_MAX, -FLT_MAX };
01056
01057 for (unsigned int i=0; i<vcount; i++)
01058 {
01059 const btVector3& p = vertices[i];
01060 for (int j=0; j<3; j++)
01061 {
01062 if ( p[j] < bmin[j] ) bmin[j] = p[j];
01063 if ( p[j] > bmax[j] ) bmax[j] = p[j];
01064 }
01065 }
01066
01067 btScalar dx = bmax[0] - bmin[0];
01068 btScalar dy = bmax[1] - bmin[1];
01069 btScalar dz = bmax[2] - bmin[2];
01070
01071 if ( dx < EPSILON || dy < EPSILON || dz < EPSILON || vcount < 3)
01072 {
01073 btScalar cx = dx*btScalar(0.5) + bmin[0];
01074 btScalar cy = dy*btScalar(0.5) + bmin[1];
01075 btScalar cz = dz*btScalar(0.5) + bmin[2];
01076
01077 btScalar len = FLT_MAX;
01078
01079 if ( dx >= EPSILON && dx < len ) len = dx;
01080 if ( dy >= EPSILON && dy < len ) len = dy;
01081 if ( dz >= EPSILON && dz < len ) len = dz;
01082
01083 if ( len == FLT_MAX )
01084 {
01085 dx = dy = dz = btScalar(0.01);
01086 }
01087 else
01088 {
01089 if ( dx < EPSILON ) dx = len * btScalar(0.05);
01090 if ( dy < EPSILON ) dy = len * btScalar(0.05);
01091 if ( dz < EPSILON ) dz = len * btScalar(0.05);
01092 }
01093
01094 btScalar x1 = cx - dx;
01095 btScalar x2 = cx + dx;
01096
01097 btScalar y1 = cy - dy;
01098 btScalar y2 = cy + dy;
01099
01100 btScalar z1 = cz - dz;
01101 btScalar z2 = cz + dz;
01102
01103 vcount = 0;
01104
01105 addPoint(vcount,vertices,x1,y1,z1);
01106 addPoint(vcount,vertices,x2,y1,z1);
01107 addPoint(vcount,vertices,x2,y2,z1);
01108 addPoint(vcount,vertices,x1,y2,z1);
01109 addPoint(vcount,vertices,x1,y1,z2);
01110 addPoint(vcount,vertices,x2,y1,z2);
01111 addPoint(vcount,vertices,x2,y2,z2);
01112 addPoint(vcount,vertices,x1,y2,z2);
01113
01114 return true;
01115 }
01116 }
01117
01118 return true;
01119 }
01120
01121 void HullLibrary::BringOutYourDead(const btVector3* verts,unsigned int vcount, btVector3* overts,unsigned int &ocount,unsigned int *indices,unsigned indexcount)
01122 {
01123 btAlignedObjectArray<int>tmpIndices;
01124 tmpIndices.resize(m_vertexIndexMapping.size());
01125 int i;
01126
01127 for (i=0;i<m_vertexIndexMapping.size();i++)
01128 {
01129 tmpIndices[i] = m_vertexIndexMapping[i];
01130 }
01131
01132 TUIntArray usedIndices;
01133 usedIndices.resize(static_cast<int>(vcount));
01134 memset(&usedIndices[0],0,sizeof(unsigned int)*vcount);
01135
01136 ocount = 0;
01137
01138 for (i=0; i<int (indexcount); i++)
01139 {
01140 unsigned int v = indices[i];
01141
01142 btAssert( v >= 0 && v < vcount );
01143
01144 if ( usedIndices[static_cast<int>(v)] )
01145 {
01146 indices[i] = usedIndices[static_cast<int>(v)]-1;
01147 }
01148 else
01149 {
01150
01151 indices[i] = ocount;
01152
01153 overts[ocount][0] = verts[v][0];
01154 overts[ocount][1] = verts[v][1];
01155 overts[ocount][2] = verts[v][2];
01156
01157 for (int k=0;k<m_vertexIndexMapping.size();k++)
01158 {
01159 if (tmpIndices[k]==int(v))
01160 m_vertexIndexMapping[k]=ocount;
01161 }
01162
01163 ocount++;
01164
01165 btAssert( ocount >=0 && ocount <= vcount );
01166
01167 usedIndices[static_cast<int>(v)] = ocount;
01168
01169
01170 }
01171 }
01172
01173
01174 }