public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            // todo - proper swept test
            #region Get Cylinders
            Cylinder oldCylinder0 = (Cylinder)info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0);
            Cylinder newCylinder0 = (Cylinder)info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0);
            Cylinder oldCylinder1 = (Cylinder)info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1);
            Cylinder newCylinder1 = (Cylinder)info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1);
            #endregion

            Segment oldSeg0 = new Segment(oldCylinder0.Position, oldCylinder0.Length * MatrixHelper.GetBackward(oldCylinder0.Orientation));
            Segment newSeg0 = new Segment(newCylinder0.Position, newCylinder0.Length * MatrixHelper.GetBackward(newCylinder0.Orientation));
            Segment oldSeg1 = new Segment(oldCylinder1.Position, oldCylinder1.Length * MatrixHelper.GetBackward(oldCylinder1.Orientation));
            Segment newSeg1 = new Segment(newCylinder1.Position, newCylinder1.Length * MatrixHelper.GetBackward(newCylinder1.Orientation));

            float radSum = newCylinder0.Radius + newCylinder1.Radius;

            float oldt0, oldt1;
            float newt0, newt1;
            float oldDistSq = Distance.SegmentSegmentDistanceSq(out oldt0, out oldt1, oldSeg0, oldSeg1);
            float newDistSq = Distance.SegmentSegmentDistanceSq(out newt0, out newt1, newSeg0, newSeg1);

            if (System.Math.Min(oldDistSq, newDistSq) < ((radSum + collTolerance) * (radSum + collTolerance)))
            {
                Vector3 pos0 = oldSeg0.GetPoint(oldt0);
                Vector3 pos1 = oldSeg1.GetPoint(oldt1);

                Vector3 delta = pos0 - pos1;

                float dist = (float)System.Math.Sqrt((float)oldDistSq);
                float depth = radSum - dist;

                if (dist > JiggleMath.Epsilon)
                {
                    delta /= dist;
                }
                else
                {
                    // todo - make this not random
                    delta = Vector3.TransformCoordinate(Vector3Helper.Backward, Matrix.RotationAxis(Vector3Helper.Up, MathHelper.ToRadians(random.Next(360))));
                }

                Vector3 worldPos = pos1 +
                    (oldCylinder1.Radius - 0.5f * depth) * delta;

                unsafe
                {
                    SmallCollPointInfo collInfo = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, depth);
                    collisionFunctor.CollisionNotify(ref info, ref delta, &collInfo, 1);
                }

            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            // todo - proper swept test
            Sphere oldSphere = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Sphere;
            Sphere newSphere = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Sphere;

            JigLibSDX.Geometry.Plane oldPlane = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as JigLibSDX.Geometry.Plane;
            JigLibSDX.Geometry.Plane newPlane = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as JigLibSDX.Geometry.Plane;

            Matrix newPlaneInvTransform = newPlane.InverseTransformMatrix;
            Matrix oldPlaneInvTransform = oldPlane.InverseTransformMatrix;

            Vector3 oldSpherePos = Vector3.TransformCoordinate(oldSphere.Position, oldPlaneInvTransform);
            Vector3 newSpherePos = Vector3.TransformCoordinate(newSphere.Position, newPlaneInvTransform);

            // consider it a contact if either old or new are touching
            float oldDist = Distance.PointPlaneDistance(oldSpherePos, oldPlane);
            float newDist = Distance.PointPlaneDistance(newSpherePos, newPlane);

            if (System.Math.Min(newDist, oldDist) > collTolerance + newSphere.Radius)
                return;

            // collision - record depth using the old values
            float oldDepth = oldSphere.Radius - oldDist;

            // calc the world position based on the old position(s)
            Vector3 worldPos = oldSphere.Position - oldSphere.Radius * oldPlane.Normal;

            unsafe
            {
                SmallCollPointInfo collInfo = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, oldDepth);
                collisionFunctor.CollisionNotify(ref info, ref oldPlane.normal, &collInfo, 1);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            // todo - proper swept test
            Sphere oldSphere0 = (Sphere) info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0);
            Sphere newSphere0 = (Sphere)info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0);
            Sphere oldSphere1 = (Sphere)info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1);
            Sphere newSphere1 = (Sphere)info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1);

            Vector3 oldDelta = oldSphere0.Position - oldSphere1.Position;
            Vector3 newDelta = newSphere0.Position - oldSphere1.Position;

            float oldDistSq = oldDelta.LengthSquared();
            float newDistSq = newDelta.LengthSquared();

            float radSum = newSphere0.Radius + newSphere1.Radius;

            if (System.Math.Min(oldDistSq, newDistSq) < ((radSum + collTolerance) * (radSum + collTolerance)))
            {
                float oldDist = (float)System.Math.Sqrt((float)oldDistSq);
                float depth = radSum - oldDist;

                if (oldDist > JiggleMath.Epsilon)
                {
                    oldDelta /= oldDist;
                }
                else
                {
                    // TODO - make this not random...!
                    oldDelta = Vector3.TransformCoordinate(Vector3Helper.Backward, Matrix.RotationAxis(Vector3Helper.Up, MathHelper.ToRadians(random.Next(360))));
                }

                Vector3 worldPos = oldSphere1.Position +
                    (oldSphere1.Radius - 0.5f * depth) * oldDelta;

                unsafe
                {
                    SmallCollPointInfo collInfo = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, depth);

                    collisionFunctor.CollisionNotify(ref info, ref oldDelta, &collInfo, 1);
                }
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="infoOrig"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo infoOrig, float collTolerance, CollisionFunctor collisionFunctor)
        {
            CollDetectInfo info = infoOrig;
            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            // todo - proper swept test
            Sphere oldSphere = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Sphere;
            Sphere newSphere = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Sphere;

            Heightmap oldHeightmap = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as Heightmap;
            Heightmap newHeightmap = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as Heightmap;

            float newDist;
            Vector3 normal;
            newHeightmap.GetHeightAndNormal(out newDist, out normal,newSphere.Position);
            if (newDist < collTolerance + newSphere.Radius)
            {
                float oldDist = oldHeightmap.GetHeight(oldSphere.Position);
                float depth = oldSphere.Radius - oldDist;

                // calc the world position when it just hit
                Vector3 oldPt = oldSphere.Position - oldSphere.Radius * normal;
                unsafe
                {
                    SmallCollPointInfo ptInfo = new SmallCollPointInfo(oldPt - body0Pos, oldPt - body1Pos, depth);

                    collisionFunctor.CollisionNotify(ref info, ref normal, &ptInfo, 1);
                }
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            // todo - proper swept test
            Capsule oldCapsule = (Capsule)info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0);
            Capsule newCapsule = (Capsule)info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0);

            JigLibSDX.Geometry.Plane oldPlane = (JigLibSDX.Geometry.Plane)info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1);
            JigLibSDX.Geometry.Plane newPlane = (JigLibSDX.Geometry.Plane)info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1);

            Matrix newPlaneInvTransform = newPlane.InverseTransformMatrix;
            Matrix oldPlaneInvTransform = oldPlane.InverseTransformMatrix;

            unsafe
            {
            #if USE_STACKALLOC
                SmallCollPointInfo* collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI];
            #else
                SmallCollPointInfo[] collPtArray = SCPIStackAlloc();
                fixed (SmallCollPointInfo* collPts = collPtArray)
            #endif
                {
                    int numCollPts = 0;

                    // the start
                    {
                        Vector3 oldCapsuleStartPos = Vector3.TransformCoordinate(oldCapsule.Position, oldPlaneInvTransform);
                        Vector3 newCapsuleStartPos = Vector3.TransformCoordinate(newCapsule.Position, newPlaneInvTransform);

                        float oldDist = Distance.PointPlaneDistance(oldCapsuleStartPos, oldPlane);
                        float newDist = Distance.PointPlaneDistance(newCapsuleStartPos, newPlane);

                        if (MathHelper.Min(newDist, oldDist) < collTolerance + newCapsule.Radius)
                        {
                            float oldDepth = oldCapsule.Radius - oldDist;
                            // calc the world position based on the old position8(s)
                            Vector3 worldPos = oldCapsule.Position - oldCapsule.Radius * oldPlane.Normal;
                            collPts[numCollPts++] = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, oldDepth);
                        }
                    }

                    // the end
                    {
                        Vector3 oldCapsuleEndPos = Vector3.TransformCoordinate(oldCapsule.GetEnd(), oldPlaneInvTransform);
                        Vector3 newCapsuleEndPos = Vector3.TransformCoordinate(newCapsule.GetEnd(), newPlaneInvTransform);
                        float oldDist = Distance.PointPlaneDistance(oldCapsuleEndPos, oldPlane);
                        float newDist = Distance.PointPlaneDistance(newCapsuleEndPos, newPlane);

                        if (System.Math.Min(newDist, oldDist) < collTolerance + newCapsule.Radius)
                        {
                            float oldDepth = oldCapsule.Radius - oldDist;
                            // calc the world position based on the old position(s)
                            Vector3 worldPos = oldCapsule.GetEnd() - oldCapsule.Radius * oldPlane.Normal;
                            collPts[numCollPts++] = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, oldDepth);
                        }

                        if (numCollPts > 0)
                        {
                            collisionFunctor.CollisionNotify(ref info, ref oldPlane.normal, collPts, numCollPts);
                        }
                    }
                }
            #if !USE_STACKALLOC
                FreeStackAlloc(collPtArray);
            #endif
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="infoOrig"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo infoOrig, float collTolerance, CollisionFunctor collisionFunctor)
        {
            CollDetectInfo info = infoOrig;

            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            // todo - proper swept test
            Capsule oldCapsule = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Capsule;
            Capsule newCapsule = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Capsule;

            Heightmap oldHeightmap = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as Heightmap;
            Heightmap newHeightmap = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as Heightmap;

            unsafe
            {

            #if USE_STACKALLOC
                SmallCollPointInfo* collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI];
            #else
                SmallCollPointInfo[] collPtArray = SCPIStackAlloc();
                fixed (SmallCollPointInfo* collPts = collPtArray)
            #endif
                {
                    int numCollPts = 0;
                    Vector3 averageNormal = Vector3.Zero;

                    // the start
                    {
                        float oldDist, newDist;
                        Vector3 normal;
                        oldHeightmap.GetHeightAndNormal(out oldDist, out normal, oldCapsule.Position);
                        newHeightmap.GetHeightAndNormal(out newDist, out normal, newCapsule.Position);

                        if (MathHelper.Min(newDist, oldDist) < collTolerance + newCapsule.Radius)
                        {
                            float oldDepth = oldCapsule.Radius - oldDist;
                            // calc the world position based on the old position(s)
                            Vector3 worldPos = oldCapsule.Position - oldCapsule.Radius * normal;
                            if (numCollPts < MaxLocalStackSCPI)
                            {
                                collPts[numCollPts++] = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, oldDepth);
                            }
                            averageNormal += normal;
                        }
                    }
                    // the end
                    {
                        Vector3 oldEnd = oldCapsule.GetEnd();
                        Vector3 newEnd = newCapsule.GetEnd();
                        float oldDist, newDist;
                        Vector3 normal;
                        oldHeightmap.GetHeightAndNormal(out oldDist, out normal, oldEnd);
                        newHeightmap.GetHeightAndNormal(out newDist, out normal, newEnd);
                        if (MathHelper.Min(newDist, oldDist) < collTolerance + newCapsule.Radius)
                        {
                            float oldDepth = oldCapsule.Radius - oldDist;
                            // calc the world position based on the old position(s)
                            Vector3 worldPos = oldEnd - oldCapsule.Radius * normal;
                            if (numCollPts < MaxLocalStackSCPI)
                            {
                                collPts[numCollPts++] = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, oldDepth);
                            }
                            averageNormal += normal;
                        }
                    }

                    if (numCollPts > 0)
                    {
                        JiggleMath.NormalizeSafe(ref averageNormal);
                        collisionFunctor.CollisionNotify(ref info, ref averageNormal, collPts, numCollPts);
                    }
                }
            #if !USE_STACKALLOC
                FreeStackAlloc(collPtArray);
            #endif
            }
        }
        public static void CollDetectSphereStaticMeshOverlap(BoundingSphere oldSphere, BoundingSphere newSphere,
            TriangleMesh mesh, CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            float sphereTolR = collTolerance + newSphere.Radius;
            float sphereTolR2 = sphereTolR * sphereTolR;

            unsafe
            {
            #if USE_STACKALLOC
                SmallCollPointInfo* collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI];
                int* potentialTriangles = stackalloc int[MaxLocalStackTris];
                {
                    {
            #else
                SmallCollPointInfo[] collPtArray = SCPIStackAlloc();
                fixed (SmallCollPointInfo* collPts = collPtArray)
                {
                    int[] potTriArray = IntStackAlloc();
                    fixed( int* potentialTriangles = potTriArray)
                    {
            #endif
                        int numCollPts = 0;

                        Vector3 collNormal = Vector3.Zero;

                        BoundingBox bb = BoundingBoxHelper.InitialBox;
                        BoundingBoxHelper.AddSphere(newSphere, ref bb);
                        int numTriangles = mesh.GetTrianglesIntersectingtAABox(potentialTriangles, MaxLocalStackTris, ref bb);

                        // Deano : get the spheres centers in triangle mesh space
                        Vector3 newSphereCen = Vector3.TransformCoordinate(newSphere.Center, mesh.InverseTransformMatrix);
                        Vector3 oldSphereCen = Vector3.TransformCoordinate(oldSphere.Center, mesh.InverseTransformMatrix);

                        for (int iTriangle = 0; iTriangle < numTriangles; ++iTriangle)
                        {
                            IndexedTriangle meshTriangle = mesh.GetTriangle(potentialTriangles[iTriangle]);
                            float distToCentre = SlimDX.Plane.DotCoordinate(meshTriangle.Plane, newSphereCen); //meshTriangle.Plane.DotCoordinate(newSphereCen);

                            if (distToCentre <= 0.0f)
                                continue;
                            if (distToCentre >= sphereTolR)
                                continue;
                            int i0, i1, i2;
                            meshTriangle.GetVertexIndices(out i0, out i1, out i2);

                            Triangle triangle = new Triangle(mesh.GetVertex(i0), mesh.GetVertex(i1), mesh.GetVertex(i2));

                            float s, t;
                            float newD2 = Distance.PointTriangleDistanceSq(out s, out t, newSphereCen, triangle);

                            if (newD2 < sphereTolR2)
                            {
                                // have overlap - but actually report the old intersection
                                float oldD2 = Distance.PointTriangleDistanceSq(out s, out t, oldSphereCen, triangle);
                                float dist = (float)System.Math.Sqrt((float)oldD2);
                                float depth = oldSphere.Radius - dist;

                                Vector3 triPointSTNorm = oldSphereCen - triangle.GetPoint(s, t);
                                JiggleMath.NormalizeSafe(ref triPointSTNorm);

                                Vector3 collisionN = (dist > float.Epsilon) ? triPointSTNorm : triangle.Normal;

                                // since impulse get applied at the old position
                                Vector3 pt = oldSphere.Center - oldSphere.Radius * collisionN;

                                if (numCollPts < MaxLocalStackSCPI)
                                {
                                    collPts[numCollPts++] = new SmallCollPointInfo(pt - body0Pos, pt - body1Pos, depth);
                                }
                                collNormal += collisionN;
                            }
                        }

                        if (numCollPts > 0)
                        {
                            JiggleMath.NormalizeSafe(ref collNormal);
                            collisionFunctor.CollisionNotify(ref info, ref collNormal, collPts, numCollPts);
                        }
            #if USE_STACKALLOC
                    }
               }
            #else

                        FreeStackAlloc(potTriArray);
                    }
                    FreeStackAlloc(collPtArray);
                }
            #endif
            }
        }
        internal static void CollDetectSphereStaticMeshSweep(BoundingSphere oldSphere, BoundingSphere newSphere, TriangleMesh mesh,
            CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            // really use a swept test - or overlap?
            Vector3 delta = newSphere.Center - oldSphere.Center;
            if (delta.LengthSquared() < (0.25f * newSphere.Radius * newSphere.Radius))
            {
                CollDetectSphereStaticMeshOverlap(oldSphere, newSphere, mesh, info, collTolerance, collisionFunctor);
            }
            else
            {
                Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
                Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

                float sphereTolR = collTolerance + oldSphere.Radius;
                float sphereToR2 = sphereTolR * sphereTolR;

                Vector3 collNormal = Vector3.Zero;

                BoundingBox bb = BoundingBoxHelper.InitialBox;
                BoundingBoxHelper.AddSphere(oldSphere, ref bb);
                BoundingBoxHelper.AddSphere(newSphere, ref bb);

                // get the spheres centers in triangle mesh space
                Vector3 newSphereCen = Vector3.TransformCoordinate(newSphere.Center, mesh.InverseTransformMatrix);
                Vector3 oldSphereCen = Vector3.TransformCoordinate(oldSphere.Center, mesh.InverseTransformMatrix);

                unsafe
                {
            #if USE_STACKALLOC
                    SmallCollPointInfo* collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI];
                    int* potentialTriangles = stackalloc int[MaxLocalStackTris];
                    {
                        {
            #else
                    SmallCollPointInfo[] collPtArray = SCPIStackAlloc();
                    fixed (SmallCollPointInfo* collPts = collPtArray)
                    {
                        int[] potTriArray = IntStackAlloc();
                        fixed( int* potentialTriangles = potTriArray)
                        {
            #endif
                            int numCollPts = 0;

                            int numTriangles = mesh.GetTrianglesIntersectingtAABox(potentialTriangles, MaxLocalStackTris, ref bb);

                            for (int iTriangle = 0; iTriangle < numTriangles; ++iTriangle)
                            {

                                // first test the old sphere for being on the wrong side
                                IndexedTriangle meshTriangle = mesh.GetTriangle(potentialTriangles[iTriangle]);
                                float distToCentreOld = SlimDX.Plane.DotCoordinate(meshTriangle.Plane, oldSphereCen);
                                if (distToCentreOld <= 0.0f)
                                    continue;
                                // now test the new sphere for being clear

                                float distToCentreNew = SlimDX.Plane.DotCoordinate(meshTriangle.Plane, newSphereCen);
                                if (distToCentreNew > sphereTolR)
                                    continue;

                                int i0, i1, i2;
                                meshTriangle.GetVertexIndices(out i0, out i1, out i2);

                                Triangle triangle = new Triangle(mesh.GetVertex(i0), mesh.GetVertex(i1), mesh.GetVertex(i2));

                                // If the old sphere is intersecting, just use that result
                                float s, t;
                                float d2 = Distance.PointTriangleDistanceSq(out s, out t, oldSphereCen, triangle);

                                if (d2 < sphereToR2)
                                {
                                    float dist = (float)System.Math.Sqrt(d2);
                                    float depth = oldSphere.Radius - dist;
                                    Vector3 triangleN = triangle.Normal;
                                    Vector3 normSafe = oldSphereCen - triangle.GetPoint(s, t);

                                    JiggleMath.NormalizeSafe(ref normSafe);

                                    Vector3 collisionN = (dist > float.Epsilon) ? normSafe : triangleN;
                                    // since impulse gets applied at the old position
                                    Vector3 pt = oldSphere.Center - oldSphere.Radius * collisionN;
                                    if (numCollPts < MaxLocalStackSCPI)
                                    {
                                        collPts[numCollPts++] = new SmallCollPointInfo(pt - body0Pos, pt - body1Pos, depth);
                                    }
                                    collNormal += collisionN;
                                }
                                else if (distToCentreNew < distToCentreOld)
                                {
                                    // old sphere is not intersecting - do a sweep, but only if the sphere is moving into the
                                    // triangle
                                    Vector3 pt, N; // CHECK THIS
                                    float depth;
                                    if (Intersection.SweptSphereTriangleIntersection(out pt, out N, out depth, oldSphere, newSphere, triangle,
                                        distToCentreOld, distToCentreNew, Intersection.EdgesToTest.EdgeAll, Intersection.CornersToTest.CornerAll))
                                    {
                                        // collision point etc must be relative to the old position because that's
                                        //where the impulses are applied
                                        float dist = (float)System.Math.Sqrt(d2);
                                        float depth2 = oldSphere.Radius - dist;
                                        Vector3 triangleN = triangle.Normal;
                                        Vector3 normSafe = oldSphereCen - triangle.GetPoint(s, t);
                                        JiggleMath.NormalizeSafe(ref normSafe);
                                        Vector3 collisionN = (dist > JiggleMath.Epsilon) ? normSafe : triangleN;
                                        // since impulse gets applied at the old position
                                        Vector3 pt2 = oldSphere.Center - oldSphere.Radius * collisionN;
                                        if (numCollPts < MaxLocalStackSCPI)
                                        {
                                            collPts[numCollPts++] = new SmallCollPointInfo(pt2 - body0Pos, pt2 - body1Pos, depth);
                                        }
                                        collNormal += collisionN;
                                    }
                                }
                            }
                            if (numCollPts > 0)
                            {
                                JiggleMath.NormalizeSafe(ref collNormal);
                                collisionFunctor.CollisionNotify(ref info, ref collNormal, collPts, numCollPts);
                            }
                        }
            #if USE_STACKALLOC
                    }
               }
            #else

                        FreeStackAlloc(potTriArray);
                    }
                    FreeStackAlloc(collPtArray);
                }
            #endif
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="infoOrig"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo infoOrig, float collTolerance, CollisionFunctor collisionFunctor)
        {
            // get the skins in the order that we're expectiing
            CollDetectInfo info = infoOrig;
            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            // todo - proper swept test
            Capsule oldCapsule = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Capsule;
            Capsule newCapsule = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Capsule;
            Segment oldSeg = new Segment(oldCapsule.Position, oldCapsule.Length * MatrixHelper.GetBackward(oldCapsule.Orientation));
            Segment newSeg = new Segment(newCapsule.Position, newCapsule.Length * MatrixHelper.GetBackward(newCapsule.Orientation));

            float radius = oldCapsule.Radius;

            Box oldBox = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as Box;
            Box newBox = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as Box;

            float oldSegT;
            float oldBoxT0, oldBoxT1, oldBoxT2;
            float oldDistSq = Distance.SegmentBoxDistanceSq(out oldSegT, out oldBoxT0, out oldBoxT1, out oldBoxT2,oldSeg, oldBox);
            float newSegT;
            float newBoxT0, newBoxT1, newBoxT2;
            float newDistSq = Distance.SegmentBoxDistanceSq(out newSegT, out newBoxT0, out newBoxT1, out newBoxT2,newSeg, newBox);

            if (MathHelper.Min(oldDistSq, newDistSq) < ((radius + collTolerance) * (radius + collTolerance)))
            {
                Matrix oldBoxOrientation = oldBox.Orientation;
                Vector3 segPos = oldSeg.GetPoint(oldSegT);
                Vector3 boxPos = oldBox.GetCentre() + oldBoxT0 * MatrixHelper.GetRight(ref oldBoxOrientation) +
                    oldBoxT1 * MatrixHelper.GetUp(ref oldBoxOrientation) + oldBoxT2 * MatrixHelper.GetBackward(ref oldBoxOrientation);

                float dist = (float)System.Math.Sqrt((float)oldDistSq);
                float depth = radius - dist;

                Vector3 dir;

                if (dist > JiggleMath.Epsilon)
                {
                    dir = segPos - boxPos;
                    JiggleMath.NormalizeSafe(ref dir);
                }
                else if ((segPos - oldBox.GetCentre()).LengthSquared() > JiggleMath.Epsilon)
                {
                    dir = segPos - oldBox.GetCentre();
                    JiggleMath.NormalizeSafe(ref dir);
                }
                else
                {
                    // todo - make this not random
                    dir = Vector3.TransformCoordinate(Vector3Helper.Backward, Matrix.RotationAxis(Vector3Helper.Up, MathHelper.ToRadians(random.Next(360))));
                }

                unsafe
                {
                    SmallCollPointInfo collInfo = new SmallCollPointInfo(boxPos - body0Pos, boxPos - body1Pos, depth);

                    collisionFunctor.CollisionNotify(ref info, ref dir, &collInfo, 1);
                }

            }
        }
        private static bool DoOverlapBoxTriangleTest(Box oldBox, Box newBox,
            ref IndexedTriangle triangle, TriangleMesh mesh,
            ref CollDetectInfo info, float collTolerance,
            CollisionFunctor collisionFunctor)
        {
            Matrix dirs0 = newBox.Orientation;

            #region REFERENCE: Triangle tri = new Triangle(mesh.GetVertex(triangle.GetVertexIndex(0)),mesh.GetVertex(triangle.GetVertexIndex(1)),mesh.GetVertex(triangle.GetVertexIndex(2)));
            Vector3 triVec0;
            Vector3 triVec1;
            Vector3 triVec2;
            mesh.GetVertex(triangle.GetVertexIndex(0), out triVec0);
            mesh.GetVertex(triangle.GetVertexIndex(1), out triVec1);
            mesh.GetVertex(triangle.GetVertexIndex(2), out triVec2);

            // Deano move tri into world space
            Matrix transformMatrix = mesh.TransformMatrix;
            Vector3.TransformCoordinate(ref triVec0, ref transformMatrix, out triVec0);
            Vector3.TransformCoordinate(ref triVec1, ref transformMatrix, out triVec1);
            Vector3.TransformCoordinate(ref triVec2, ref transformMatrix, out triVec2);

            Triangle tri = new Triangle(ref triVec0,ref triVec1,ref triVec2);
            #endregion

            #region REFERENCE Vector3 triEdge0 = (tri.GetPoint(1) - tri.GetPoint(0));
            Vector3 pt0;
            Vector3 pt1;
            tri.GetPoint(0, out pt0);
            tri.GetPoint(1, out pt1);

            Vector3 triEdge0;
            Vector3.Subtract(ref pt1, ref pt0, out triEdge0);
            #endregion

            #region REFERENCE Vector3 triEdge1 = (tri.GetPoint(2) - tri.GetPoint(1));
            Vector3 pt2;
            tri.GetPoint(2, out pt2);

            Vector3 triEdge1;
            Vector3.Subtract(ref pt2, ref pt1, out triEdge1);
            #endregion

            #region REFERENCE Vector3 triEdge2 = (tri.GetPoint(0) - tri.GetPoint(2));
            Vector3 triEdge2;
            Vector3.Subtract(ref pt0, ref pt2, out triEdge2);
            #endregion

            triEdge0.Normalize();
            triEdge1.Normalize();
            triEdge2.Normalize();

            Vector3 triNormal = triangle.Plane.Normal;

            // the 15 potential separating axes
            const int numAxes = 13;
            Vector3[] axes = new Vector3[numAxes];

            axes[0] = triNormal;
            MatrixHelper.GetRight(ref dirs0, out axes[1]);
            MatrixHelper.GetUp(ref dirs0, out axes[2]);
            MatrixHelper.GetBackward(ref dirs0, out axes[3]);

            Vector3.Cross(ref axes[1], ref triEdge0, out axes[4]);
            Vector3.Cross(ref axes[1], ref triEdge1, out axes[5]);
            Vector3.Cross(ref axes[1], ref triEdge2, out axes[6]);
            Vector3.Cross(ref axes[2], ref triEdge0, out axes[7]);
            Vector3.Cross(ref axes[2], ref triEdge1, out axes[8]);
            Vector3.Cross(ref axes[2], ref triEdge2, out axes[9]);
            Vector3.Cross(ref axes[3], ref triEdge0, out axes[10]);
            Vector3.Cross(ref axes[3], ref triEdge1, out axes[11]);
            Vector3.Cross(ref axes[3], ref triEdge2, out axes[12]);

            // the overlap depths along each axis
            float[] overlapDepths = new float[numAxes];

            // see if the boxes are separate along any axis, and if not keep a
            // record of the depths along each axis
            int i;
            for (i = 0; i < numAxes; ++i)
            {
                overlapDepths[i] = 1.0f;
                if (Disjoint(out overlapDepths[i], axes[i], newBox, tri, collTolerance))
                    return false;
            }

            // The box overlap, find the separation depth closest to 0.
            float minDepth = float.MaxValue;
            int minAxis = -1;

            for (i = 0; i < numAxes; ++i)
            {
                // If we can't normalise the axis, skip it
                float l2 = axes[i].LengthSquared();
                if (l2 < JiggleMath.Epsilon)
                    continue;

                // Normalise the separation axis and the depth
                float invl = 1.0f / (float)System.Math.Sqrt(l2);
                axes[i] *= invl;
                overlapDepths[i] *= invl;

                // If this axis is the minimum, select it
                if (overlapDepths[i] < minDepth)
                {
                    minDepth = overlapDepths[i];
                    minAxis = i;
                }
            }

            if (minAxis == -1)
                return false;

            // Make sure the axis is facing towards the 0th box.
            // if not, invert it
            Vector3 D = newBox.GetCentre() - tri.Centre;
            Vector3 N = axes[minAxis];
            float depth = overlapDepths[minAxis];

            if (Vector3.Dot(D, N) < 0.0f)
               N *= -1;

            Vector3 boxOldPos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 boxNewPos = (info.Skin0.Owner != null) ? info.Skin0.Owner.Position : Vector3.Zero;
            Vector3 meshPos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            List<Vector3> pts = new List<Vector3>();
            //pts.Clear();

            const float combinationDist = 0.05f;
            GetBoxTriangleIntersectionPoints(pts, newBox, tri, depth + combinationDist);

            // adjust the depth
            #region REFERENCE: Vector3 delta = boxNewPos - boxOldPos;
            Vector3 delta;
            Vector3.Subtract(ref boxNewPos, ref boxOldPos, out delta);
            #endregion

            #region REFERENCE: float oldDepth = depth + Vector3.Dot(delta, N);
            float oldDepth = Vector3.Dot(delta, N);
            oldDepth += depth;
            #endregion

            unsafe
            {
                // report collisions
                int numPts = pts.Count;
            #if USE_STACKALLOC
                SmallCollPointInfo* collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI];
            #else
                SmallCollPointInfo[] collPtArray = SCPIStackAlloc();
                fixed (SmallCollPointInfo* collPts = collPtArray)
            #endif
                {
                    if (numPts > 0)
                    {
                        if (numPts >= MaxLocalStackSCPI)
                        {
                            numPts = MaxLocalStackSCPI - 1;
                        }

                        // adjust positions
                        for (i = 0; i < numPts; ++i)
                        {
                            collPts[i] = new SmallCollPointInfo(pts[i] - boxNewPos, pts[i] - meshPos, oldDepth);
                        }

                        collisionFunctor.CollisionNotify(ref info, ref N, collPts, numPts);
            #if !USE_STACKALLOC
                        FreeStackAlloc(collPtArray);
            #endif
                        return true;
                    }
                    else
                    {
            #if !USE_STACKALLOC
                        FreeStackAlloc(collPtArray);
            #endif
                        return false;
                    }
                }

            }
        }
        /// <summary>
        /// Detect BoxBox Collisions.
        /// </summary>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param
        public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            Box box0 = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Box;
            Box box1 = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as Box;

            Box oldBox0 = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Box;
            Box oldBox1 = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as Box;

            Matrix dirs0 = box0.Orientation;
            Matrix dirs1 = box1.Orientation;

            //SlimDX:                                                   //XNA:
            MatrixHelper.GetRight(ref dirs0, out seperatingAxes[0]);       //seperatingAxes[0] = dirs0.Right;
            MatrixHelper.GetUp(ref dirs0, out seperatingAxes[1]);          //seperatingAxes[1] = dirs0.Up;
            MatrixHelper.GetBackward(ref dirs0, out seperatingAxes[2]);    //seperatingAxes[2] = dirs0.Backward;
            MatrixHelper.GetRight(ref dirs1, out seperatingAxes[3]);       //seperatingAxes[3] = dirs1.Right;
            MatrixHelper.GetUp(ref dirs1, out seperatingAxes[4]);          //seperatingAxes[4] = dirs1.Up;
            MatrixHelper.GetBackward(ref dirs1, out seperatingAxes[5]);    //seperatingAxes[5] = dirs1.Backward;

            Vector3.Cross(ref seperatingAxes[0], ref seperatingAxes[3], out seperatingAxes[6]);
            Vector3.Cross(ref seperatingAxes[0], ref seperatingAxes[4], out seperatingAxes[7]);
            Vector3.Cross(ref seperatingAxes[0], ref seperatingAxes[5], out seperatingAxes[8]);
            Vector3.Cross(ref seperatingAxes[1], ref seperatingAxes[3], out seperatingAxes[9]);
            Vector3.Cross(ref seperatingAxes[1], ref seperatingAxes[4], out seperatingAxes[10]);
            Vector3.Cross(ref seperatingAxes[1], ref seperatingAxes[5], out seperatingAxes[11]);
            Vector3.Cross(ref seperatingAxes[2], ref seperatingAxes[3], out seperatingAxes[12]);
            Vector3.Cross(ref seperatingAxes[2], ref seperatingAxes[4], out seperatingAxes[13]);
            Vector3.Cross(ref seperatingAxes[2], ref seperatingAxes[5], out seperatingAxes[14]);

            // see if the boxes are separate along any axis, and if not keep a
            // record of the depths along each axis
            int i;
            for (i = 0; i < 15; ++i)
            {
                // If we can't normalise the axis, skip it
                float l2 = seperatingAxes[i].LengthSquared();

                if (l2 < JiggleMath.Epsilon) continue;

                overlapDepth[i] = float.MaxValue;

                if (Disjoint(out overlapDepth[i], ref seperatingAxes[i], box0, box1, collTolerance))
                    return;
            }

            // The box overlap, find the seperation depth closest to 0.
            float minDepth = float.MaxValue;
            int minAxis = -1;

            for (i = 0; i < 15; ++i)
            {
                // If we can't normalise the axis, skip it
                float l2 = seperatingAxes[i].LengthSquared();
                if (l2 < JiggleMath.Epsilon) continue;

                // Normalise the separation axis and depth
                float invl = 1.0f / (float)System.Math.Sqrt(l2);
                seperatingAxes[i] *= invl;
                overlapDepth[i] *= invl;

                // If this axis is the minmum, select it
                if (overlapDepth[i] < minDepth)
                {
                    minDepth = overlapDepth[i];
                    minAxis = i;
                }
            }

            if (minAxis == -1)
                return;

            // Make sure the axis is facing towards the 0th box.
            // if not, invert it
            Vector3 D = box1.GetCentre() - box0.GetCentre();
            Vector3 N = seperatingAxes[minAxis];
            float depth = overlapDepth[minAxis];

            if (Vector3.Dot(D, N) > 0.0f)
                N *= -1.0f;

            float minA = MathHelper.Min(box0.SideLengths.X, MathHelper.Min(box0.SideLengths.Y, box0.SideLengths.Z));
            float minB = MathHelper.Min(box1.SideLengths.X, MathHelper.Min(box1.SideLengths.Y, box1.SideLengths.Z));

            float combinationDist = 0.05f * MathHelper.Min(minA, minB);

            // the contact points
            bool contactPointsFromOld = true;
            contactPts.Clear();

            if (depth > -JiggleMath.Epsilon)
                GetBoxBoxIntersectionPoints(contactPts, oldBox0, oldBox1, combinationDist, collTolerance);

            int numPts = contactPts.Count;
            if (numPts == 0)
            {
                contactPointsFromOld = false;
                GetBoxBoxIntersectionPoints(contactPts, box0, box1, combinationDist, collTolerance);
            }
            numPts = contactPts.Count;

            Vector3 body0OldPos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1OldPos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;
            Vector3 body0NewPos = (info.Skin0.Owner != null) ? info.Skin0.Owner.Position : Vector3.Zero;
            Vector3 body1NewPos = (info.Skin1.Owner != null) ? info.Skin1.Owner.Position : Vector3.Zero;

            #region REFERENCE: Vector3 bodyDelta = body0NewPos - body0OldPos - body1NewPos + body1OldPos;
            Vector3 bodyDelta;
            Vector3.Subtract(ref body0NewPos, ref body0OldPos, out bodyDelta);
            Vector3.Subtract(ref bodyDelta, ref body1NewPos, out bodyDelta);
            Vector3.Add(ref bodyDelta, ref body1OldPos, out bodyDelta);
            #endregion

            #region REFERENCE: float bodyDeltaLen = Vector3.Dot(bodyDelta,N);
            float bodyDeltaLen;
            bodyDeltaLen = Vector3.Dot(bodyDelta, N);
            #endregion

            float oldDepth = depth + bodyDeltaLen;

            unsafe
            {
            #if USE_STACKALLOC
                SmallCollPointInfo* collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI];
            #else
                SmallCollPointInfo[] collPtArray = SCPIStackAlloc();
                fixed (SmallCollPointInfo* collPts = collPtArray)
            #endif
                {
                    int numCollPts = 0;

                    Vector3 SATPoint;

                    switch (minAxis)
                    {
                        // Box0 face, Box1 corner collision
                        case 0:
                        case 1:
                        case 2:
                            {
                                // Get the lowest point on the box1 along box1 normal
                                GetSupportPoint(out SATPoint, box1, -N);
                                break;
                            }
                        // We have a Box2 corner/Box1 face collision
                        case 3:
                        case 4:
                        case 5:
                            {
                                // Find with vertex on the triangle collided
                                GetSupportPoint(out SATPoint, box0, N);
                                break;
                            }
                        // We have an edge/edge collision
                        case 6:
                        case 7:
                        case 8:
                        case 9:
                        case 10:
                        case 11:
                        case 12:
                        case 13:
                        case 14:
                            {
                                {
                                    // Retrieve which edges collided.
                                    i = minAxis - 6;
                                    int ia = i / 3;
                                    int ib = i - ia * 3;
                                    // find two P0, P1 point on both edges.
                                    Vector3 P0, P1;
                                    GetSupportPoint(out P0, box0, N);
                                    GetSupportPoint(out P1, box1, -N);
                                    // Find the edge intersection.
                                    // plane along N and F, and passing through PB
                                    Vector3 box0Orient, box1Orient;
                                    JiggleUnsafe.Get(ref box0.transform.Orientation, ia, out box0Orient);
                                    JiggleUnsafe.Get(ref box1.transform.Orientation, ib, out box1Orient);

                                    #region REFERENCE: Vector3 planeNormal = Vector3.Cross(N, box1Orient[ib]);
                                    Vector3 planeNormal;
                                    Vector3.Cross(ref N, ref box1Orient, out planeNormal);
                                    #endregion

                                    #region REFERENCE: float planeD = Vector3.Dot(planeNormal, P1);
                                    float planeD = Vector3.Dot(planeNormal, P1);
                                    #endregion

                                    // find the intersection t, where Pintersection = P0 + t*box edge dir
                                    #region REFERENCE: float div = Vector3.Dot(box0Orient, planeNormal);
                                    float div = Vector3.Dot(box0Orient, planeNormal);
                                    #endregion

                                    // plane and ray colinear, skip the intersection.
                                    if (System.Math.Abs(div) < JiggleMath.Epsilon)
                                        return;

                                    float t = (planeD - Vector3.Dot(P0, planeNormal)) / div;

                                    // point on edge of box0
                                    #region REFERENCE: P0 += box0Orient * t;
                                    P0 = Vector3.Add(Vector3.Multiply(box0Orient, t), P0);
                                    #endregion

                                    #region REFERENCE: SATPoint = (P0 + (0.5f * depth) * N);
                                    Vector3.Multiply(ref N, 0.5f * depth, out SATPoint);
                                    Vector3.Add(ref SATPoint, ref P0, out SATPoint);
                                    #endregion

                                }
                                break;
                            }
                        default:
                            throw new Exception("Impossible switch");

                    }

                    // distribute the depth according to the distance to the SAT point
                    if (numPts > 0)
                    {
                        float minDist = float.MaxValue;
                        float maxDist = float.MinValue;
                        for (i = 0; i < numPts; ++i)
                        {
                            float dist = Distance.PointPointDistance(contactPts[i].Pos, SATPoint);
                            if (dist < minDist)
                                minDist = dist;
                            if (dist > maxDist)
                                maxDist = dist;
                        }

                        if (maxDist < minDist + JiggleMath.Epsilon)
                            maxDist = minDist + JiggleMath.Epsilon;

                        // got some intersection points
                        for (i = 0; i < numPts; ++i)
                        {
                            float minDepthScale = 0.0f;
                            float dist = Distance.PointPointDistance(contactPts[i].Pos, SATPoint);

                            float depthDiv = System.Math.Max(JiggleMath.Epsilon, maxDist - minDist);
                            float depthScale = (dist - minDist) / depthDiv;

                            depth = (1.0f - depthScale) * oldDepth + minDepthScale * depthScale * oldDepth;

                            if (contactPointsFromOld)
                            {
                                if (numCollPts < MaxLocalStackSCPI)
                                {
                                    collPts[numCollPts++] = new SmallCollPointInfo(contactPts[i].Pos - body0OldPos, contactPts[i].Pos - body1OldPos, depth);
                                }
                            }
                            else
                            {
                                if (numCollPts < MaxLocalStackSCPI)
                                {
                                    collPts[numCollPts++] = new SmallCollPointInfo(contactPts[i].Pos - body0NewPos, contactPts[i].Pos - body1NewPos, depth);
                                }
                            }

                        }
                    }
                    else
                    {
                        #region REFERENCE: collPts.Add(new CollPointInfo(SATPoint - body0NewPos, SATPoint - body1NewPos, oldDepth));
                        //collPts.Add(new CollPointInfo(SATPoint - body0NewPos, SATPoint - body1NewPos, oldDepth));
                        Vector3 cp0;
                        Vector3.Subtract(ref SATPoint, ref body0NewPos, out cp0);

                        Vector3 cp1;
                        Vector3.Subtract(ref SATPoint, ref body1NewPos, out cp1);

                        if (numCollPts < MaxLocalStackSCPI)
                        {
                            collPts[numCollPts++] = new SmallCollPointInfo(ref cp0, ref cp1, oldDepth);
                        }
                        #endregion
                    }

                    // report Collisions
                    collisionFunctor.CollisionNotify(ref info, ref N, collPts, numCollPts);
                }
            #if !USE_STACKALLOC
                FreeStackAlloc(collPtArray);
            #endif
            }
        }
        /// <summary>
        /// Detect BoxHeightmap Collisions.
        /// </summary>
        /// <param name="infoOrig"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo infoOrig, float collTolerance, CollisionFunctor collisionFunctor)
        {
            CollDetectInfo info = infoOrig;
            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            // todo - proper swept test
            Box oldBox = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Box;
            Box newBox = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Box;

            Heightmap oldHeightmap = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as Heightmap;
            Heightmap newHeightmap = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as Heightmap;

            Vector3[] oldPts, newPts;
            oldBox.GetCornerPoints(out oldPts);
            newBox.GetCornerPoints(out newPts);

            unsafe
            {
            #if USE_STACKALLOC
                SmallCollPointInfo* collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI];
            #else
                SmallCollPointInfo[] collPtArray = SCPIStackAlloc();
                fixed (SmallCollPointInfo* collPts = collPtArray)
            #endif
                {
                    int numCollPts = 0;

                    Vector3 collNormal = Vector3.Zero;

                    for (int i = 0; i < 8; ++i)
                    {
                        Vector3 newPt = newPts[i];
                        float newDist;
                        Vector3 normal;
                        newHeightmap.GetHeightAndNormal(out newDist, out normal, newPt);

                        if (newDist < collTolerance)
                        {
                            Vector3 oldPt = oldPts[i];
                            float oldDist = oldHeightmap.GetHeight(oldPt);

                            #region REFERENCE: collPts.Add(new CollPointInfo(oldPt - body0Pos, oldPt - body1Pos, -oldDist));
                            Vector3 pt0;
                            Vector3 pt1;
                            Vector3.Subtract(ref oldPt, ref body0Pos, out pt0);
                            Vector3.Subtract(ref oldPt, ref body1Pos, out pt1);
                            if (numCollPts < MaxLocalStackSCPI)
                            {
                                collPts[numCollPts++] = new SmallCollPointInfo(ref pt0, ref pt1, -oldDist);
                            }
                            #endregion

                            #region REFERENCE: collNormal += normal;
                            Vector3.Add(ref collNormal, ref normal, out collNormal);
                            #endregion
                        }
                    }

                    if (numCollPts > 0)
                    {
                        JiggleMath.NormalizeSafe(ref collNormal);
                        collisionFunctor.CollisionNotify(ref info, ref collNormal, collPts, numCollPts);
                    }
                }
            #if !USE_STACKALLOC
                FreeStackAlloc(collPtArray);
            #endif
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="infoOrig"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        #region public override void CollDetect(CollDetectInfo infoOrig, float collTolerance, CollisionFunctor collisionFunctor)
        public override void CollDetect(CollDetectInfo infoOrig, float collTolerance, CollisionFunctor collisionFunctor)
        {
           // get the skins in the order that we're expecting
            CollDetectInfo info = infoOrig;

            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            // todo - proper sweep test
            Sphere oldSphere = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Sphere;
            Sphere newSphere = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Sphere;

            Box oldBox = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as Box;
            Box newBox = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as Box;

            Vector3 oldBoxPoint;
            Vector3 newBoxPoint;

            float oldDist = oldBox.GetDistanceToPoint(out oldBoxPoint, oldSphere.Position);
            float newDist = newBox.GetDistanceToPoint(out newBoxPoint, newSphere.Position);

            // normally point will be outside
            float oldDepth = oldSphere.Radius - oldDist;
            float newDepth = newSphere.Radius - newDist;

            if (System.Math.Max(oldDepth, newDepth) > -collTolerance)
            {
                Vector3 dir;
                if (oldDist < -JiggleMath.Epsilon)
                {
                    dir = oldBoxPoint - oldSphere.Position - oldBoxPoint;
                    JiggleMath.NormalizeSafe(ref dir);
                }
                else if (oldDist > JiggleMath.Epsilon)
                {
                    dir = oldSphere.Position - oldBoxPoint;
                    JiggleMath.NormalizeSafe(ref dir);
                }
                else
                {
                    dir = oldSphere.Position - oldBox.GetCentre();
                    JiggleMath.NormalizeSafe(ref dir);
                }

                unsafe
                {
                    SmallCollPointInfo collInfo = new SmallCollPointInfo(oldBoxPoint - body0Pos,
                        oldBoxPoint - body1Pos, oldDepth);

                    
                    collisionFunctor.CollisionNotify(ref info, ref dir, &collInfo, 1);
                }

            }
        #endregion

        }
        /// <summary>
        /// Detect BoxPlane Collisions.
        /// </summary>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            Box oldBox = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Box;
            Box newBox = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Box;

            JPlane oldPlane = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as JPlane;
            JPlane newPlane = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as JPlane;

            Matrix newPlaneInvTransform = newPlane.InverseTransformMatrix;
            Vector3 newBoxCen = Vector3.TransformCoordinate(newBox.GetCentre(), newPlaneInvTransform);

            // quick check
            float centreDist = Distance.PointPlaneDistance(newBoxCen, newPlane);
            if (centreDist > collTolerance + newBox.GetBoundingRadiusAroundCentre())
                return;

            Matrix oldPlaneInvTransform = oldPlane.InverseTransformMatrix;

            Vector3[] newPts;
            newBox.GetCornerPoints(out newPts);
            Vector3[] oldPts;
            oldBox.GetCornerPoints(out oldPts);

            unsafe
            {
            #if USE_STACKALLOC
                SmallCollPointInfo* collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI];
            #else
                SmallCollPointInfo[] collPtArray = SCPIStackAlloc();
                fixed (SmallCollPointInfo* collPts = collPtArray)
            #endif
                {
                    int numCollPts = 0;

                    for (int i = 0; i < 8; ++i)
                    {
                        Vector3.TransformCoordinate(ref oldPts[i], ref oldPlaneInvTransform, out oldTransPts[i]);
                        Vector3.TransformCoordinate(ref newPts[i], ref newPlaneInvTransform, out newPts[i]);

                        float oldDepth = -Distance.PointPlaneDistance(ref oldTransPts[i], oldPlane);
                        float newDepth = -Distance.PointPlaneDistance(ref newPts[i], newPlane);

                        if (MathHelper.Max(oldDepth, newDepth) > -collTolerance)
                        {
                            if (numCollPts < MaxLocalStackSCPI)
                            {
                                collPts[numCollPts++] = new SmallCollPointInfo(oldPts[i] - body0Pos, oldPts[i] - body1Pos, oldDepth);
                            }
                        }
                    }

                    if (numCollPts > 0)
                    {
                        collisionFunctor.CollisionNotify(ref info, ref oldPlane.normal, collPts, numCollPts);
                    }
                }
            #if !USE_STACKALLOC
                FreeStackAlloc(collPtArray);
            #endif
            }
        }