private static List <HitObject> CheckJoint(HitTriangle ph3d1, HitTriangle ph3d2, IItem item)
        {
            var hitObjects = new List <HitObject>();

            if (ph3d1 != null)                 // may be null in case of degenerate triangles
            {
                var jointNormal = Vertex3D.CrossProduct(ph3d1.Normal, ph3d2.Normal);
                if (jointNormal.LengthSq() < 1e-8)                   // coplanar triangles need no joints
                {
                    return(hitObjects);
                }
            }
            // By convention of the calling function, points 1 [0] and 2 [1] of the second polygon will
            // be the common-edge points
            hitObjects.Add(GenerateJoint(ph3d2.Rgv[0], ph3d2.Rgv[1], item));
            return(hitObjects);
        }
 public static void Create(BlobBuilder builder, HitTriangle src, ref BlobPtr <Collider> dest)
 {
     ref var trianglePtr = ref UnsafeUtility.As <BlobPtr <Collider>, BlobPtr <TriangleCollider> >(ref dest);
        public HitObject[] GenerateHitObjects(Table.Table table, IItem item)
        {
            var hitObjects  = new List <HitObject>();
            var rv          = _meshGenerator.GetRampVertex(table, PhysicsConstants.HitShapeDetailLevel, true);
            var rgvLocal    = rv.RgvLocal;
            var rgHeight1   = rv.PointHeights;
            var vertexCount = rv.VertexCount;

            var(wallHeightRight, wallHeightLeft) = GetWallHeights();

            Vertex2D pv1, pv2, pv3 = new Vertex2D(), pv4 = new Vertex2D();

            // Add line segments for right ramp wall.
            if (wallHeightRight > 0.0f)
            {
                for (var i = 0; i < vertexCount - 1; i++)
                {
                    pv2 = rgvLocal[i];
                    pv3 = rgvLocal[i + 1];

                    hitObjects.AddRange(GenerateWallLineSeg(pv2, pv3, i > 0,
                                                            rgHeight1[i], rgHeight1[i + 1], wallHeightRight, item));
                    hitObjects.AddRange(GenerateWallLineSeg(pv3, pv2, i < vertexCount - 2,
                                                            rgHeight1[i], rgHeight1[i + 1], wallHeightRight, item));

                    // add joints at start and end of right wall
                    if (i == 0)
                    {
                        hitObjects.Add(GenerateJoint2D(pv2, rgHeight1[0], rgHeight1[0] + wallHeightRight, item));
                    }

                    if (i == vertexCount - 2)
                    {
                        hitObjects.Add(GenerateJoint2D(pv3, rgHeight1[vertexCount - 1],
                                                       rgHeight1[vertexCount - 1] + wallHeightRight, item));
                    }
                }
            }

            // Add line segments for left ramp wall.
            if (wallHeightLeft > 0.0f)
            {
                for (var i = 0; i < vertexCount - 1; i++)
                {
                    pv2 = rgvLocal[vertexCount + i];
                    pv3 = rgvLocal[vertexCount + i + 1];

                    hitObjects.AddRange(GenerateWallLineSeg(pv2, pv3, i > 0,
                                                            rgHeight1[vertexCount - i - 2], rgHeight1[vertexCount - i - 1], wallHeightLeft, item));
                    hitObjects.AddRange(GenerateWallLineSeg(pv3, pv2, i < vertexCount - 2,
                                                            rgHeight1[vertexCount - i - 2], rgHeight1[vertexCount - i - 1], wallHeightLeft, item));

                    // add joints at start and end of left wall
                    if (i == 0)
                    {
                        hitObjects.Add(GenerateJoint2D(pv2, rgHeight1[vertexCount - 1],
                                                       rgHeight1[vertexCount - 1] + wallHeightLeft, item));
                    }

                    if (i == vertexCount - 2)
                    {
                        hitObjects.Add(GenerateJoint2D(pv3, rgHeight1[0], rgHeight1[0] + wallHeightLeft, item));
                    }
                }
            }

            // Add hit triangles for the ramp floor.
            HitTriangle ph3dpoly, ph3dpolyOld = null;

            Vertex3D[] rgv3D;

            for (var i = 0; i < vertexCount - 1; i++)
            {
                /*
                 * Layout of one ramp quad seen from above, ramp direction is bottom to top:
                 *
                 *    3 - - 4
                 *    | \   |
                 *    |   \ |
                 *    2 - - 1
                 */
                pv1 = rgvLocal[i];                       // i-th right
                pv2 = rgvLocal[vertexCount * 2 - i - 1]; // i-th left
                pv3 = rgvLocal[vertexCount * 2 - i - 2]; // (i+1)-th left
                pv4 = rgvLocal[i + 1];                   // (i+1)-th right

                // left ramp floor triangle, CCW order
                rgv3D = new [] {
                    new Vertex3D(pv2.X, pv2.Y, rgHeight1[i]),
                    new Vertex3D(pv1.X, pv1.Y, rgHeight1[i]),
                    new Vertex3D(pv3.X, pv3.Y, rgHeight1[i + 1])
                };

                // add joint for starting edge of ramp
                if (i == 0)
                {
                    hitObjects.Add(GenerateJoint(rgv3D[0], rgv3D[1], item));
                }

                // add joint for left edge
                hitObjects.Add(GenerateJoint(rgv3D[0], rgv3D[2], item));

                //!! this is not efficient at all, use native triangle-soup directly somehow
                ph3dpoly = new HitTriangle(rgv3D, ItemType.Ramp, item);

                if (!ph3dpoly.IsDegenerate)                   // degenerate triangles happen if width is 0 at some point
                {
                    hitObjects.Add(ph3dpoly);
                    hitObjects.AddRange(CheckJoint(ph3dpolyOld, ph3dpoly, item));
                    ph3dpolyOld = ph3dpoly;
                }

                // right ramp floor triangle, CCW order
                rgv3D = new [] {
                    new Vertex3D(pv3.X, pv3.Y, rgHeight1[i + 1]),
                    new Vertex3D(pv1.X, pv1.Y, rgHeight1[i]),
                    new Vertex3D(pv4.X, pv4.Y, rgHeight1[i + 1])
                };

                // add joint for right edge
                hitObjects.Add(GenerateJoint(rgv3D[1], rgv3D[2], item));

                ph3dpoly = new HitTriangle(rgv3D, ItemType.Ramp, item);
                if (!ph3dpoly.IsDegenerate)
                {
                    hitObjects.Add(ph3dpoly);
                }

                hitObjects.AddRange(CheckJoint(ph3dpolyOld, ph3dpoly, item));
                ph3dpolyOld = ph3dpoly;
            }

            if (vertexCount >= 2)
            {
                // add joint for final edge of ramp
                var v1 = new Vertex3D(pv4.X, pv4.Y, rgHeight1[vertexCount - 1]);
                var v2 = new Vertex3D(pv3.X, pv3.Y, rgHeight1[vertexCount - 1]);
                hitObjects.Add(GenerateJoint(v1, v2, item));
            }

            // add outside bottom,
            // joints at the intersections are not needed since the inner surface has them
            // this surface is identical... except for the direction of the normal face.
            // hence the joints protect both surface edges from having a fall through

            for (var i = 0; i < vertexCount - 1; i++)
            {
                // see sketch above
                pv1 = rgvLocal[i];
                pv2 = rgvLocal[vertexCount * 2 - i - 1];
                pv3 = rgvLocal[vertexCount * 2 - i - 2];
                pv4 = rgvLocal[i + 1];

                // left ramp triangle, order CW
                rgv3D = new[] {
                    new Vertex3D(pv1.X, pv1.Y, rgHeight1[i]),
                    new Vertex3D(pv2.X, pv2.Y, rgHeight1[i]),
                    new Vertex3D(pv3.X, pv3.Y, rgHeight1[i + 1])
                };

                ph3dpoly = new HitTriangle(rgv3D, ItemType.Ramp, item);
                if (!ph3dpoly.IsDegenerate)
                {
                    hitObjects.Add(ph3dpoly);
                }

                // right ramp triangle, order CW
                rgv3D = new[] {
                    new Vertex3D(pv3.X, pv3.Y, rgHeight1[i + 1]),
                    new Vertex3D(pv4.X, pv4.Y, rgHeight1[i + 1]),
                    new Vertex3D(pv1.X, pv1.Y, rgHeight1[i])
                };

                ph3dpoly = new HitTriangle(rgv3D, ItemType.Ramp, item);
                if (!ph3dpoly.IsDegenerate)
                {
                    hitObjects.Add(ph3dpoly);
                }
            }

            return(hitObjects
                   .Select(obj => SetupHitObject(obj, table))
                   .ToArray());
        }