// clip polygon with plane and generate new polygon points
static void _cldClipPolyToPlane( dVector3 avArrayIn[], int ctIn, 
                      dVector3 avArrayOut[], int &ctOut, 
                      const dVector4 &plPlane )
{
  // start with no output points
  ctOut = 0;

  int i0 = ctIn-1;

  // for each edge in input polygon
  for (int i1=0; i1<ctIn; i0=i1, i1++) {
  

    // calculate distance of edge points to plane
    dReal fDistance0 = POINTDISTANCE( plPlane ,avArrayIn[i0] );
    dReal fDistance1 = POINTDISTANCE( plPlane ,avArrayIn[i1] );


    // if first point is in front of plane
    if( fDistance0 >= 0 ) {
      // emit point
      avArrayOut[ctOut][0] = avArrayIn[i0][0];
      avArrayOut[ctOut][1] = avArrayIn[i0][1];
      avArrayOut[ctOut][2] = avArrayIn[i0][2];
      ctOut++;
    }

    // if points are on different sides
    if( (fDistance0 > 0 && fDistance1 < 0) || ( fDistance0 < 0 && fDistance1 > 0) ) {

      // find intersection point of edge and plane
      dVector3 vIntersectionPoint;
      vIntersectionPoint[0]= avArrayIn[i0][0] - (avArrayIn[i0][0]-avArrayIn[i1][0])*fDistance0/(fDistance0-fDistance1);
      vIntersectionPoint[1]= avArrayIn[i0][1] - (avArrayIn[i0][1]-avArrayIn[i1][1])*fDistance0/(fDistance0-fDistance1);
      vIntersectionPoint[2]= avArrayIn[i0][2] - (avArrayIn[i0][2]-avArrayIn[i1][2])*fDistance0/(fDistance0-fDistance1);

      // emit intersection point
      avArrayOut[ctOut][0] = vIntersectionPoint[0];
      avArrayOut[ctOut][1] = vIntersectionPoint[1];
      avArrayOut[ctOut][2] = vIntersectionPoint[2];
      ctOut++;
    }
  }

}
BOOL sTrimeshCapsuleColliderData::_cldClipEdgeToPlane( 
	dVector3 &vEpnt0, dVector3 &vEpnt1, const dVector4& plPlane)
{
	// calculate distance of edge points to plane
	dReal fDistance0 = POINTDISTANCE( plPlane, vEpnt0 );
	dReal fDistance1 = POINTDISTANCE( plPlane, vEpnt1 );

	// if both points are behind the plane
	if ( fDistance0 < 0 && fDistance1 < 0 ) 
	{
		// do nothing
		return FALSE;
		// if both points in front of the plane
	} else if ( fDistance0 > 0 && fDistance1 > 0 ) 
	{
		// accept them
		return TRUE;
		// if we have edge/plane intersection
	} else if ((fDistance0 > 0 && fDistance1 < 0) || ( fDistance0 < 0 && fDistance1 > 0)) 
	{
			// find intersection point of edge and plane
			dVector3 vIntersectionPoint;
			vIntersectionPoint[0]= vEpnt0[0]-(vEpnt0[0]-vEpnt1[0])*fDistance0/(fDistance0-fDistance1);
			vIntersectionPoint[1]= vEpnt0[1]-(vEpnt0[1]-vEpnt1[1])*fDistance0/(fDistance0-fDistance1);
			vIntersectionPoint[2]= vEpnt0[2]-(vEpnt0[2]-vEpnt1[2])*fDistance0/(fDistance0-fDistance1);

			// clamp correct edge to intersection point
			if ( fDistance0 < 0 ) 
			{
				SET(vEpnt0,vIntersectionPoint);
			} else 
			{
				SET(vEpnt1,vIntersectionPoint);
			}
			return TRUE;
		}
		return TRUE;
}
// test one mesh triangle on intersection with capsule
void sTrimeshCapsuleColliderData::_cldTestOneTriangleVSCapsule(
    const dVector3 &v0, const dVector3 &v1, const dVector3 &v2,
    uint8 flags)
{
    // calculate edges
    SUBTRACT(v1,v0,m_vE0);
    SUBTRACT(v2,v1,m_vE1);
    SUBTRACT(v0,v2,m_vE2);

    dVector3	_minus_vE0;
    SUBTRACT(v0,v1,_minus_vE0);

    // calculate poly normal
    dCalcVectorCross3(m_vN,m_vE1,_minus_vE0);

    // Even though all triangles might be initially valid, 
    // a triangle may degenerate into a segment after applying 
    // space transformation.
    if (!dSafeNormalize3(m_vN))
    {
        return;
    }

    // create plane from triangle
    dReal plDistance = -dCalcVectorDot3(v0,m_vN);
    dVector4 plTrianglePlane;
    CONSTRUCTPLANE(plTrianglePlane,m_vN,plDistance);

    // calculate capsule distance to plane
    dReal fDistanceCapsuleCenterToPlane = POINTDISTANCE(plTrianglePlane,m_vCapsulePosition);

    // Capsule must be over positive side of triangle
    if (fDistanceCapsuleCenterToPlane < 0 /* && !bDoubleSided*/) 
    {
        // if not don't generate contacts
        return;
    }

    dVector3 vPnt0;
    SET	(vPnt0,v0);
    dVector3 vPnt1;
    SET	(vPnt1,v1);
    dVector3 vPnt2;
    SET	(vPnt2,v2);

    if (fDistanceCapsuleCenterToPlane < 0 )
    {
        SET	(vPnt0,v0);
        SET	(vPnt1,v2);
        SET	(vPnt2,v1);
    }

    // do intersection test and find best separating axis
    if (!_cldTestSeparatingAxesOfCapsule(vPnt0, vPnt1, vPnt2, flags))
    {
        // if not found do nothing
        return;
    }

    // if best separation axis is not found
    if (m_iBestAxis == 0 ) 
    {
        // this should not happen (we should already exit in that case)
        dIASSERT(FALSE);
        // do nothing
        return;
    }

    // calculate caps centers in absolute space
    dVector3 vCposTrans;
    vCposTrans[0] = m_vCapsulePosition[0] + m_vNormal[0]*m_vCapsuleRadius;
    vCposTrans[1] = m_vCapsulePosition[1] + m_vNormal[1]*m_vCapsuleRadius;
    vCposTrans[2] = m_vCapsulePosition[2] + m_vNormal[2]*m_vCapsuleRadius;

    dVector3 vCEdgePoint0;
    vCEdgePoint0[0]  = vCposTrans[0] + m_vCapsuleAxis[0]*(m_fCapsuleSize*REAL(0.5)-m_vCapsuleRadius);
    vCEdgePoint0[1]  = vCposTrans[1] + m_vCapsuleAxis[1]*(m_fCapsuleSize*REAL(0.5)-m_vCapsuleRadius);
    vCEdgePoint0[2]  = vCposTrans[2] + m_vCapsuleAxis[2]*(m_fCapsuleSize*REAL(0.5)-m_vCapsuleRadius);

    dVector3 vCEdgePoint1;
    vCEdgePoint1[0] = vCposTrans[0] - m_vCapsuleAxis[0]*(m_fCapsuleSize*REAL(0.5)-m_vCapsuleRadius);
    vCEdgePoint1[1] = vCposTrans[1] - m_vCapsuleAxis[1]*(m_fCapsuleSize*REAL(0.5)-m_vCapsuleRadius);
    vCEdgePoint1[2] = vCposTrans[2] - m_vCapsuleAxis[2]*(m_fCapsuleSize*REAL(0.5)-m_vCapsuleRadius);

    // transform capsule edge points into triangle space
    vCEdgePoint0[0] -= vPnt0[0];
    vCEdgePoint0[1] -= vPnt0[1];
    vCEdgePoint0[2] -= vPnt0[2];

    vCEdgePoint1[0] -= vPnt0[0];
    vCEdgePoint1[1] -= vPnt0[1];
    vCEdgePoint1[2] -= vPnt0[2];

    dVector4 plPlane;
    dVector3 _minus_vN;
    _minus_vN[0] = -m_vN[0];
    _minus_vN[1] = -m_vN[1];
    _minus_vN[2] = -m_vN[2];
    // triangle plane
    CONSTRUCTPLANE(plPlane,_minus_vN,0);
    //plPlane = Plane4f( -m_vN, 0);

    if (!_cldClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) 
    { 
        return; 
    }

    // plane with edge 0
    dVector3 vTemp;
    dCalcVectorCross3(vTemp,m_vN,m_vE0);
    CONSTRUCTPLANE(plPlane, vTemp, REAL(1e-5));
    if (!_cldClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane ))
    { 
        return; 
    }

    dCalcVectorCross3(vTemp,m_vN,m_vE1);
    CONSTRUCTPLANE(plPlane, vTemp, -(dCalcVectorDot3(m_vE0,vTemp)-REAL(1e-5)));
    if (!_cldClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) 
    { 
        return; 
    }

    dCalcVectorCross3(vTemp,m_vN,m_vE2);
    CONSTRUCTPLANE(plPlane, vTemp, REAL(1e-5));
    if (!_cldClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) { 
        return; 
    }

    // return capsule edge points into absolute space
    vCEdgePoint0[0] += vPnt0[0];
    vCEdgePoint0[1] += vPnt0[1];
    vCEdgePoint0[2] += vPnt0[2];

    vCEdgePoint1[0] += vPnt0[0];
    vCEdgePoint1[1] += vPnt0[1];
    vCEdgePoint1[2] += vPnt0[2];

    // calculate depths for both contact points
    SUBTRACT(vCEdgePoint0,m_vCapsulePosition,vTemp);
    dReal fDepth0 = dCalcVectorDot3(vTemp,m_vNormal) - (m_fBestCenter-m_fBestrt);
    SUBTRACT(vCEdgePoint1,m_vCapsulePosition,vTemp);
    dReal fDepth1 = dCalcVectorDot3(vTemp,m_vNormal) - (m_fBestCenter-m_fBestrt);

    // clamp depths to zero
    if (fDepth0 < 0) 
    {
        fDepth0 = 0.0f;
    }

    if (fDepth1 < 0 ) 
    {
        fDepth1 = 0.0f;
    }

    // Cached contacts's data
    // contact 0
    dIASSERT(m_ctContacts < (m_iFlags & NUMC_MASK)); // Do not call function if there is no room to store result
    m_gLocalContacts[m_ctContacts].fDepth = fDepth0;
    SET(m_gLocalContacts[m_ctContacts].vNormal,m_vNormal);
    SET(m_gLocalContacts[m_ctContacts].vPos,vCEdgePoint0);
    m_gLocalContacts[m_ctContacts].nFlags = 1;
    m_ctContacts++;

    if (m_ctContacts < (m_iFlags & NUMC_MASK)) {
        // contact 1
        m_gLocalContacts[m_ctContacts].fDepth = fDepth1;
        SET(m_gLocalContacts[m_ctContacts].vNormal,m_vNormal);
        SET(m_gLocalContacts[m_ctContacts].vPos,vCEdgePoint1);
        m_gLocalContacts[m_ctContacts].nFlags = 1;
        m_ctContacts++;
    }
}