29 using System.Collections.Generic;
30 using System.Diagnostics;
32 namespace OpenSim.
Region.PhysicsModules.ConvexDecompositionDotNet
34 public static class HullUtils
36 public static int argmin(
float[] a,
int n)
39 for (
int i = 1; i < n; i++)
49 public static float clampf(
float a)
51 return Math.Min(1.0f, Math.Max(0.0f, a));
54 public static float Round(
float a,
float precision)
56 return (
float)Math.Floor(0.5f + a / precision) * precision;
59 public static float Interpolate(
float f0,
float f1,
float alpha)
61 return f0 * (1 - alpha) + f1 * alpha;
64 public static void Swap<T>(ref T a, ref T b)
71 public static bool above(List<float3> vertices, int3 t, float3 p,
float epsilon)
73 float3 vtx = vertices[t.x];
74 float3 n = TriNormal(vtx, vertices[t.y], vertices[t.z]);
75 return (float3.dot(n, p - vtx) > epsilon);
78 public static int hasedge(int3 t,
int a,
int b)
80 for (
int i = 0; i < 3; i++)
83 if (t[i] == a && t[i1] == b)
89 public static bool hasvert(int3 t,
int v)
91 return (t[0] == v || t[1] == v || t[2] == v);
94 public static int shareedge(int3 a, int3 b)
97 for (i = 0; i < 3; i++)
100 if (hasedge(a, b[i1], b[i]) != 0)
106 public static void b2bfix(HullTriangle s, HullTriangle t, List<HullTriangle> tris)
109 for (i = 0; i < 3; i++)
111 int i1 = (i + 1) % 3;
112 int i2 = (i + 2) % 3;
115 Debug.Assert(tris[s.neib(a, b)].neib(b, a) == s.id);
116 Debug.Assert(tris[t.neib(a, b)].neib(b, a) == t.id);
117 tris[s.neib(a, b)].setneib(b, a, t.neib(b, a));
118 tris[t.neib(b, a)].setneib(a, b, s.neib(a, b));
122 public static void removeb2b(HullTriangle s, HullTriangle t, List<HullTriangle> tris)
129 public static void checkit(HullTriangle t, List<HullTriangle> tris)
132 Debug.Assert(tris[t.id] == t);
133 for (i = 0; i < 3; i++)
135 int i1 = (i + 1) % 3;
136 int i2 = (i + 2) % 3;
139 Debug.Assert(a != b);
140 Debug.Assert(tris[t.n[i]].neib(b, a) == t.id);
144 public static void extrude(HullTriangle t0,
int v, List<HullTriangle> tris)
148 HullTriangle ta =
new HullTriangle(v, t[1], t[2], tris);
149 ta.n =
new int3(t0.n[0], n + 1, n + 2);
150 tris[t0.n[0]].setneib(t[1], t[2], n + 0);
151 HullTriangle tb =
new HullTriangle(v, t[2], t[0], tris);
152 tb.n =
new int3(t0.n[1], n + 2, n + 0);
153 tris[t0.n[1]].setneib(t[2], t[0], n + 1);
154 HullTriangle tc =
new HullTriangle(v, t[0], t[1], tris);
155 tc.n =
new int3(t0.n[2], n + 0, n + 1);
156 tris[t0.n[2]].setneib(t[0], t[1], n + 2);
160 if (hasvert(tris[ta.n[0]], v))
161 removeb2b(ta, tris[ta.n[0]], tris);
162 if (hasvert(tris[tb.n[0]], v))
163 removeb2b(tb, tris[tb.n[0]], tris);
164 if (hasvert(tris[tc.n[0]], v))
165 removeb2b(tc, tris[tc.n[0]], tris);
169 public static HullTriangle extrudable(
float epsilon, List<HullTriangle> tris)
172 HullTriangle t = null;
173 for (i = 0; i < tris.Count; i++)
175 if (t == null || (tris.Count > i && (
object)tris[i] != null && t.rise < tris[i].rise))
180 return (t.rise > epsilon) ? t : null;
183 public static Quaternion RotationArc(float3 v0, float3 v1)
185 Quaternion q =
new Quaternion();
186 v0 = float3.normalize(v0);
187 v1 = float3.normalize(v1);
188 float3 c = float3.cross(v0, v1);
189 float d = float3.dot(v0, v1);
192 return new Quaternion(1f, 0f, 0f, 0f);
194 float s = (float)Math.Sqrt((1 + d) * 2f);
202 public static float3 PlaneLineIntersection(Plane plane, float3 p0, float3 p1)
205 float3 dif = p1 - p0;
206 float dn = float3.dot(plane.normal, dif);
207 float t = -(plane.dist + float3.dot(plane.normal, p0)) / dn;
208 return p0 + (dif * t);
211 public static float3 LineProject(float3 p0, float3 p1, float3 a)
213 float3 w =
new float3();
215 float t = float3.dot(w, (a - p0)) / (w.x * w.x + w.y * w.y + w.z * w.z);
219 public static float3 PlaneProject(Plane plane, float3 point)
221 return point - plane.normal * (float3.dot(point, plane.normal) + plane.dist);
224 public static float LineProjectTime(float3 p0, float3 p1, float3 a)
226 float3 w =
new float3();
228 float t = float3.dot(w, (a - p0)) / (w.x * w.x + w.y * w.y + w.z * w.z);
232 public static float3 ThreePlaneIntersection(Plane p0, Plane p1, Plane p2)
234 float3x3 mp = float3x3.Transpose(
new float3x3(p0.normal, p1.normal, p2.normal));
235 float3x3 mi = float3x3.Inverse(mp);
236 float3 b =
new float3(p0.dist, p1.dist, p2.dist);
240 public static bool PolyHit(List<float3> vert, float3 v0, float3 v1)
242 float3 impact =
new float3();
243 float3 normal =
new float3();
244 return PolyHit(vert, v0, v1, out impact, out normal);
247 public static bool PolyHit(List<float3> vert, float3 v0, float3 v1, out float3 impact)
249 float3 normal =
new float3();
250 return PolyHit(vert, v0, v1, out impact, out normal);
253 public static bool PolyHit(List<float3> vert, float3 v0, float3 v1, out float3 impact, out float3 normal)
255 float3 the_point =
new float3();
261 float3 nrml =
new float3(0, 0, 0);
262 for (i = 0; i < vert.Count; i++)
264 int i1 = (i + 1) % vert.Count;
265 int i2 = (i + 2) % vert.Count;
266 nrml = nrml + float3.cross(vert[i1] - vert[i], vert[i2] - vert[i1]);
269 float m = float3.magnitude(nrml);
274 nrml = nrml * (1.0f / m);
275 float dist = -float3.dot(nrml, vert[0]);
278 if ((d0 = float3.dot(v0, nrml) + dist) < 0 || (d1 = float3.dot(v1, nrml) + dist) > 0)
286 float a = d0 / (d0 - d1);
287 the_point = v0 * (1 - a) + v1 * a;
291 for (
int j = 0; inside && j < vert.Count; j++)
294 float3 pp1 =
new float3();
295 float3 pp2 =
new float3();
296 float3 side =
new float3();
298 pp2 = vert[(j + 1) % vert.Count];
299 side = float3.cross((pp2 - pp1), (the_point - pp1));
300 inside = (float3.dot(nrml, side) >= 0.0);
316 public static bool BoxInside(float3 p, float3 bmin, float3 bmax)
318 return (p.x >= bmin.x && p.x <= bmax.x && p.y >= bmin.y && p.y <= bmax.y && p.z >= bmin.z && p.z <= bmax.z);
321 public static bool BoxIntersect(float3 v0, float3 v1, float3 bmin, float3 bmax, float3 impact)
323 if (BoxInside(v0, bmin, bmax))
328 if (v0.x <= bmin.x && v1.x >= bmin.x)
330 float a = (bmin.x - v0.x) / (v1.x - v0.x);
332 float vy = (1 - a) * v0.y + a * v1.y;
333 float vz = (1 - a) * v0.z + a * v1.z;
334 if (vy >= bmin.y && vy <= bmax.y && vz >= bmin.z && vz <= bmax.z)
342 else if (v0.x >= bmax.x && v1.x <= bmax.x)
344 float a = (bmax.x - v0.x) / (v1.x - v0.x);
346 float vy = (1 - a) * v0.y + a * v1.y;
347 float vz = (1 - a) * v0.z + a * v1.z;
348 if (vy >= bmin.y && vy <= bmax.y && vz >= bmin.z && vz <= bmax.z)
356 if (v0.y <= bmin.y && v1.y >= bmin.y)
358 float a = (bmin.y - v0.y) / (v1.y - v0.y);
359 float vx = (1 - a) * v0.x + a * v1.x;
361 float vz = (1 - a) * v0.z + a * v1.z;
362 if (vx >= bmin.x && vx <= bmax.x && vz >= bmin.z && vz <= bmax.z)
370 else if (v0.y >= bmax.y && v1.y <= bmax.y)
372 float a = (bmax.y - v0.y) / (v1.y - v0.y);
373 float vx = (1 - a) * v0.x + a * v1.x;
375 float vz = (1 - a) * v0.z + a * v1.z;
376 if (vx >= bmin.x && vx <= bmax.x && vz >= bmin.z && vz <= bmax.z)
384 if (v0.z <= bmin.z && v1.z >= bmin.z)
386 float a = (bmin.z - v0.z) / (v1.z - v0.z);
387 float vx = (1 - a) * v0.x + a * v1.x;
388 float vy = (1 - a) * v0.y + a * v1.y;
390 if (vy >= bmin.y && vy <= bmax.y && vx >= bmin.x && vx <= bmax.x)
398 else if (v0.z >= bmax.z && v1.z <= bmax.z)
400 float a = (bmax.z - v0.z) / (v1.z - v0.z);
401 float vx = (1 - a) * v0.x + a * v1.x;
402 float vy = (1 - a) * v0.y + a * v1.y;
404 if (vy >= bmin.y && vy <= bmax.y && vx >= bmin.x && vx <= bmax.x)
415 public static float DistanceBetweenLines(float3 ustart, float3 udir, float3 vstart, float3 vdir, float3 upoint)
417 return DistanceBetweenLines(ustart, udir, vstart, vdir, upoint, null);
420 public static float DistanceBetweenLines(float3 ustart, float3 udir, float3 vstart, float3 vdir)
422 return DistanceBetweenLines(ustart, udir, vstart, vdir, null, null);
425 public static float DistanceBetweenLines(float3 ustart, float3 udir, float3 vstart, float3 vdir, float3 upoint, float3 vpoint)
427 float3 cp = float3.normalize(float3.cross(udir, vdir));
429 float distu = -float3.dot(cp, ustart);
430 float distv = -float3.dot(cp, vstart);
431 float dist = (float)Math.Abs(distu - distv);
435 plane.normal = float3.normalize(float3.cross(vdir, cp));
436 plane.dist = -float3.dot(plane.normal, vstart);
437 upoint = PlaneLineIntersection(plane, ustart, ustart + udir);
442 plane.normal = float3.normalize(float3.cross(udir, cp));
443 plane.dist = -float3.dot(plane.normal, ustart);
444 vpoint = PlaneLineIntersection(plane, vstart, vstart + vdir);
449 public static float3 TriNormal(float3 v0, float3 v1, float3 v2)
453 float3 cp = float3.cross(v1 - v0, v2 - v1);
454 float m = float3.magnitude(cp);
456 return new float3(1, 0, 0);
457 return cp * (1.0f / m);
460 public static int PlaneTest(Plane p, float3 v,
float planetestepsilon)
462 float a = float3.dot(v, p.normal) + p.dist;
463 int flag = (a > planetestepsilon) ? (2) : ((a < -planetestepsilon) ? (1) : (0));
467 public static int SplitTest(ref ConvexH convex, Plane plane,
float planetestepsilon)
470 for (
int i = 0; i < convex.vertices.Count; i++)
472 flag |= PlaneTest(plane, convex.vertices[i], planetestepsilon);
477 public static Quaternion VirtualTrackBall(float3 cop, float3 cor, float3 dir1, float3 dir2)
490 float3 nrml = cor - cop;
491 float fudgefactor = 1.0f / (float3.magnitude(nrml) * 0.25f);
492 nrml = float3.normalize(nrml);
493 float dist = -float3.dot(nrml, cor);
494 float3 u = PlaneLineIntersection(
new Plane(nrml, dist), cop, cop + dir1);
497 m = float3.magnitude(u);
504 u = u - (nrml * (float)Math.Sqrt(1 - m * m));
506 float3 v = PlaneLineIntersection(
new Plane(nrml, dist), cop, cop + dir2);
509 m = float3.magnitude(v);
516 v = v - (nrml * (float)Math.Sqrt(1 - m * m));
518 return RotationArc(u, v);
521 public static bool AssertIntact(ConvexH convex,
float planetestepsilon)
525 for (i = 0; i < convex.edges.Count; i++)
527 if (convex.edges[estart].p != convex.edges[i].p)
532 if (inext >= convex.edges.Count || convex.edges[inext].p != convex.edges[i].p)
536 Debug.Assert(convex.edges[inext].p == convex.edges[i].p);
537 int nb = convex.edges[i].ea;
538 Debug.Assert(nb != 255);
539 if (nb == 255 || nb == -1)
541 Debug.Assert(nb != -1);
542 Debug.Assert(i == convex.edges[nb].ea);
544 for (i = 0; i < convex.edges.Count; i++)
546 Debug.Assert((0) == PlaneTest(convex.facets[convex.edges[i].p], convex.vertices[convex.edges[i].v], planetestepsilon));
547 if ((0) != PlaneTest(convex.facets[convex.edges[i].p], convex.vertices[convex.edges[i].v], planetestepsilon))
549 if (convex.edges[estart].p != convex.edges[i].p)
554 if (i1 >= convex.edges.Count || convex.edges[i1].p != convex.edges[i].p)
559 if (i2 >= convex.edges.Count || convex.edges[i2].p != convex.edges[i].p)
565 float3 localnormal = TriNormal(convex.vertices[convex.edges[i].v], convex.vertices[convex.edges[i1].v], convex.vertices[convex.edges[i2].v]);
566 Debug.Assert(float3.dot(localnormal, convex.facets[convex.edges[i].p].normal) > 0);
567 if (float3.dot(localnormal, convex.facets[convex.edges[i].p].normal) <= 0)
573 public static ConvexH test_btbq(
float planetestepsilon)
576 ConvexH convex =
new ConvexH(4, 8, 2);
577 convex.vertices[0] =
new float3(0, 0, 0);
578 convex.vertices[1] =
new float3(1, 0, 0);
579 convex.vertices[2] =
new float3(1, 1, 0);
580 convex.vertices[3] =
new float3(0, 1, 0);
581 convex.facets[0] =
new Plane(
new float3(0, 0, 1), 0);
582 convex.facets[1] =
new Plane(
new float3(0, 0, -1), 0);
583 convex.edges[0] =
new ConvexH.HalfEdge(7, 0, 0);
584 convex.edges[1] =
new ConvexH.HalfEdge(6, 1, 0);
585 convex.edges[2] =
new ConvexH.HalfEdge(5, 2, 0);
586 convex.edges[3] =
new ConvexH.HalfEdge(4, 3, 0);
588 convex.edges[4] =
new ConvexH.HalfEdge(3, 0, 1);
589 convex.edges[5] =
new ConvexH.HalfEdge(2, 3, 1);
590 convex.edges[6] =
new ConvexH.HalfEdge(1, 2, 1);
591 convex.edges[7] =
new ConvexH.HalfEdge(0, 1, 1);
592 AssertIntact(convex, planetestepsilon);
596 public static ConvexH test_cube()
598 ConvexH convex =
new ConvexH(8, 24, 6);
599 convex.vertices[0] =
new float3(0, 0, 0);
600 convex.vertices[1] =
new float3(0, 0, 1);
601 convex.vertices[2] =
new float3(0, 1, 0);
602 convex.vertices[3] =
new float3(0, 1, 1);
603 convex.vertices[4] =
new float3(1, 0, 0);
604 convex.vertices[5] =
new float3(1, 0, 1);
605 convex.vertices[6] =
new float3(1, 1, 0);
606 convex.vertices[7] =
new float3(1, 1, 1);
608 convex.facets[0] =
new Plane(
new float3(-1, 0, 0), 0);
609 convex.facets[1] =
new Plane(
new float3(1, 0, 0), -1);
610 convex.facets[2] =
new Plane(
new float3(0, -1, 0), 0);
611 convex.facets[3] =
new Plane(
new float3(0, 1, 0), -1);
612 convex.facets[4] =
new Plane(
new float3(0, 0, -1), 0);
613 convex.facets[5] =
new Plane(
new float3(0, 0, 1), -1);
615 convex.edges[0] =
new ConvexH.HalfEdge(11, 0, 0);
616 convex.edges[1] =
new ConvexH.HalfEdge(23, 1, 0);
617 convex.edges[2] =
new ConvexH.HalfEdge(15, 3, 0);
618 convex.edges[3] =
new ConvexH.HalfEdge(16, 2, 0);
620 convex.edges[4] =
new ConvexH.HalfEdge(13, 6, 1);
621 convex.edges[5] =
new ConvexH.HalfEdge(21, 7, 1);
622 convex.edges[6] =
new ConvexH.HalfEdge(9, 5, 1);
623 convex.edges[7] =
new ConvexH.HalfEdge(18, 4, 1);
625 convex.edges[8] =
new ConvexH.HalfEdge(19, 0, 2);
626 convex.edges[9] =
new ConvexH.HalfEdge(6, 4, 2);
627 convex.edges[10] =
new ConvexH.HalfEdge(20, 5, 2);
628 convex.edges[11] =
new ConvexH.HalfEdge(0, 1, 2);
630 convex.edges[12] =
new ConvexH.HalfEdge(22, 3, 3);
631 convex.edges[13] =
new ConvexH.HalfEdge(4, 7, 3);
632 convex.edges[14] =
new ConvexH.HalfEdge(17, 6, 3);
633 convex.edges[15] =
new ConvexH.HalfEdge(2, 2, 3);
635 convex.edges[16] =
new ConvexH.HalfEdge(3, 0, 4);
636 convex.edges[17] =
new ConvexH.HalfEdge(14, 2, 4);
637 convex.edges[18] =
new ConvexH.HalfEdge(7, 6, 4);
638 convex.edges[19] =
new ConvexH.HalfEdge(8, 4, 4);
640 convex.edges[20] =
new ConvexH.HalfEdge(10, 1, 5);
641 convex.edges[21] =
new ConvexH.HalfEdge(5, 5, 5);
642 convex.edges[22] =
new ConvexH.HalfEdge(12, 7, 5);
643 convex.edges[23] =
new ConvexH.HalfEdge(1, 3, 5);
648 public static ConvexH ConvexHMakeCube(float3 bmin, float3 bmax)
650 ConvexH convex = test_cube();
651 convex.vertices[0] =
new float3(bmin.x, bmin.y, bmin.z);
652 convex.vertices[1] =
new float3(bmin.x, bmin.y, bmax.z);
653 convex.vertices[2] =
new float3(bmin.x, bmax.y, bmin.z);
654 convex.vertices[3] =
new float3(bmin.x, bmax.y, bmax.z);
655 convex.vertices[4] =
new float3(bmax.x, bmin.y, bmin.z);
656 convex.vertices[5] =
new float3(bmax.x, bmin.y, bmax.z);
657 convex.vertices[6] =
new float3(bmax.x, bmax.y, bmin.z);
658 convex.vertices[7] =
new float3(bmax.x, bmax.y, bmax.z);
660 convex.facets[0] =
new Plane(
new float3(-1, 0, 0), bmin.x);
661 convex.facets[1] =
new Plane(
new float3(1, 0, 0), -bmax.x);
662 convex.facets[2] =
new Plane(
new float3(0, -1, 0), bmin.y);
663 convex.facets[3] =
new Plane(
new float3(0, 1, 0), -bmax.y);
664 convex.facets[4] =
new Plane(
new float3(0, 0, -1), bmin.z);
665 convex.facets[5] =
new Plane(
new float3(0, 0, 1), -bmax.z);
669 public static ConvexH ConvexHCrop(ref ConvexH convex, Plane slice,
float planetestepsilon)
672 int vertcountunder = 0;
673 int vertcountover = 0;
674 List<int> vertscoplanar =
new List<int>();
675 List<int> edgesplit =
new List<int>();
677 Debug.Assert(convex.edges.Count < 480);
679 EdgeFlag[] edgeflag =
new EdgeFlag[512];
680 VertFlag[] vertflag =
new VertFlag[256];
681 PlaneFlag[] planeflag =
new PlaneFlag[128];
682 ConvexH.HalfEdge[] tmpunderedges =
new ConvexH.HalfEdge[512];
684 Coplanar[] coplanaredges =
new Coplanar[512];
685 int coplanaredges_num = 0;
687 List<float3> createdverts =
new List<float3>();
690 for (i = 0; i < convex.vertices.Count; i++)
692 vertflag[i].planetest = (byte)PlaneTest(slice, convex.vertices[i], planetestepsilon);
693 if (vertflag[i].planetest == (0))
696 vertflag[i].undermap = (byte)vertcountunder++;
697 vertflag[i].overmap = (byte)vertcountover++;
699 else if (vertflag[i].planetest == (1))
701 vertflag[i].undermap = (byte)vertcountunder++;
705 Debug.Assert(vertflag[i].planetest == (2));
706 vertflag[i].overmap = (byte)vertcountover++;
707 vertflag[i].undermap = 255;
710 int vertcountunderold = vertcountunder;
712 int under_edge_count = 0;
713 int underplanescount = 0;
716 for (
int currentplane = 0; currentplane < convex.facets.Count; currentplane++)
724 int coplanaredge = -1;
728 if (e1 >= convex.edges.Count || convex.edges[e1].p != currentplane)
733 ConvexH.HalfEdge edge0 = convex.edges[e0];
734 ConvexH.HalfEdge edge1 = convex.edges[e1];
735 ConvexH.HalfEdge edgea = convex.edges[edge0.ea];
737 planeside |= vertflag[edge0.v].planetest;
743 if (vertflag[edge0.v].planetest == (2) && vertflag[edge1.v].planetest == (2))
746 edgeflag[e0].undermap = -1;
748 else if ((vertflag[edge0.v].planetest | vertflag[edge1.v].planetest) == (1))
752 edgeflag[e0].undermap = (short)under_edge_count;
753 tmpunderedges[under_edge_count].v = vertflag[edge0.v].undermap;
754 tmpunderedges[under_edge_count].p = (byte)underplanescount;
758 Debug.Assert(edgeflag[edge0.ea].undermap != -1);
759 tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap;
760 tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count;
764 else if ((vertflag[edge0.v].planetest | vertflag[edge1.v].planetest) == (0))
769 if (e2 >= convex.edges.Count || convex.edges[e2].p != currentplane)
773 Debug.Assert(convex.edges[e2].p == currentplane);
774 ConvexH.HalfEdge edge2 = convex.edges[e2];
775 if (vertflag[edge2.v].planetest == (1))
778 edgeflag[e0].undermap = (short)under_edge_count;
779 tmpunderedges[under_edge_count].v = vertflag[edge0.v].undermap;
780 tmpunderedges[under_edge_count].p = (byte)underplanescount;
781 tmpunderedges[under_edge_count].ea = -1;
783 coplanaredge = under_edge_count;
784 vout = vertflag[edge0.v].undermap;
785 vin = vertflag[edge1.v].undermap;
790 edgeflag[e0].undermap = -1;
793 else if (vertflag[edge0.v].planetest == (1) && vertflag[edge1.v].planetest == (2))
797 edgeflag[e0].undermap = (short)under_edge_count;
798 tmpunderedges[under_edge_count].v = vertflag[edge0.v].undermap;
799 tmpunderedges[under_edge_count].p = (byte)underplanescount;
802 Debug.Assert(edgeflag[edge0.ea].undermap != -1);
804 tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap;
805 tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count;
806 vout = tmpunderedges[edgeflag[edge0.ea].undermap].v;
810 Plane p0 = convex.facets[edge0.p];
811 Plane pa = convex.facets[edgea.p];
812 createdverts.Add(ThreePlaneIntersection(p0, pa, slice));
815 vout = vertcountunder++;
820 tmpunderedges[under_edge_count].v = (byte)vout;
821 tmpunderedges[under_edge_count].p = (byte)underplanescount;
822 tmpunderedges[under_edge_count].ea = -1;
823 coplanaredge = under_edge_count;
835 else if (vertflag[edge0.v].planetest == (0) && vertflag[edge1.v].planetest == (2))
839 edgeflag[e0].undermap = -1;
840 vout = vertflag[edge0.v].undermap;
843 Debug.Assert(edge0.p == currentplane);
844 while (!((planeside & 1) != 0) && k < convex.edges.Count && convex.edges[k].p == edge0.p)
846 planeside |= vertflag[convex.edges[k].v].planetest;
849 if ((planeside & 1) != 0)
851 tmpunderedges[under_edge_count].v = (byte)vout;
852 tmpunderedges[under_edge_count].p = (byte)underplanescount;
853 tmpunderedges[under_edge_count].ea = -1;
854 coplanaredge = under_edge_count;
859 else if (vertflag[edge0.v].planetest == (2) && vertflag[edge1.v].planetest == (1))
863 Debug.Assert(vin == -1);
866 Plane p0 = convex.facets[edge0.p];
867 Plane pa = convex.facets[edgea.p];
868 createdverts.Add(ThreePlaneIntersection(p0, pa, slice));
871 vin = vertcountunder++;
876 int nea = edgeflag[edge0.ea].undermap;
877 Debug.Assert(tmpunderedges[nea].p == tmpunderedges[nea + 1].p);
878 vin = tmpunderedges[nea + 1].v;
879 Debug.Assert(vin < vertcountunder);
880 Debug.Assert(vin >= vertcountunderold);
889 tmpunderedges[under_edge_count].v = (byte)vin;
890 tmpunderedges[under_edge_count].p = (byte)underplanescount;
891 edgeflag[e0].undermap = (short)under_edge_count;
894 Debug.Assert(edgeflag[edge0.ea].undermap != -1);
896 tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap;
897 tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count;
899 Debug.Assert(edgeflag[e0].undermap == under_edge_count);
902 else if (vertflag[edge0.v].planetest == (2) && vertflag[edge1.v].planetest == (0))
906 edgeflag[e0].undermap = -1;
907 vin = vertflag[edge1.v].undermap;
908 Debug.Assert(vin != -1);
926 }
while (e0 != estart);
928 if ((planeside & 1) != 0)
930 planeflag[currentplane].undermap = (byte)underplanescount;
931 tmpunderplanes[underplanescount] = convex.facets[currentplane];
936 planeflag[currentplane].undermap = 0;
938 if (vout >= 0 && (planeside & 1) != 0)
940 Debug.Assert(vin >= 0);
941 Debug.Assert(coplanaredge >= 0);
942 Debug.Assert(coplanaredge != 511);
943 coplanaredges[coplanaredges_num].ea = (ushort)coplanaredge;
944 coplanaredges[coplanaredges_num].v0 = (byte)vin;
945 coplanaredges[coplanaredges_num].v1 = (byte)vout;
951 if (coplanaredges_num > 0)
953 tmpunderplanes[underplanescount++] = slice;
955 for (i = 0; i < coplanaredges_num - 1; i++)
957 if (coplanaredges[i].v1 != coplanaredges[i + 1].v0)
960 for (j = i + 2; j < coplanaredges_num; j++)
962 if (coplanaredges[i].v1 == coplanaredges[j].v0)
964 Coplanar tmp = coplanaredges[i + 1];
965 coplanaredges[i + 1] = coplanaredges[j];
966 coplanaredges[j] = tmp;
970 if (j >= coplanaredges_num)
972 Debug.Assert(j < coplanaredges_num);
978 ConvexH punder =
new ConvexH(vertcountunder, under_edge_count + coplanaredges_num, underplanescount);
979 ConvexH under = punder;
983 for (i = 0; i < convex.vertices.Count; i++)
985 if (vertflag[i].planetest != (2))
987 under.vertices[k++] = convex.vertices[i];
991 while (k < vertcountunder)
993 under.vertices[k++] = createdverts[i++];
995 Debug.Assert(i == createdverts.Count);
998 for (i = 0; i < coplanaredges_num; i++)
1000 ConvexH.HalfEdge edge = under.edges[under_edge_count + i];
1001 edge.p = (byte)(underplanescount - 1);
1002 edge.ea = (short)coplanaredges[i].ea;
1003 edge.v = (byte)coplanaredges[i].v0;
1004 under.edges[under_edge_count + i] = edge;
1006 tmpunderedges[coplanaredges[i].ea].ea = (short)(under_edge_count + i);
1009 under.edges =
new List<ConvexH.HalfEdge>(tmpunderedges);
1010 under.facets =
new List<Plane>(tmpunderplanes);
1014 public static ConvexH ConvexHDup(ConvexH src)
1016 ConvexH dst =
new ConvexH(src.vertices.Count, src.edges.Count, src.facets.Count);
1017 dst.vertices =
new List<float3>(src.vertices.Count);
1018 foreach (float3 f
in src.vertices)
1019 dst.vertices.Add(
new float3(f));
1020 dst.edges =
new List<ConvexH.HalfEdge>(src.edges.Count);
1021 foreach (ConvexH.HalfEdge e in src.edges)
1022 dst.edges.Add(
new ConvexH.HalfEdge(e));
1023 dst.facets =
new List<Plane>(src.facets.Count);
1024 foreach (Plane p
in src.facets)
1025 dst.facets.Add(
new Plane(p));
1029 public static int candidateplane(List<Plane> planes,
int planes_count, ConvexH convex,
float epsilon)
1034 for (i = 0; i < planes_count; i++)
1037 for (
int j = 0; j < convex.vertices.Count; j++)
1039 d = Math.Max(d, float3.dot(convex.vertices[j], planes[i].normal) + planes[i].dist);
1041 if (i == 0 || d > md)
1047 return (md > epsilon) ? p : -1;
1050 public static float3 orth(float3 v)
1052 float3 a = float3.cross(v,
new float3(0f, 0f, 1f));
1053 float3 b = float3.cross(v,
new float3(0f, 1f, 0f));
1054 return float3.normalize((float3.magnitude(a) > float3.magnitude(b)) ? a : b);
1057 public static int maxdir(List<float3> p,
int count, float3 dir)
1059 Debug.Assert(count != 0);
1061 float currDotm = float3.dot(p[0], dir);
1062 for (
int i = 1; i < count; i++)
1064 float currDoti = float3.dot(p[i], dir);
1065 if (currDoti > currDotm)
1067 currDotm = currDoti;
1074 public static int maxdirfiltered(List<float3> p,
int count, float3 dir, byte[] allow)
1078 float currDotm = float3.dot(p[0], dir);
1081 while (allow[m] == 0)
1084 for (
int i = 1; i < count; i++)
1088 currDoti = float3.dot(p[i], dir);
1089 if (currDoti > currDotm)
1091 currDotm = currDoti;
1100 public static int maxdirsterid(List<float3> p,
int count, float3 dir, byte[] allow)
1105 m = maxdirfiltered(p, count, dir, allow);
1108 float3 u = orth(dir);
1109 float3 v = float3.cross(u, dir);
1111 for (
float x = 0.0f; x <= 360.0f; x += 45.0f)
1115 float s = (float)Math.Sin((3.14159264f / 180.0f) * (x));
1116 float c = (float)Math.Cos((3.14159264f / 180.0f) * (x));
1117 mb = maxdirfiltered(p, count, dir + (u * s + v * c) * 0.025f, allow);
1119 if (ma == m && mb == m)
1124 if (ma != -1 && ma != mb)
1127 for (
float xx = x - 40.0f; xx <= x; xx += 5.0f)
1129 float s = (float)Math.Sin((3.14159264f / 180.0f) * (xx));
1130 float c = (float)Math.Cos((3.14159264f / 180.0f) * (xx));
1131 int md = maxdirfiltered(p, count, dir + (u * s + v * c) * 0.025f, allow);
1132 if (mc == m && md == m)
1146 Debug.Assert(
false);
1150 public static int4 FindSimplex(List<float3> verts, byte[] allow)
1152 float3[] basis =
new float3[3];
1153 basis[0] =
new float3(0.01f, 0.02f, 1.0f);
1154 int p0 = maxdirsterid(verts, verts.Count, basis[0], allow);
1155 int p1 = maxdirsterid(verts, verts.Count, -basis[0], allow);
1156 basis[0] = verts[p0] - verts[p1];
1157 if (p0 == p1 || basis[0] ==
new float3(0, 0, 0))
1158 return new int4(-1, -1, -1, -1);
1159 basis[1] = float3.cross(
new float3(1, 0.02f, 0), basis[0]);
1160 basis[2] = float3.cross(
new float3(-0.02f, 1, 0), basis[0]);
1161 basis[1] = float3.normalize((float3.magnitude(basis[1]) > float3.magnitude(basis[2])) ? basis[1] : basis[2]);
1162 int p2 = maxdirsterid(verts, verts.Count, basis[1], allow);
1163 if (p2 == p0 || p2 == p1)
1165 p2 = maxdirsterid(verts, verts.Count, -basis[1], allow);
1167 if (p2 == p0 || p2 == p1)
1168 return new int4(-1, -1, -1, -1);
1169 basis[1] = verts[p2] - verts[p0];
1170 basis[2] = float3.normalize(float3.cross(basis[1], basis[0]));
1171 int p3 = maxdirsterid(verts, verts.Count, basis[2], allow);
1172 if (p3 == p0 || p3 == p1 || p3 == p2)
1173 p3 = maxdirsterid(verts, verts.Count, -basis[2], allow);
1174 if (p3 == p0 || p3 == p1 || p3 == p2)
1175 return new int4(-1, -1, -1, -1);
1176 Debug.Assert(!(p0 == p1 || p0 == p2 || p0 == p3 || p1 == p2 || p1 == p3 || p2 == p3));
1177 if (float3.dot(verts[p3] - verts[p0], float3.cross(verts[p1] - verts[p0], verts[p2] - verts[p0])) < 0)
1179 Swap(ref p2, ref p3);
1181 return new int4(p0, p1, p2, p3);
1184 public static float GetDist(
float px,
float py,
float pz, float3 p2)
1186 float dx = px - p2.x;
1187 float dy = py - p2.y;
1188 float dz = pz - p2.z;
1190 return dx * dx + dy * dy + dz * dz;
1193 public static void ReleaseHull(PHullResult result)
1195 if (result.Indices != null)
1196 result.Indices = null;
1197 if (result.Vertices != null)
1198 result.Vertices = null;
1201 public static int calchullgen(List<float3> verts,
int vlimit, List<HullTriangle> tris)
1203 if (verts.Count < 4)
1206 vlimit = 1000000000;
1208 float3 bmin =
new float3(verts[0]);
1209 float3 bmax =
new float3(verts[0]);
1210 List<int> isextreme =
new List<int>(verts.Count);
1211 byte[] allow =
new byte[verts.Count];
1212 for (j = 0; j < verts.Count; j++)
1216 bmin = float3.VectorMin(bmin, verts[j]);
1217 bmax = float3.VectorMax(bmax, verts[j]);
1219 float epsilon = float3.magnitude(bmax - bmin) * 0.001f;
1221 int4 p = FindSimplex(verts, allow);
1225 float3 center = (verts[p[0]] + verts[p[1]] + verts[p[2]] + verts[p[3]]) / 4.0f;
1226 HullTriangle t0 =
new HullTriangle(p[2], p[3], p[1], tris);
1227 t0.n =
new int3(2, 3, 1);
1228 HullTriangle t1 =
new HullTriangle(p[3], p[2], p[0], tris);
1229 t1.n =
new int3(3, 2, 0);
1230 HullTriangle t2 =
new HullTriangle(p[0], p[1], p[3], tris);
1231 t2.n =
new int3(0, 1, 3);
1232 HullTriangle t3 =
new HullTriangle(p[1], p[0], p[2], tris);
1233 t3.n =
new int3(1, 0, 2);
1234 isextreme[p[0]] = isextreme[p[1]] = isextreme[p[2]] = isextreme[p[3]] = 1;
1240 for (j = 0; j < tris.Count; j++)
1242 HullTriangle t = tris[j];
1243 Debug.Assert((object)t != null);
1244 Debug.Assert(t.vmax < 0);
1245 float3 n = TriNormal(verts[(t)[0]], verts[(t)[1]], verts[(t)[2]]);
1246 t.vmax = maxdirsterid(verts, verts.Count, n, allow);
1247 t.rise = float3.dot(n, verts[t.vmax] - verts[(t)[0]]);
1251 while (vlimit > 0 && (te = extrudable(epsilon, tris)) != null)
1255 Debug.Assert(isextreme[v] == 0);
1261 if (tris.Count <= j || (
object)tris[j] == null)
1264 if (above(verts, t, verts[v], 0.01f * epsilon))
1266 extrude(tris[j], v, tris);
1273 if (tris.Count <= j || (
object)tris[j] == null)
1275 if (!hasvert(tris[j], v))
1278 if (above(verts, nt, center, 0.01f * epsilon) || float3.magnitude(float3.cross(verts[nt[1]] - verts[nt[0]], verts[nt[2]] - verts[nt[1]])) < epsilon * epsilon * 0.1f)
1280 HullTriangle nb = tris[tris[j].n[0]];
1281 Debug.Assert(nb != null);
1282 Debug.Assert(!hasvert(nb, v));
1283 Debug.Assert(nb.id < j);
1284 extrude(nb, v, tris);
1291 HullTriangle t = tris[j];
1296 float3 n = TriNormal(verts[(t)[0]], verts[(t)[1]], verts[(t)[2]]);
1297 t.vmax = maxdirsterid(verts, verts.Count, n, allow);
1298 if (isextreme[t.vmax] != 0)
1304 t.rise = float3.dot(n, verts[t.vmax] - verts[(t)[0]]);
1312 public static bool calchull(List<float3> verts, out List<int> tris_out,
int vlimit, List<HullTriangle> tris)
1316 int rc = calchullgen(verts, vlimit, tris);
1319 List<int> ts =
new List<int>();
1320 for (
int i = 0; i < tris.Count; i++)
1322 if ((
object)tris[i] != null)
1324 for (
int j = 0; j < 3; j++)
1325 ts.Add((tris[i])[j]);
1335 public static int calchullpbev(List<float3> verts,
int vlimit, out List<Plane> planes,
float bevangle, List<HullTriangle> tris)
1339 planes =
new List<Plane>();
1340 int rc = calchullgen(verts, vlimit, tris);
1343 for (i = 0; i < tris.Count; i++)
1345 if (tris[i] != null)
1348 HullTriangle t = tris[i];
1349 p.normal = TriNormal(verts[(t)[0]], verts[(t)[1]], verts[(t)[2]]);
1350 p.dist = -float3.dot(p.normal, verts[(t)[0]]);
1352 for (j = 0; j < 3; j++)
1356 HullTriangle s = tris[t.n[j]];
1357 float3 snormal = TriNormal(verts[(s)[0]], verts[(s)[1]], verts[(s)[2]]);
1358 if (float3.dot(snormal, p.normal) >= Math.Cos(bevangle * (3.14159264f / 180.0f)))
1360 float3 n = float3.normalize(snormal + p.normal);
1361 planes.Add(
new Plane(n, -float3.dot(n, verts[maxdir(verts, verts.Count, n)])));
1370 public static int overhull(List<Plane> planes, List<float3> verts,
int maxplanes, out List<float3> verts_out, out List<int> faces_out,
float inflate)
1377 if (verts.Count < 4)
1379 maxplanes = Math.Min(maxplanes, planes.Count);
1380 float3 bmin =
new float3(verts[0]);
1381 float3 bmax =
new float3(verts[0]);
1382 for (i = 0; i < verts.Count; i++)
1384 bmin = float3.VectorMin(bmin, verts[i]);
1385 bmax = float3.VectorMax(bmax, verts[i]);
1389 bmin -=
new float3(inflate, inflate, inflate);
1390 bmax +=
new float3(inflate, inflate, inflate);
1391 for (i = 0; i < planes.Count; i++)
1393 planes[i].dist -= inflate;
1395 float3 emin =
new float3(bmin);
1396 float3 emax =
new float3(bmax);
1397 float epsilon = float3.magnitude(emax - emin) * 0.025f;
1398 float planetestepsilon = float3.magnitude(emax - emin) * (0.001f);
1401 ConvexH c = ConvexHMakeCube(
new float3(bmin),
new float3(bmax));
1403 while (maxplanes-- != 0 && (k = candidateplane(planes, planes.Count, c, epsilon)) >= 0)
1406 c = ConvexHCrop(ref tmp, planes[k], planetestepsilon);
1412 if (AssertIntact(c, planetestepsilon) ==
false)
1419 tmp.vertices = null;
1422 Debug.Assert(AssertIntact(c, planetestepsilon));
1425 faces_out =
new List<int>();
1426 int faces_count_out = 0;
1428 faces_out[faces_count_out++] = -1;
1430 while (i < c.edges.Count)
1433 while (j + i < c.edges.Count && c.edges[i].p == c.edges[i + j].p)
1437 faces_out[faces_count_out++] = j;
1440 faces_out[faces_count_out++] = c.edges[i].v;
1446 Debug.Assert(k == c.facets.Count);
1447 Debug.Assert(faces_count_out == 1 + c.facets.Count + c.edges.Count);
1448 verts_out = c.vertices;
1449 int verts_count_out = c.vertices.Count;
1450 for (i = 0; i < c.vertices.Count; i++)
1452 verts_out[i] =
new float3(c.vertices[i]);
1461 public static int overhullv(List<float3> verts,
int maxplanes, out List<float3> verts_out, out List<int> faces_out,
float inflate,
float bevangle,
int vlimit, List<HullTriangle> tris)
1466 if (verts.Count == 0)
1468 List<Plane> planes =
new List<Plane>();
1469 int rc = calchullpbev(verts, vlimit, out planes, bevangle, tris);
1472 return overhull(planes, verts, maxplanes, out verts_out, out faces_out, inflate);
1475 public static void addPoint(ref uint vcount, List<float3> p,
float x,
float y,
float z)
1477 p.Add(
new float3(x, y, z));
1481 public static bool ComputeHull(List<float3> vertices, ref PHullResult result,
int vlimit,
float inflate)
1483 List<HullTriangle> tris =
new List<HullTriangle>();
1485 List<float3> verts_out;
1487 if (inflate == 0.0f)
1490 bool ret = calchull(vertices, out tris_out, vlimit, tris);
1494 result.Indices = tris_out;
1495 result.Vertices = vertices;
1500 int ret = overhullv(vertices, 35, out verts_out, out faces, inflate, 120.0f, vlimit, tris);
1504 List<int3> tris2 =
new List<int3>();
1507 for (
int i = 0; i < n; i++)
1509 int pn = faces[k++];
1510 for (
int j = 2; j < pn; j++)
1511 tris2.Add(
new int3(faces[k], faces[k + j - 1], faces[k + j]));
1514 Debug.Assert(tris2.Count == faces.Count - 1 - (n * 3));
1516 result.Indices =
new List<int>(tris2.Count * 3);
1517 for (
int i = 0; i < tris2.Count; i++)
1519 result.Indices.Add(tris2[i].x);
1520 result.Indices.Add(tris2[i].y);
1521 result.Indices.Add(tris2[i].z);
1523 result.Vertices = verts_out;
1529 private static bool CleanupVertices(List<float3> svertices, out List<float3> vertices,
float normalepsilon, out float3 scale)
1531 const float EPSILON = 0.000001f;
1533 vertices =
new List<float3>();
1534 scale =
new float3(1f, 1f, 1f);
1536 if (svertices.Count == 0)
1541 float[] recip =
new float[3];
1543 float[] bmin = { Single.MaxValue, Single.MaxValue, Single.MaxValue };
1544 float[] bmax = { Single.MinValue, Single.MinValue, Single.MinValue };
1546 for (
int i = 0; i < svertices.Count; i++)
1548 float3 p = svertices[i];
1550 for (
int j = 0; j < 3; j++)
1559 float dx = bmax[0] - bmin[0];
1560 float dy = bmax[1] - bmin[1];
1561 float dz = bmax[2] - bmin[2];
1563 float3 center =
new float3();
1565 center.x = dx * 0.5f + bmin[0];
1566 center.y = dy * 0.5f + bmin[1];
1567 center.z = dz * 0.5f + bmin[2];
1569 if (dx < EPSILON || dy < EPSILON || dz < EPSILON || svertices.Count < 3)
1571 float len = Single.MaxValue;
1573 if (dx > EPSILON && dx < len)
1575 if (dy > EPSILON && dy < len)
1577 if (dz > EPSILON && dz < len)
1580 if (len == Single.MaxValue)
1582 dx = dy = dz = 0.01f;
1594 float x1 = center[0] - dx;
1595 float x2 = center[0] + dx;
1597 float y1 = center[1] - dy;
1598 float y2 = center[1] + dy;
1600 float z1 = center[2] - dz;
1601 float z2 = center[2] + dz;
1603 addPoint(ref vcount, vertices, x1, y1, z1);
1604 addPoint(ref vcount, vertices, x2, y1, z1);
1605 addPoint(ref vcount, vertices, x2, y2, z1);
1606 addPoint(ref vcount, vertices, x1, y2, z1);
1607 addPoint(ref vcount, vertices, x1, y1, z2);
1608 addPoint(ref vcount, vertices, x2, y1, z2);
1609 addPoint(ref vcount, vertices, x2, y2, z2);
1610 addPoint(ref vcount, vertices, x1, y2, z2);
1624 center.x *= recip[0];
1625 center.y *= recip[1];
1626 center.z *= recip[2];
1629 for (
int i = 0; i < svertices.Count; i++)
1631 float3 p = svertices[i];
1645 for (j = 0; j < vcount; j++)
1647 float3 v = vertices[j];
1653 float dx1 = Math.Abs(x - px);
1654 float dy1 = Math.Abs(y - py);
1655 float dz1 = Math.Abs(z - pz);
1657 if (dx1 < normalepsilon && dy1 < normalepsilon && dz1 < normalepsilon)
1662 float dist1 = GetDist(px, py, pz, center);
1663 float dist2 = GetDist(v[0], v[1], v[2], center);
1678 float3 dest =
new float3(px, py, pz);
1688 float[] bmin2 = { Single.MaxValue, Single.MaxValue, Single.MaxValue };
1689 float[] bmax2 = { Single.MinValue, Single.MinValue, Single.MinValue };
1691 for (
int i = 0; i < vcount; i++)
1693 float3 p = vertices[i];
1694 for (
int j = 0; j < 3; j++)
1696 if (p[j] < bmin2[j])
1698 if (p[j] > bmax2[j])
1703 float dx2 = bmax2[0] - bmin2[0];
1704 float dy2 = bmax2[1] - bmin2[1];
1705 float dz2 = bmax2[2] - bmin2[2];
1707 if (dx2 < EPSILON || dy2 < EPSILON || dz2 < EPSILON || vcount < 3)
1709 float cx = dx2 * 0.5f + bmin2[0];
1710 float cy = dy2 * 0.5f + bmin2[1];
1711 float cz = dz2 * 0.5f + bmin2[2];
1713 float len = Single.MaxValue;
1715 if (dx2 >= EPSILON && dx2 < len)
1717 if (dy2 >= EPSILON && dy2 < len)
1719 if (dz2 >= EPSILON && dz2 < len)
1722 if (len == Single.MaxValue)
1724 dx2 = dy2 = dz2 = 0.01f;
1736 float x1 = cx - dx2;
1737 float x2 = cx + dx2;
1739 float y1 = cy - dy2;
1740 float y2 = cy + dy2;
1742 float z1 = cz - dz2;
1743 float z2 = cz + dz2;
1747 addPoint(ref vcount, vertices, x1, y1, z1);
1748 addPoint(ref vcount, vertices, x2, y1, z1);
1749 addPoint(ref vcount, vertices, x2, y2, z1);
1750 addPoint(ref vcount, vertices, x1, y2, z1);
1751 addPoint(ref vcount, vertices, x1, y1, z2);
1752 addPoint(ref vcount, vertices, x2, y1, z2);
1753 addPoint(ref vcount, vertices, x2, y2, z2);
1754 addPoint(ref vcount, vertices, x1, y2, z2);
1763 private static void BringOutYourDead(List<float3> verts, out List<float3> overts, List<int> indices)
1765 int[] used =
new int[verts.Count];
1768 overts =
new List<float3>();
1770 for (
int i = 0; i < indices.Count; i++)
1774 Debug.Assert(v >= 0 && v < verts.Count);
1778 indices[i] = used[v] - 1;
1782 indices[i] = ocount;
1784 overts.Add(verts[v]);
1788 Debug.Assert(ocount >= 0 && ocount <= verts.Count);
1795 public static HullError CreateConvexHull(HullDesc desc, ref HullResult result)
1799 PHullResult hr =
new PHullResult();
1801 uint vcount = (uint)desc.Vertices.Count;
1805 List<float3> vsource;
1806 float3 scale =
new float3();
1808 bool ok = CleanupVertices(desc.Vertices, out vsource, desc.NormalEpsilon, out scale);
1814 for (
int i = 0; i < vsource.Count; i++)
1816 float3 v = vsource[i];
1823 float skinwidth = 0;
1824 if (desc.HasHullFlag(
HullFlag.QF_SKIN_WIDTH))
1825 skinwidth = desc.SkinWidth;
1827 ok = ComputeHull(vsource, ref hr, (
int)desc.MaxVertices, skinwidth);
1831 List<float3> vscratch;
1832 BringOutYourDead(hr.Vertices, out vscratch, hr.Indices);
1834 ret = HullError.QE_OK;
1836 if (desc.HasHullFlag(
HullFlag.QF_TRIANGLES))
1838 result.Polygons =
false;
1839 result.Indices = hr.Indices;
1840 result.OutputVertices = vscratch;
1844 result.Polygons =
true;
1845 result.OutputVertices = vscratch;
1849 List<int> source = hr.Indices;
1850 List<int> dest =
new List<int>();
1851 for (
int i = 0; i < hr.Indices.Count / 3; i++)
1854 dest.Add(source[i * 3 + 0]);
1855 dest.Add(source[i * 3 + 1]);
1856 dest.Add(source[i * 3 + 2]);
1859 result.Indices = dest;