Home

Resume

Blog

Teikitu


/* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
/*  »Project«   Teikitu Gaming System (TgS) (∂)
    »File«      TgS Collision - F - Box-Triangle.c_inc
    »Keywords«  Collision;Distance;Closest;Intersect;Penetrate;Sweep;Box;Triangle;
    »Author«    Andrew Aye (EMail: mailto:andrew.aye@gmail.com, Web: http://www.andrewaye.com)
    »Version«   4.51 / »GUID« A9981407-3EC9-42AF-8B6F-8BE6DD919615                                                                                                        */
    /*   -------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
/*  Copyright: © 2002-2017, Andrew Aye.  All Rights Reserved.
    This software is free for non-commercial use.  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
      following conditions are met:
        Redistribution of source code must retain this copyright notice, this list of conditions and the following disclaimers.
        Redistribution in binary form must reproduce this copyright notice, this list of conditions and the following disclaimers in the documentation and other materials
          provided with the distribution.
    The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
    The intellectual property rights of the algorithms used reside with Andrew Aye.
    You may not use this software, in whole or in part, in support of any commercial product without the express written consent of the author.
    There is no warranty or other guarantee of fitness of this software for any purpose. It is provided solely "as is".                                                   */
/* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
/* == Collision ========================================================================================================================================================= */

/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  File Local Functions                                                                                                                                                  */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

static TgBOOL                               V(tgCO_F_ST_Penetrate_Axis_Seperation_BX)( V(PC_STg2_CO_Axis_Result), V(CPC_TgSTRI), V(CPC_TgBOX) );
static TgRESULT                             V(tgCO_F_ST_Sweep_Axis_Seperation_BX)( V(PC_STg2_CO_Axis_Info), const TYPE, V(CPC_TgSTRI), V(CPC_TgBOX), V(CPC_TgDELTA) );




/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  Public Functions                                                                                                                                                      */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

/* ---- V(tgCO_F_ST_Penetrate_BX) --------------------------------------------------------------------------------------------------------------------------------------- */
/* Input:  tgPacket: The current series of contact points for this query-series, and contact generation parameters.                                                       */
/* Input:  psST0: Space Triangle primitive                                                                                                                                */
/* Input:  psBX0: Box primitive - contact points are generated on this primitive                                                                                          */
/* Output: tgPacket: Points of penetration between the two primitives are added to it                                                                                     */
/* Return: Result Code                                                                                                                                                    */
/* Let α represent the simulation frequency, β the maximum velocity in the system.                                                                                        */
/*  Thus, β/α is the displacement vector used as the function parameter.                                                                                                  */
/* Let Φ represent the minimal distance between the triangle centre and the nearest edge.                                                                                 */
/* For the system to retain coherency/validity then β/α < Φ - feature reduction may help to reduce this issue.                                                            */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT V(tgCO_F_ST_Penetrate_BX)(V(PC_STg2_CO_Packet) psPacket, V(CPC_TgSTRI) psST0, V(CPC_TgBOX) psBX0)
{
    C_TgSINT32                          niContact = psPacket->m_niContact;
    V(P_STg2_CO_Contact)                psContact;
    V(STg2_CO_Axis_Result)              sAxS;
    V(C_TgVEC)                          vDS = V(F_SUB)(&psBX0->m.m.vOrigin, psST0->m_sCT.m_sET.m_sPT.m_avPoint);
    TgRESULT                            iResult;
    TYPE                                fAX_NM;

    TgPARAM_CHECK( V(tgGM_ST_Is_Valid)(psST0) && V(tgGM_BX_Is_Valid)(psBX0) );

    if (0 == psPacket->m_niMaxContact || psPacket->m_niContact >= psPacket->m_niMaxContact || nullptr == psPacket->m_psContact)
    {
        return (KTgE_FAIL);
    };

    /*  Quick out logic - for the contact generation routines to be accurate then the box origin is assumed to be outside of the infinite negative projection of the */
    /* triangle space.  (ie. that it is on the positive half-space of the plane defined by the triangle. */

    if (V(F_DOT)(&psST0->m_sCT.m_sET.m_sPT.m_vNormal, &vDS) < MKL(0.0))
    {
        return (KTgE_NO_INTERSECT);
    };

    /* Find the minimal axis of separation, or return if the primitives are not in contact. */

    if (!V(tgCO_F_ST_Penetrate_Axis_Seperation_BX)(&sAxS, psST0, psBX0))
    {
        return (KTgE_NO_INTERSECT);
    };

    TgERROR( F(tgCM_NR1)(V(F_LSQ)(&sAxS.m_vNormal)) && sAxS.m_fDepth >= MKL(0.0) );

    /* == Contact Generation == */

    if (sAxS.m_iAxis == 1 || sAxS.m_iAxis >= 21)
    {
        /* -- Triangle Normal or Edge Plane Intersection -- */
        /*  The minimal separation axis is triangle normal or one of the edge planes. */

        C_TgSINT32                          iIdx = sAxS.m_iAxis == 1 ? 0 : sAxS.m_iAxis - 21;

        /*  Analyze the valid triangle vertices to see if they are contact points - this is done since contained points are not found by the following algorithm */
        /* (box edge clipping). */

        V(C_TgVEC)                          vK0 = V(F_NEG)(&(psST0->m_avPlane[iIdx].m_vNormal));
        V(C_TgVEC)                          vNormal = sAxS.m_iAxis == 1 ? psST0->m_sCT.m_sET.m_sPT.m_vNormal : vK0;

        TgSINT32                            iVert, iFlag, iAxis;

        for (iVert = 0; iVert < 3; ++iVert)
        {
            V(C_TgVEC)                          vVert = psST0->m_sCT.m_sET.m_sPT.m_avPoint[iVert];
            TYPE                                fT0, fT1, fT;
            V(TgVEC)                            vK1, vK2;

            if (!V(tgGM_ST_Test_Point)(psST0, iVert)) /* Skip reduced features/vertices. */
            {
                continue;
            };

            if (!V(tgGM_BX_Is_Contained)(psBX0, &vVert)) /* Skip exterior points - edge crossings are handled differently. */
            {
                continue;
            };

            if (psPacket->m_niContact >= psPacket->m_niMaxContact)
            {
                return (KTgE_MAX_CONTACTS);
            };

            psContact = psPacket->m_psContact + psPacket->m_niContact;

            /* Find the point on the box along the negative normal direction. */
            vK1 = V(F_NEG)(&vNormal);
            iResult = V(tgCO_FI_BX_Clip_Param_LR10)(&fT0, &fT1, psBX0, &vVert, &vK1);
            TgERROR( F(tgPM_ABS)(fT0) <= F(KTgEPS) );

            fT = (TgFAILED( iResult ) || fT1 < MKL(0.0)) ? MKL(0.0) : fT1;

            vK2 = V(F_MUL_SV)(fT, &vNormal);
            psContact->m_vS0 = V(F_SUB)(&vVert, &vK2);
            psContact->m_vN0 = vNormal;
            psContact->m_fT0 = MKL(0.0);
            psContact->m_fDepth = fT;

            ++psPacket->m_niContact;
            /*TgDEBUG_COLLISION_TRIANGLE( iDBG_TriID, ETgFEBUG_COLLISION_COLLIDED ); */
        };

        /*  F_Clip the edges of the box against the triangle space. */

        for (iFlag = 0; iFlag < 8; ++iFlag)
        {
            const TYPE                          fE0 = 0 != (iFlag & 1) ? psBX0->m_vExtent.m.x : -psBX0->m_vExtent.m.x;
            const TYPE                          fE1 = 0 != (iFlag & 2) ? psBX0->m_vExtent.m.y : -psBX0->m_vExtent.m.y;
            const TYPE                          fE2 = 0 != (iFlag & 4) ? psBX0->m_vExtent.m.z : -psBX0->m_vExtent.m.z;
            V(C_TgVEC)                          vCS = V(tgGM_BX_Calc_Point)(psBX0, fE0, fE1, fE2);
            V(C_TgVEC)                          vK3 = V(F_SUB)(&vCS, psST0->m_sCT.m_sET.m_sPT.m_avPoint);
            const TYPE                          fDistN = V(F_DOT)(&vK3, &psST0->m_sCT.m_sET.m_sPT.m_vNormal);
            TYPE                                fDist[3];

            if (fDistN >= MKL(0.0))
            {
                /* The point/vertex is above the triangle plane - ignore and continue processing. */

                continue;
            };

            fDist[0] = V(tgCO_F_PN_Dist_VT)(psST0->m_avPlane + 0, &vCS);
            fDist[1] = V(tgCO_F_PN_Dist_VT)(psST0->m_avPlane + 1, &vCS);
            fDist[2] = V(tgCO_F_PN_Dist_VT)(psST0->m_avPlane + 2, &vCS);

            if (fDist[0] >= -F(KTgEPS) && fDist[1] >= -F(KTgEPS) && fDist[2] >= -F(KTgEPS))
            {
                /* The vertex is contained inside the negative triangle space - add it as a contact and test next vertex. */

                if (psPacket->m_niContact >= psPacket->m_niMaxContact)
                {
                    return (KTgE_MAX_CONTACTS);
                };

                psContact = psPacket->m_psContact + psPacket->m_niContact;

                psContact->m_vS0 = vCS;
                psContact->m_fT0 = MKL(0.0);

                if (sAxS.m_iAxis >= 21)
                {
                    TYPE                                fT0, fT1;
                    TgSINT32                            iCode = 0;

                    iResult = V(tgCO_FI_ST_Clip_Param_F_LR10)(&fT0, &fT1, &iCode, psST0, &vCS, &vNormal);
                    TgERROR( F(tgPM_ABS)(fT0) <= F(KTgEPS) );

                    psContact->m_fDepth = (TgFAILED( iResult ) || 3 != (iCode & 3) || fT1 < MKL(0.0)) ? MKL(0.0) : fT1;
                }
                else
                {
                    psContact->m_fDepth = -fDistN;
                };

                psContact->m_vN0 = vNormal;
                ++psPacket->m_niContact;
                /*TgDEBUG_COLLISION_TRIANGLE( iDBG_TriID, ETgFEBUG_COLLISION_COLLIDED ); */

                continue;
            };

            /*  The vertex is under the triangle plane but not inside the triangle itself.  Attempt to create contact points where the triangle would clip the box edges. */

            for (iAxis = 0; iAxis < 3; ++iAxis)
            {
                V(C_TgVEC)                          vK6 = psST0->m_avPlane[0].m_vNormal;
                V(C_TgVEC)                          vK1 = psST0->m_avPlane[1].m_vNormal;
                V(C_TgVEC)                          vK2 = psST0->m_avPlane[2].m_vNormal;

                const TYPE                          fBX_EN0 = V(F_DOT)(&vK6, psBX0->m.m.avAxis + iAxis);
                const TYPE                          fBX_EN1 = V(F_DOT)(&vK1, psBX0->m.m.avAxis + iAxis);
                const TYPE                          fBX_EN2 = V(F_DOT)(&vK2, psBX0->m.m.avAxis + iAxis);

                TYPE                                fBX_EN[3];
                V(TgVEC)                            vS2;
                TgSINT32                            iEdge;

                fBX_EN[0] = 0 == (iFlag & (1 << iAxis)) ? fBX_EN0 : -fBX_EN0;
                fBX_EN[1] = 0 == (iFlag & (1 << iAxis)) ? fBX_EN1 : -fBX_EN1;
                fBX_EN[2] = 0 == (iFlag & (1 << iAxis)) ? fBX_EN2 : -fBX_EN2;

                for (iEdge = 0; iEdge < 3; ++iEdge)
                {
                    const TYPE                          fInt = -fDist[iEdge] / fBX_EN[iEdge];
                    const TYPE                          fK0 = 0 == (iFlag & (1 << iAxis)) ? fInt : -fInt;
                    V(C_TgVEC)                          vK5 = V(F_MUL_VS)(psBX0->m.m.avAxis + iAxis, fK0);
                    V(C_TgVEC)                          vK4 = V(F_ADD)(&vCS, &vK5);
                    V(C_TgVEC)                          vK7 = V(F_SUB)(&vS2, psST0->m_sCT.m_sET.m_sPT.m_avPoint);
                    TYPE                                fDepth = -V(F_DOT)(&vK7, &psST0->m_sCT.m_sET.m_sPT.m_vNormal);

                    if (TgTRUE != V(tgGM_ST_Test_Edge)(psST0, iEdge) || (TgTRUE == F(tgCM_NR0)(F(tgPM_ABS)(fBX_EN[iEdge]))))
                    {
                        /* Ignore edge planes where the axis is near-parallel, or has been marked as non-valid. */
                        continue;
                    };

                    if (fInt < MKL(0.0) || fInt > MKL(2.0)*psBX0->m_vExtent.m_aData[iAxis])
                    {
                        /* The resulting clipping point is outside of legal space. */
                        continue;
                    };

                    /* If the resulting point is not contained inside of the negative triangle space - ignore it. */

                    if (fDepth < -F(KTgEPS))
                    {
                        continue;
                    };

                    vS2 = vK4;

                    if (
                        (V(tgCO_F_PN_Dist_VT)(psST0->m_avPlane + ((iEdge + 1) % 3), &vS2)) < -F(KTgEPS) ||
                        (V(tgCO_F_PN_Dist_VT)(psST0->m_avPlane + ((iEdge + 2) % 3), &vS2)) < -F(KTgEPS)
                    )
                    {
                        continue;
                    };

                    if (psPacket->m_niContact >= psPacket->m_niMaxContact)
                    {
                        return (KTgE_MAX_CONTACTS);
                    };

                    psContact = psPacket->m_psContact + psPacket->m_niContact;

                    psContact->m_vS0 = vS2;
                    psContact->m_vN0 = vNormal;
                    psContact->m_fT0 = MKL(0.0);

                    if (iIdx >= 0)
                    {
                        if (iIdx != iEdge)
                        {
                            TYPE                                fT0, fT1;
                            TgSINT32                            iCode = 0;

                            iResult = V(tgCO_FI_ST_Clip_Param_F_LR10)(&fT0, &fT1, &iCode, psST0, &vS2, &vNormal);
                            TgERROR( F(tgPM_ABS)(fT0) <= F(KTgEPS) );

                            psContact->m_fDepth = (TgFAILED( iResult ) || 3 != (iCode & 3) || fT1 < MKL(0.0)) ? MKL(0.0) : fT1;
                        }
                        else
                        {
                            psContact->m_fDepth = MKL(0.0);
                        };
                    }
                    else
                    {
                        psContact->m_fDepth = fDepth < MKL(0.0) ? MKL(0.0) : fDepth;
                    };

                    ++psPacket->m_niContact;
                    /*TgDEBUG_COLLISION_TRIANGLE( iDBG_TriID, ETgFEBUG_COLLISION_COLLIDED ); */
                };
            };
        };

        return (niContact == psPacket->m_niContact ? KTgE_NO_INTERSECT : KTgS_OK);
    };

    if (sAxS.m_iAxis >= 8)
    {
        /* -- Edge/Edge Intersection -- */
        /*   The minimal separation axis is the result of the cross product of both a triangle and box axis. */

        /* Construct the line segments representing the colliding edges. */

        C_TgSINT32                          iTriIdx = (sAxS.m_iAxis - 8) / 3;
        C_TgSINT32                          iBoxIdx0 = (sAxS.m_iAxis - 8) % 3;
        V(TgVEC)                            vK6;

        /*  The support point function works in this case because the axis separation routine is known NOT to return back a axis (normal) that is orthogonal to an */
        /* existing box axis. This ensures the resulting vector is on a box edge. */

        C_TgSINT32                          iIdx1 = (iBoxIdx0 + 1) % 3;
        C_TgSINT32                          iIdx2 = (iBoxIdx0 + 2) % 3;
        const TYPE                          fBX1_N = V(F_DOT)(psBX0->m.m.avAxis + iIdx1, &sAxS.m_vNormal);
        const TYPE                          fBX2_N = V(F_DOT)(psBX0->m.m.avAxis + iIdx2, &sAxS.m_vNormal);

        const TYPE                          fK0 = fBX1_N > MKL(0.0) ? psBX0->m_vExtent.m_aData[iIdx1] : -psBX0->m_vExtent.m_aData[iIdx1];
        const TYPE                          fK1 = fBX2_N > MKL(0.0) ? psBX0->m_vExtent.m_aData[iIdx2] : -psBX0->m_vExtent.m_aData[iIdx2];
        const TYPE                          fK2 = MKL(2.0)*psBX0->m_vExtent.m_aData[iBoxIdx0];
        V(C_TgVEC)                          vK0 = V(F_MUL_SV)(fK0, psBX0->m.m.avAxis + iIdx1);
        V(C_TgVEC)                          vK1 = V(F_MUL_SV)(fK1, psBX0->m.m.avAxis + iIdx2);
        V(C_TgVEC)                          vK2 = V(F_MUL_SV)(psBX0->m_vExtent.m_aData[iBoxIdx0], psBX0->m.m.avAxis + iBoxIdx0);
        V(C_TgVEC)                          vK3 = V(F_ADD)(&vK0, &vK1);
        V(C_TgVEC)                          vK4 = V(F_SUB)(&psBX0->m.m.vOrigin, &vK2);
        V(C_TgVEC)                          vK5 = V(F_MUL_SV)(fK2, psBX0->m.m.avAxis + iBoxIdx0);

        V(TgVEC)                            vP0;
        TYPE                                fDistSq, fT0, fT1;

        vP0 = V(F_ADD)(&vK3, &vK4);

        /* Calculate the contact point based on the points of closest proximity between the two edges. */
        fDistSq = V(tgCO_F_LR11_ParamSq_LR11)(
            &fT0, &fT1, &vP0, &vK5, psST0->m_sCT.m_sET.m_sPT.m_avPoint + iTriIdx, psST0->m_sCT.m_sET.m_avEdge + iTriIdx);

        vK6 = V(F_MUL_SV)(fT0, &vK5);

        psContact = psPacket->m_psContact + psPacket->m_niContact;

        psContact->m_vS0 = V(F_ADD)(&vP0, &vK6);
        psContact->m_vN0 = sAxS.m_vNormal;
        psContact->m_fT0 = MKL(0.0);
        psContact->m_fDepth = F(tgPM_SQRT)(fDistSq);

        TgERROR( F(tgCM_NR0)(fDistSq - sAxS.m_fDepth*sAxS.m_fDepth) );

        ++psPacket->m_niContact;
        /*TgDEBUG_COLLISION_TRIANGLE( iDBG_TriID, ETgFEBUG_COLLISION_COLLIDED ); */

        return (KTgS_OK);
    }

    TgERROR( sAxS.m_iAxis > 1 );

    /* -- Box Axis Intersection */
    /*  The minimal separation axis is one of the box axes. */

    fAX_NM = V(F_DOT)(&sAxS.m_vNormal, &psST0->m_sCT.m_sET.m_sPT.m_vNormal);

    if (!F(tgCM_NR0)(fAX_NM))
    {
        /*  Analyze the box vertices to see if they are contact points - this is done since contained points are not found by the following algorithm (edge clipping).  */
        /* Take each box vertex, project it down along the contact normal to see if it intersects the triangle making a contact. */

        TgSINT32                            iFlag;

        for (iFlag = 0; iFlag < 8; ++iFlag)
        {
            const TYPE                          fE0 = 0 != (iFlag & 1) ? psBX0->m_vExtent.m.x : -psBX0->m_vExtent.m.x;
            const TYPE                          fE1 = 0 != (iFlag & 2) ? psBX0->m_vExtent.m.y : -psBX0->m_vExtent.m.y;
            const TYPE                          fE2 = 0 != (iFlag & 4) ? psBX0->m_vExtent.m.z : -psBX0->m_vExtent.m.z;
            V(C_TgVEC)                          vCS = V(tgGM_BX_Calc_Point)(psBX0, fE0, fE1, fE2);
            V(C_TgVEC)                          vK0 = V(F_SUB)(&vCS, psST0->m_sCT.m_sET.m_sPT.m_avPoint);
            const TYPE                          fDistN = V(F_DOT)(&vK0, &psST0->m_sCT.m_sET.m_sPT.m_vNormal);
            const TYPE                          fDepth = F(tgPM_ABS)(fDistN / fAX_NM);
            V(C_TgVEC)                          vK1 = V(F_MUL_SV)(F(tgPM_FSEL)(fAX_NM, fDepth, -fDepth), &sAxS.m_vNormal);
            V(C_TgVEC)                          vP0 = V(F_ADD)(&vCS, &vK1);

            if (fDistN >= MKL(0.0)) /* The point/vertex is above the triangle plane - ignore and continue processing. */
            {
                continue;
            };

            if (!V(tgGM_ST_Is_Contained)(psST0, &vP0))
            {
                continue;
            };

            if (psPacket->m_niContact >= psPacket->m_niMaxContact)
            {
                return (KTgE_MAX_CONTACTS);
            };

            psContact = psPacket->m_psContact + psPacket->m_niContact;

            psContact->m_vS0 = vCS;
            psContact->m_vN0 = sAxS.m_vNormal;
            psContact->m_fT0 = MKL(0.0);
            psContact->m_fDepth = fDepth;

            ++psPacket->m_niContact;
            /*TgDEBUG_COLLISION_TRIANGLE( iDBG_TriID, ETgFEBUG_COLLISION_COLLIDED ); */
        };
    };

    TgERROR( !F(tgCM_NR1)(V(F_DOT)(&sAxS.m_vNormal, &psST0->m_sCT.m_sET.m_sPT.m_vNormal)) );

    {
        /*  Need to use the special version of the clip function so that the cutting face opposite of the resultant contact surface can be disabled so that the correct */
        /* points on the triangle can be found. */

        V(PU_STg2_CO_Clip_List)             psCL;
        C_TgSINT32                          iFlag = ~(1 << (sAxS.m_iAxis - 2));
        const TYPE                          fExtent = psBX0->m_vExtent.m_aData[(sAxS.m_iAxis - 2) % 3];
        TYPE                                fRadSq;

        psCL = TgMALLOC_POOL( sizeof( V(STg2_CO_Clip_List) ) + 7 * sizeof( V(TgVEC) ) );
        psCL->m_niPoint = 0;
        psCL->m_niMax = 8;

        iResult = V(tgCO_F_BXF_Clip_PT)(psCL, psBX0, iFlag, &psST0->m_sCT.m_sET.m_sPT);
        TgERROR( TgSUCCEEDED( iResult ) );

        fRadSq = psBX0->m_vExtent.m.x*psBX0->m_vExtent.m.x;
        fRadSq += psBX0->m_vExtent.m.y*psBX0->m_vExtent.m.y;
        fRadSq += psBX0->m_vExtent.m.z*psBX0->m_vExtent.m.z;

        for (iResult = 0; iResult < psCL->m_niPoint; ++iResult)
        {
            /*  If the contact point is on an invalid edge and is not a box vertex then cull the point. */

            V(C_TgVEC)                          vRelPoint = V(F_SUB)(&psCL->m_avPoint[iResult], &psBX0->m.m.vOrigin);

            /* Box vertices are not eligible for culling. */

            if (!F(tgCM_NR0)(V(F_LSQ)(&vRelPoint) - fRadSq))
            {
                if (!V(tgGM_ST_Test_Edge_0)(psST0))
                {
                    if (V(tgCO_F_PN_Dist_VT)(psST0->m_avPlane + 0, psCL->m_avPoint + iResult) < psPacket->m_fSnapTol)
                    {
                        continue;
                    };
                };

                if (!V(tgGM_ST_Test_Edge_1)(psST0))
                {
                    if (V(tgCO_F_PN_Dist_VT)(psST0->m_avPlane + 1, psCL->m_avPoint + iResult) < psPacket->m_fSnapTol)
                    {
                        continue;
                    };
                };

                if (!V(tgGM_ST_Test_Edge_2)(psST0))
                {
                    if (V(tgCO_F_PN_Dist_VT)(psST0->m_avPlane + 2, psCL->m_avPoint + iResult) < psPacket->m_fSnapTol)
                    {
                        continue;
                    };
                };
            };

            psContact = psPacket->m_psContact + psPacket->m_niContact;

            if (psPacket->m_niContact >= psPacket->m_niMaxContact)
            {
                TgFREE_POOL( psCL );
                return (KTgE_MAX_CONTACTS);
            }
            else
            {
                const TYPE                          fDepth = fExtent + V(F_DOT)(&vRelPoint, &sAxS.m_vNormal);
                V(C_TgVEC)                          vK2 = V(F_MUL_SV)(fDepth, &sAxS.m_vNormal);

                psContact->m_vS0 = V(F_SUB)(psCL->m_avPoint + iResult, &vK2);
                psContact->m_vN0 = sAxS.m_vNormal;
                psContact->m_fT0 = MKL(0.0);
                psContact->m_fDepth = fDepth < MKL(0.0) ? MKL(0.0) : fDepth;

                ++psPacket->m_niContact;
                /*TgDEBUG_COLLISION_TRIANGLE( iDBG_TriID, ETgFEBUG_COLLISION_COLLIDED ); */
            };
        };

        TgFREE_POOL( psCL );
    };

    return (niContact == psPacket->m_niContact ? KTgE_NO_INTERSECT : KTgS_OK);
}


/* ---- V(tgCO_F_ST_Sweep_BX) ------------------------------------------------------------------------------------------------------------------------------------------- */
/* Input:  tgPacket: The current series of contact points for this query-series, and contact generation parameters.                                                       */
/* Input:  fPM: Current normalized time of first contact.                                                                                                                 */
/* Input:  bPenetrate: If the swept primitives are in penetration, if true the function will return points of penetration.                                                */
/* Input:  psST0: Space Triangle primitive                                                                                                                                */
/* Input:  psBX0: Box primitive                                                                                                                                           */
/* Input:  sDT: A structure holding the swept primitive displacement for the entire duration of the test period                                                           */
/* Output: tgPacket: Contact points are added or replace the current set depending on the time comparison and given parameters                                            */
/* Output: fPM: New normalized time of first contact                                                                                                                      */
/* Return: Result Code                                                                                                                                                    */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT V(tgCO_F_ST_Sweep_BX)( V(PC_STg2_CO_Packet) psPacket, TYPE *pfPM, V(CPC_TgSTRI) psST0, V(CPC_TgBOX) psBX0, V(CPC_TgDELTA) psDT )
{
    V(P_STg2_CO_Contact)                psContact;
    V(STg2_CO_Axis_Project)             sP0, sP1;
    V(STg2_CO_Axis_Info)                sNFO;
    TgRESULT                            iResult;

    TgERROR( V(tgGM_ST_Is_Valid)(psST0) && V(tgGM_BX_Is_Valid)(psBX0) );

    if (0 == psPacket->m_niMaxContact || psPacket->m_niContact >= psPacket->m_niMaxContact || nullptr == psPacket->m_psContact)
    {
        return (KTgE_FAIL);
    };

    /*TgDEBUG_COLLISION_TRIANGLE_CREATEID(iDBG_TriID, tgST1, ETgFEBUG_COLLISION_ENTERFCN); */

    sNFO.m_enSide = ETgCO_AXIS_CONTACT_DIRECTION__UNKNOWN;
    sNFO.m_fMinT = F(KTgMAX);

    iResult = V(tgCO_F_ST_Sweep_Axis_Seperation_BX)(&sNFO, *pfPM + psPacket->m_fSweepTol, psST0, psBX0, psDT);

    if (TgFAILED( iResult ))
    {
        TgERROR( KTgE_NO_INTERSECT == iResult );
        return (iResult);
    };

    /* == Contact Generation == */

    TgERROR( (sNFO.m_enSide != ETgCO_AXIS_CONTACT_DIRECTION__UNKNOWN) );

    if (sNFO.m_enSide == ETgCO_AXIS_CONTACT_DIRECTION__PENETRATED || sNFO.m_fMinT < MKL(0.0))
    {
        /* Pre-Penetration. */
        if (*pfPM > psPacket->m_fSweepTol)
        {
            psPacket->m_niContact = 0;
        };

        *pfPM = MKL(0.0);

        if ((TgTRUE == psPacket->m_bReport_Penetration) && (KTgE_MAX_CONTACTS == V(tgCO_F_ST_Penetrate_BX)(psPacket, psST0, psBX0)))
        {
            return (KTgE_MAX_CONTACTS);
        };

        return (KTgE_PREPENETRATION);
    };

    /* Make sure this contact has not occurred more than tolerance later than the current sweep time. */

    if (sNFO.m_fMinT > *pfPM + psPacket->m_fSweepTol)
    {
        return (KTgE_NO_INTERSECT);
    };

    /* Generate the axis projection information using the returned axis vector - and then choose the pertinent values. */

    V(tgCO_F_PT_Axis_ProjInfo)( &sP0, &sNFO.m_vNormal, &psST0->m_sCT.m_sET.m_sPT );
    V(tgCO_F_BX_Axis_ProjInfo)( &sP1, &sNFO.m_vNormal, psBX0 );

    {
        C_TgBOOL                            bSide = sNFO.m_enSide == ETgCO_AXIS_CONTACT_DIRECTION__NEGATIVE;
        V(PC_TgVEC)                         avVert0 = bSide ? sP0.m_avMinVert : sP0.m_avMaxVert;
        V(PC_TgVEC)                         avVert1 = bSide ? sP1.m_avMaxVert : sP1.m_avMinVert;
        C_TgSINT32                          niVertD0 = bSide ? sP0.m_iMinID : sP0.m_iMaxID;
        C_TgSINT32                          niVertD1 = bSide ? sP1.m_iMaxID : sP1.m_iMinID;
        C_TgSINT32                          iFeatureID = bSide ? sP0.m_iMinID : sP0.m_iMaxID;
        V(C_TgVEC)                          vK0 = V(F_NEG)(&sNFO.m_vNormal);
        V(C_TgVEC)                          vNormal = bSide ? vK0 : sNFO.m_vNormal;
        V(C_TgVEC)                          vOffset = V(F_MUL_SV)(sNFO.m_fMinT, &psDT->m_vDT);

        /* Based on the axis projection information - generate the appropriate contact for this axis. */
        if (1 == niVertD0) /* Triangle Vertex in contact with the box. */
        {
            /* Check feature reduction on the triangle to make sure the vertex is valid. */

            if (((iFeatureID >= 0) & (iFeatureID <= 2)) && !V(tgGM_ST_Test_Point)(psST0, iFeatureID))
            {
                return (KTgE_NO_INTERSECT);
            };

            /* Check to see if result values need to be reset because of the change in intersection time. */

            if (sNFO.m_fMinT < *pfPM - psPacket->m_fSweepTol)
            {
                psPacket->m_niContact = 0;
                *pfPM = sNFO.m_fMinT;
            };

            psContact = psPacket->m_psContact + psPacket->m_niContact;

            psContact->m_vS0 = avVert0[0];
            psContact->m_vN0 = vNormal;
            psContact->m_fT0 = sNFO.m_fMinT;
            psContact->m_fDepth = MKL(0.0);

            ++psPacket->m_niContact;

            /*TgDEBUG_COLLISION_TRIANGLE(iDBG_TriID, ETgFEBUG_COLLISION_COLLIDED); */
            return (KTgS_OK);
        };

        if (niVertD1 == 1)
        {
            /* Box Vertex in contact with the triangle. */
            if (sNFO.m_fMinT < *pfPM - psPacket->m_fSweepTol)
            {
                psPacket->m_niContact = 0;
                *pfPM = sNFO.m_fMinT;
            };

            psContact = psPacket->m_psContact + psPacket->m_niContact;

            psContact->m_vS0 = V(F_ADD)(&vOffset, &avVert1[0]);
            psContact->m_vN0 = vNormal;
            psContact->m_fT0 = sNFO.m_fMinT;
            psContact->m_fDepth = MKL(0.0);

            ++psPacket->m_niContact;

            /*TgDEBUG_COLLISION_TRIANGLE(iDBG_TriID, ETgFEBUG_COLLISION_COLLIDED); */
            return (KTgS_OK);
        };

        if (niVertD0 == 2 || niVertD1 == 2) /* Box or Tri Edge Contact */
        {
            /* Check feature reduction on the triangle to make sure the edge is valid. */

            V(TgVEC)                            vRN0 = V(KTgV_ZERO);
            V(TgVEC)                            vRN1 = V(KTgV_ZERO);
            V(TgSEGMENT)                        sTriE;
            TYPE                                fT0, fT1;
            V(C_TgVEC)                          vK9 = V(F_SUB)(avVert0 + 1, avVert0);

            iResult = -1;

            if (((0 != (iFeatureID & 4)) & (niVertD0 == 2)) && !V(tgGM_ST_Test_Edge)(psST0, iFeatureID - 4))
            {
                return (KTgE_NO_INTERSECT);
            };

            V(tgGM_SG_Init)(&sTriE, avVert0, &vK9);

            if (niVertD1 == 4) /* Triangle Edge in contact with a Box Face */
            {
                V(C_TgVEC)                          vK1 = V(F_ADD)(avVert1 + 0, &vOffset);
                V(C_TgVEC)                          vK2 = V(F_SUB)(avVert1 + 1, avVert1);
                V(C_TgVEC)                          vK3 = V(F_SUB)(avVert1 + 2, avVert1);
                V(TgRECTANGLE)                      sBoxFace;

                V(tgGM_RT_Init_SE)(&sBoxFace, &vK1, &vK2, &vK3);

                if (TgSUCCEEDED( V(tgCO_F_RT_Clip_Param_SG)(&fT0, &fT1, &sBoxFace, &sTriE) ))
                {
                    V(C_TgVEC)                          vK4 = V(F_MUL_SV)(fT0, &sTriE.m_vDirN);
                    V(C_TgVEC)                          vK5 = V(F_MUL_SV)(fT1, &sTriE.m_vDirN);
                    V(C_TgVEC)                          vK6 = V(F_ADD)(&sTriE.m_vOrigin, &vK4);
                    V(C_TgVEC)                          vK7 = V(F_ADD)(&sTriE.m_vOrigin, &vK5);
                    V(C_TgVEC)                          vK8 = V(F_SUB)(&vRN0, &vRN1);

                    vRN0 = vK6;
                    vRN1 = vK7;
                    iResult = V(F_LSQ)(&vK8) > F(KTgROOT_EPS) ? 2 : 1;
                };
            }
            else
            {
                V(C_TgVEC)                          vK1 = V(F_SUB)(avVert1 + 1, avVert1);
                V(C_TgVEC)                          vK2 = V(F_ADD)(&vOffset, avVert1);
                V(TgSEGMENT)                        sBoxE;

                V(tgGM_SG_Init)(&sBoxE, &vK2, &vK1);

                if (niVertD0 == 2) /* Triangle Edge in contact with a Box Edge */
                {
                    iResult = V(tgCO_F_LN_Internal_Intersect_LN)(
                        &vRN0, &vRN1, &sTriE.m_vOrigin, &sTriE.m_vDirN, &sBoxE.m_vOrigin, &sBoxE.m_vDirN);
                }
                else /* Triangle Face in contact with a Box Edge */
                {
                    TgSINT32                            iCode;

                    iResult = V(tgCO_F_ST_Clip_Param_F_SG)(&fT0, &fT1, &iCode, psST0, &sBoxE);
                    TgERROR( TgSUCCEEDED( iResult ) );

                    if (0 == (iCode & 12)) /* Check to see if both points are either invalid or reduced. */
                    {
                        return (KTgE_NO_INTERSECT);
                    }
                    else
                    {
                        const TYPE                          fK0 = (0 != (iCode & 4)) ? fT0 : fT1;
                        V(C_TgVEC)                          vK3 = V(F_MUL_SV)(fK0, &sBoxE.m_vDirN);
                        V(C_TgVEC)                          vK4 = V(F_MUL_SV)(fT1, &sBoxE.m_vDirN);
                        V(C_TgVEC)                          vK5 = V(F_ADD)(&sBoxE.m_vOrigin, &vK3);
                        V(C_TgVEC)                          vK6 = V(F_ADD)(&sBoxE.m_vOrigin, &vK4);
                        V(C_TgVEC)                          vK7 = V(F_SUB)(&vK5, &vK6);

                        vRN0 = vK5;
                        vRN1 = vK6;

                        iResult = (12 == (iCode & 12)) && V(F_LSQ)(&vK7) > F(KTgROOT_EPS) ? 2 : 1;
                    };
                };
            };

            if (sNFO.m_fMinT < *pfPM - psPacket->m_fSweepTol)
            {
                psPacket->m_niContact = 0;
                *pfPM = sNFO.m_fMinT;
            };

            switch (iResult)
            {
                case 2:
                    psContact = psPacket->m_psContact + psPacket->m_niContact;

                    psContact->m_vS0 = vRN1;
                    psContact->m_vN0 = vNormal;
                    psContact->m_fT0 = sNFO.m_fMinT;
                    psContact->m_fDepth = MKL(0.0);

                    ++psPacket->m_niContact;

                case 1:
                    if (psPacket->m_niContact >= psPacket->m_niMaxContact)
                    {
                        return (KTgE_MAX_CONTACTS);
                    };

                    psContact = psPacket->m_psContact + psPacket->m_niContact;

                    psContact->m_vS0 = vRN0;
                    psContact->m_vN0 = vNormal;
                    psContact->m_fT0 = sNFO.m_fMinT;
                    psContact->m_fDepth = MKL(0.0);

                    ++psPacket->m_niContact;
                    /*TgDEBUG_COLLISION_TRIANGLE(iDBG_TriID, ETgFEBUG_COLLISION_COLLIDED); */

                    break;

                default:
                    TgERROR(TgFALSE);
            };

            return (iResult > 0 ? KTgS_OK : KTgE_NO_INTERSECT);
        }
        else
        {
            /* Triangle Face in contact with a Box Face */
            /* Construct a centroid orientated rectangle definition */

            V(C_TgVEC)                          vE0 = V(F_SUB)(avVert1 + 1, avVert1 + 0);
            V(C_TgVEC)                          vE1 = V(F_SUB)(avVert1 + 2, avVert1 + 0);
            const TYPE                          fE0_E0 = V(F_LSQ)(&vE0);
            const TYPE                          fE1_E1 = V(F_LSQ)(&vE1);
            V(C_TgVEC)                          vS0 = V(F_ADD)(avVert1 + 0, &vOffset);

            TgSINT32                            iIdx, iVert, iCode, niPoint = 0;
            V(TgVEC)                            avContact[12];
            TYPE                                fT0, fT1;

            /*  Analyze the valid triangle vertices to see if they are contact points - this is done since contained points are not found by the following algorithm */
            /* (box edge clipping). */

            for (iVert = 0; iVert < 3; ++iVert)
            {
                /* Check to see if the triangle point is contained in the box face. */

                V(C_TgVEC)                          vDS = V(F_SUB)(psST0->m_sCT.m_sET.m_sPT.m_avPoint + iVert, &vS0);
                const TYPE                          fDS_E0 = V(F_DOT)(&vDS, &vE0);
                const TYPE                          fDS_E1 = V(F_DOT)(&vDS, &vE1);

                if (!V(tgGM_ST_Test_Point)(psST0, iVert))
                {
                    if (fDS_E0 < MKL(0.0) || fDS_E1 < MKL(0.0) || fDS_E0 > fE0_E0 || fDS_E1 > fE1_E1)
                    {
                        continue;
                    };
                };

                avContact[niPoint++] = psST0->m_sCT.m_sET.m_sPT.m_avPoint[iVert];
            };

            V(tgCO_FI_ST_Clip_Param_F_LR11)(&fT0, &fT1, &iCode, psST0, &vS0, &vE0);
            if (0 != (iCode & 4))
            {
                V(C_TgVEC)                          vK1 = V(F_MUL_SV)(fT0, &vE0);

                avContact[niPoint++] = V(F_ADD)(&vS0, &vK1);
            };

            if (0 != (iCode & 8))
            {
                V(C_TgVEC)                          vK1 = V(F_MUL_SV)(fT1, &vE0);

                avContact[niPoint++] = V(F_ADD)(&vS0, &vK1);
            };

            V(tgCO_FI_ST_Clip_Param_F_LR11)(&fT0, &fT1, &iCode, psST0, &vS0, &vE1);
            if (0 != (iCode & 4))
            {
                V(C_TgVEC)                          vK1 = V(F_MUL_SV)(fT0, &vE1);

                avContact[niPoint++] = V(F_ADD)(&vS0, &vK1);
            };

            if (0 != (iCode & 8))
            {
                V(C_TgVEC)                          vK1 = V(F_MUL_SV)(fT1, &vE1);

                avContact[niPoint++] = V(F_ADD)(&vS0, &vK1);
            };

            {
                V(C_TgVEC)                          vK3 = V(F_ADD)(&vS0, &vE1);

                V(tgCO_FI_ST_Clip_Param_F_LR11)(&fT0, &fT1, &iCode, psST0, &vK3, &vE0);
                if (0 != (iCode & 4))
                {
                    V(C_TgVEC)                          vK1 = V(F_MUL_SV)(fT0, &vE0);
                    V(C_TgVEC)                          vK2 = V(F_ADD)(&vS0, &vE1);

                    avContact[niPoint++] = V(F_ADD)(&vK2, &vK1);
                };

                if (0 != (iCode & 8))
                {
                    V(C_TgVEC)                          vK1 = V(F_MUL_SV)(fT1, &vE0);
                    V(C_TgVEC)                          vK2 = V(F_ADD)(&vS0, &vE1);

                    avContact[niPoint++] = V(F_ADD)(&vK2, &vK1);
                };
            };

            {
                V(C_TgVEC)                          vK3 = V(F_ADD)(&vS0, &vE0);

                V(tgCO_FI_ST_Clip_Param_F_LR11)(&fT0, &fT1, &iCode, psST0, &vK3, &vE1);
                if (0 != (iCode & 4))
                {
                    V(C_TgVEC)                          vK1 = V(F_MUL_SV)(fT0, &vE1);
                    V(C_TgVEC)                          vK2 = V(F_ADD)(&vS0, &vE0);

                    avContact[niPoint++] = V(F_ADD)(&vK2, &vK1);
                };

                if (0 != (iCode & 8))
                {
                    V(C_TgVEC)                          vK1 = V(F_MUL_SV)(fT1, &vE1);
                    V(C_TgVEC)                          vK2 = V(F_ADD)(&vS0, &vE0);

                    avContact[niPoint++] = V(F_ADD)(&vK2, &vK1);
                };
            };

            TgERROR( niPoint > 0 );

            if (sNFO.m_fMinT < *pfPM - psPacket->m_fSweepTol)
            {
                psPacket->m_niContact = 0;
                *pfPM = sNFO.m_fMinT;
            };

            for (iIdx = 0; iIdx < niPoint; ++iIdx)
            {
                TgSINT32                            iTest;

                for (iTest = 0; iTest < iIdx; ++iTest)
                {
                    V(C_TgVEC)                          vK4 = V(F_SUB)(avContact + iTest, avContact + iIdx);

                    if (!F(tgCM_NR0)(V(F_LSQ)(&vK4)))
                    {
                        break;
                    };
                }

                if (iTest != iIdx)
                {
                    continue;
                };

                if (psPacket->m_niContact >= psPacket->m_niMaxContact)
                {
                    return (KTgE_MAX_CONTACTS);
                };

                psContact = psPacket->m_psContact + psPacket->m_niContact;
                psContact->m_vS0 = avContact[iIdx];
                psContact->m_vN0 = vNormal;
                psContact->m_fT0 = sNFO.m_fMinT;
                psContact->m_fDepth = MKL(0.0);

                ++psPacket->m_niContact;
            };
        };
    };

    /*TgDEBUG_COLLISION_TRIANGLE(iDBG_TriID, ETgFEBUG_COLLISION_COLLIDED); */
    return (KTgS_OK);
}




/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  File Local Functions                                                                                                                                                  */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

/* ---- V(tgCO_F_ST_Penetrate_Axis_Seperation_BX) ----------------------------------------------------------------------------------------------------------------------- */
/* Input:  psST0: Space Triangle primitive                                                                                                                                */
/* Input:  psBX0: Box primitive                                                                                                                                           */
/* Output: sAxS: Structure holds the resulting axis separation information necessary to create a contact set.                                                             */
/* Return: False if a separating axis exists, true otherwise                                                                                                              */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
static TgBOOL V(tgCO_F_ST_Penetrate_Axis_Seperation_BX)(V(PC_STg2_CO_Axis_Result) psAxS, V(CPC_TgSTRI) psST0, V(CPC_TgBOX) psBX0)
{
    TYPE                                fMinBox, fMaxBox, fMinTri, fMaxTri;
    TgUINT32                            iIndex;
    TgBOOL                              bTriIsCoPlanarToFace = TgFALSE;
    TgSINT32                            iTriIndex;
    TgSINT32                            iBoxIndex;

    /* -- Axis: Triangle Normal -- */

    fMinTri = V(F_DOT)(psST0->m_sCT.m_sET.m_sPT.m_avPoint, &psST0->m_sCT.m_sET.m_sPT.m_vNormal);
    V(tgGM_BX_Project)(&fMinBox, &fMaxBox, psBX0, &psST0->m_sCT.m_sET.m_sPT.m_vNormal);

    if (fMaxBox < fMinTri || fMinBox > fMinTri) /* Separation test. */
    {
        return (TgFALSE);
    };

    psAxS->m_vNormal = psST0->m_sCT.m_sET.m_sPT.m_vNormal;
    psAxS->m_fDepth = fMinTri - fMinBox;
    psAxS->m_iAxis = 1;

    /* -- Axis: Box Face/Plane Normals -- */

    for (iIndex = 0; iIndex < 3; ++iIndex)
    {
        V(C_TgVEC)                          vAxis = psBX0->m.m.avAxis[iIndex];

        /* Weight the function towards the triangle normal.  In this case ignore any box axis that is "close". */

        if (F(tgCM_NR1)(V(F_DOT)(&psST0->m_sCT.m_sET.m_sPT.m_vNormal, &vAxis)))
        {
            /*  Optimization step: Since a box axis is identical to the triangle normal, the remaining two box axes would be coplanar with the triangle.  Thus, the cross */
            /* product values would all return vectors equivalent to the triangle normal.  The remaining cross-product values would be the edge-plane normals. */
            bTriIsCoPlanarToFace = TgTRUE;
            continue;
        }
        else
        {
            /* Determine the extents of the primitives along the chosen axis. */

            const TYPE                          fBO_AU = V(F_DOT)(&psBX0->m.m.vOrigin, &vAxis);

            V(tgGM_ST_Project)(&fMinTri, &fMaxTri, psST0, &vAxis);

            fMinBox = fBO_AU - psBX0->m_vExtent.m_aData[iIndex];
            fMaxBox = fBO_AU + psBX0->m_vExtent.m_aData[iIndex];

            /* Separation Test. */

            if (fMaxBox < fMinTri || fMinBox > fMaxTri)
            {
                return (TgFALSE);
            }
            else
            {
                /* Selection of the best (minimal depth) axis. */

                const TYPE                          fMinDepth = fMaxBox - fMinTri;
                const TYPE                          fMaxDepth = fMaxTri - fMinBox;
                C_TgBOOL                            bNegAxis = fMinDepth > fMaxDepth ? TgTRUE : TgFALSE;

                if ((bNegAxis ? fMaxDepth : fMinDepth) < psAxS->m_fDepth)
                {
                    psAxS->m_vNormal = (TgTRUE == bNegAxis) ? vAxis : V(F_NEG)( &vAxis );
                    psAxS->m_fDepth = (TgTRUE == bNegAxis) ? fMaxDepth : fMinDepth;
                    psAxS->m_iAxis = (TgSINT32)iIndex + (TgTRUE == bNegAxis ? 5 : 2);
                };
            };
        };
    };

    /* -- Axis: Axis-Box Cross Product */

    if (!bTriIsCoPlanarToFace)
    {
        for (iTriIndex = 0; iTriIndex < 3; ++iTriIndex)
        {
            /* Disregard edges that are indicated as invalid.  This is usually due to feature reduction removing this element. */
            for (iBoxIndex = 0; iBoxIndex < 3; ++iBoxIndex)
            {
                TYPE                                fAxisLen;
                V(TgVEC)                            vAxis;

                /* Axis is created by taking the cross product of the triangle edge and a box axis. */

                vAxis = V(F_UCX_LEN)(&fAxisLen, psBX0->m.m.avAxis + iBoxIndex, psST0->m_sCT.m_sET.m_avEdge + iTriIndex);

                if (F(tgCM_NR0)(fAxisLen)) /* Sanif/Parallel check for the resulting vector. */
                {
                    continue;
                };

                /*  Check to see if the resultant normal is approximately the same as that of the triangle normal. If this is the case skip this axis.  This check is */
                /* primarily to aid in contact generation, since a resultant in this context implies an edge-edge contact (1-2 point) instead of the more stable cases */
                /* (3-4 points). */

                if (
                    F(tgCM_NR1)(V(F_DOT)(psBX0->m.m.avAxis + 0, &vAxis)) ||
                    F(tgCM_NR1)(V(F_DOT)(psBX0->m.m.avAxis + 1, &vAxis)) ||
                    F(tgCM_NR1)(V(F_DOT)(psBX0->m.m.avAxis + 2, &vAxis)) ||
                    F(tgCM_NR1)(V(F_DOT)(&psST0->m_sCT.m_sET.m_sPT.m_vNormal, &vAxis))
                )
                {
                    continue;
                };

                /* Determine the extents of the primitives along the chosen axis. */

                V(tgGM_ST_Project)(&fMinTri, &fMaxTri, psST0, &vAxis);
                V(tgGM_BX_Project)(&fMinBox, &fMaxBox, psBX0, &vAxis);

                /* Separation Test. */

                if (fMaxBox < fMinTri || fMinBox < fMaxTri)
                {
                    return (TgFALSE);
                };

                if (!V(tgGM_ST_Test_Edge)(psST0, iTriIndex)) /* Feature reduction test - ignore axes associated with reduced edges. */
                {
                    continue;
                }
                else
                {
                    /* Selection of the best (minimal depth) axis. */

                    const TYPE                          fMinDepth = fMaxBox - fMinTri;
                    const TYPE                          fMaxDepth = fMaxTri - fMinBox;
                    C_TgBOOL                            bNegAxis = fMinDepth > fMaxDepth;

                    if ((bNegAxis ? fMaxDepth : fMinDepth) < psAxS->m_fDepth)
                    {
                        psAxS->m_vNormal = bNegAxis ? vAxis : V(F_NEG)(&vAxis);
                        psAxS->m_fDepth = bNegAxis ? fMaxDepth : fMinDepth;
                        psAxS->m_iAxis = iTriIndex * 3 + iBoxIndex + 8;
                    };
                };
            };
        };
    }
    else
    {
        for (iTriIndex = 0; iTriIndex < 3; ++iTriIndex)
        {
            V(C_TgVEC)                          vAxis = psST0->m_avPlane[iTriIndex].m_vNormal;

            /* Check to see if the resultant normal is approximately the same as that of the triangle normal. If this is the case skip this axis.  This check is primarily*/
            /* to aid in contact generation, since a resultant in this context implies an edge-edge contact (1-2 point) instead of the more stable cases (3-4 points). */

            if (
                F(tgCM_NR1)(V(F_DOT)(psBX0->m.m.avAxis + 0, &vAxis)) ||
                F(tgCM_NR1)(V(F_DOT)(psBX0->m.m.avAxis + 1, &vAxis)) ||
                F(tgCM_NR1)(V(F_DOT)(psBX0->m.m.avAxis + 2, &vAxis))
            )
            {
                continue;
            };

            /* Determine the extents of the primitives along the chosen axis. */

            V(tgGM_ST_Project)(&fMinTri, &fMaxTri, psST0, &vAxis);
            V(tgGM_BX_Project)(&fMinBox, &fMaxBox, psBX0, &vAxis);

            /* Separation Test. */

            if (fMaxBox < fMinTri || fMinBox < fMaxTri)
            {
                return (TgFALSE);
            };

            if (!V(tgGM_ST_Test_Edge)(psST0, iTriIndex)) /* Feature reduction test - ignore axes associated with reduced edges. */
            {
                continue;
            }
            else
            {
                /* Selection of the best (minimal depth) axis. */

                const TYPE                          fMinDepth = fMaxBox - fMinTri;
                const TYPE                          fMaxDepth = fMaxTri - fMinBox;
                C_TgBOOL                            bNegAxis = fMinDepth > fMaxDepth ? TgTRUE : TgFALSE;

                if ((TgTRUE == bNegAxis ? fMaxDepth : fMinDepth) < psAxS->m_fDepth)
                {
                    psAxS->m_vNormal = TgTRUE == bNegAxis ? vAxis : V(F_NEG)(&vAxis);
                    psAxS->m_fDepth = TgTRUE == bNegAxis ? fMaxDepth : fMinDepth;
                    psAxS->m_iAxis = iTriIndex + 21;
                };
            };
        };
    };

    return (TgTRUE);
}


/* ---- V(tgCO_F_ST_Sweep_Axis_Seperation_BX) --------------------------------------------------------------------------------------------------------------------------- */
/*  Feature reduction removal of reduced edges and their associated directions implemented.                                                                               */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT V(tgCO_F_ST_Sweep_Axis_Seperation_BX)( V(PC_STg2_CO_Axis_Info) psNFO, const TYPE fLimitT, V(CPC_TgSTRI) psST0, V(CPC_TgBOX) psBX0, V(CPC_TgDELTA) psDT )
{
    V(STg2_CO_Axis_Test)                sAxTest; /* Parameter data output variable */
    TgSINT32                            iResult;
    V(TgVEC)                            vAxis;
    TgSINT32                            iTriIndex;
    TgSINT32                            iBoxIndex;
    TgSINT32                            iIndex;

    TYPE                                fSkipT = -F(KTgMAX); /* T-value for axes associated with reduced features. */
    TgBOOL                              bTriIsCoPlanarToFace = TgFALSE;

    const TYPE fS0_NM = V(F_DOT)(psST0->m_sCT.m_sET.m_sPT.m_avPoint, &psST0->m_sCT.m_sET.m_sPT.m_vNormal);

    sAxTest.m_fLimitT = fLimitT; /* The maximum t-value by which a contact must happen resulting in non-contact. */
    sAxTest.m_fMinT = -F(KTgMAX);
    sAxTest.m_fMaxT = F(KTgMAX);

    /* -- Axis: Triangle Normal -- */

    sAxTest.m_fMin0 = fS0_NM;
    sAxTest.m_fMax0 = fS0_NM;
    V(tgGM_BX_Project)(&sAxTest.m_fMin1, &sAxTest.m_fMax1, psBX0, &psST0->m_sCT.m_sET.m_sPT.m_vNormal);
    sAxTest.m_fSpeed = V(F_DOT)(&psDT->m_vDT, &psST0->m_sCT.m_sET.m_sPT.m_vNormal);

    iResult = V(tgCO_F_Test_Seperating_Axis)(&sAxTest);
    switch (iResult)
    {
        case  1: /* Update has occurred */
            psNFO->m_enSide = (sAxTest.m_fMax1 < sAxTest.m_fMin0) ?
                ETgCO_AXIS_CONTACT_DIRECTION__NEGATIVE : ETgCO_AXIS_CONTACT_DIRECTION__POSITIVE;
            psNFO->m_vNormal = psST0->m_sCT.m_sET.m_sPT.m_vNormal;
            psNFO->m_fMinT = sAxTest.m_fMinT;
        case  0: /* Contact occurred in valid interval, but earlier contact already recorded. */
            break;
        case -1: /* No contact occurred during valid interval, thus primitives are separated on this axis. */
            return (KTgE_NO_INTERSECT);
    };

    TgERROR( (psNFO->m_enSide != ETgCO_AXIS_CONTACT_DIRECTION__NEGATIVE) ); /* Sanity Check: Box can not contact the triangle back side.; */

    /* -- Axis: Box Face/Plane Normals -- */

    for (iIndex = 0; iIndex < 3; ++iIndex)
    {
        V(C_TgVEC)                          vAxis1 = psBX0->m.m.avAxis[iIndex];

        /* Weight the function towards the triangle normal.  In this case ignore any box axis that is "close". */

        if (F(tgCM_NR1)(V(F_DOT)(&psST0->m_sCT.m_sET.m_sPT.m_vNormal, &vAxis1)))
        {
            /*  Optimization step: Since a box axis is identical to the triangle normal, the remaining two box axes would be coplanar with the triangle.  Thus, the cross */
            /* product values would all return vectors equivalent to the triangle normal.  The remaining cross-product values would be the edge-plane normals. */

            bTriIsCoPlanarToFace = TgTRUE;
            continue;
        }
        else
        {
            const TYPE                          fBO_AU = V(F_DOT)(&psBX0->m.m.vOrigin, &vAxis1);

            V(tgGM_ST_Project)(&sAxTest.m_fMin0, &sAxTest.m_fMax0, psST0, &vAxis1);
            sAxTest.m_fMin1 = fBO_AU - psBX0->m_vExtent.m_aData[iIndex];
            sAxTest.m_fMax1 = fBO_AU + psBX0->m_vExtent.m_aData[iIndex];
            sAxTest.m_fSpeed = V(F_DOT)(&vAxis1, &psDT->m_vDT);

            iResult = V(tgCO_F_Test_Seperating_Axis)(&sAxTest);
            switch (iResult)
            {
                case  1: /* Update has occurred */
                    psNFO->m_enSide = (sAxTest.m_fMax1 < sAxTest.m_fMin0) ? ETgCO_AXIS_CONTACT_DIRECTION__NEGATIVE : ETgCO_AXIS_CONTACT_DIRECTION__POSITIVE;
                    psNFO->m_vNormal = vAxis1;
                    psNFO->m_fMinT = sAxTest.m_fMinT;
                case  0: /* Contact occurred in valid interval, but earlier contact already recorded. */
                    break;
                case -1: /* No contact occurred during valid interval, thus primitives are separated on this axis. */
                    return (KTgE_NO_INTERSECT);
            };
        };
    };

    if (!bTriIsCoPlanarToFace)
    {
        for (iTriIndex = 0; iTriIndex < 3; ++iTriIndex)
        {
            /* Disregard edges that are indicated as invalid.  This is usually due to feature reduction removing this element. */

            for (iBoxIndex = 0; iBoxIndex < 3; ++iBoxIndex)
            {
                TYPE                                fAxisLen;

                /* Axis is created by taking the cross product of the triangle edge and a box axis. */

                vAxis = V(F_UCX_LEN)(&fAxisLen, psBX0->m.m.avAxis + iBoxIndex, psST0->m_sCT.m_sET.m_avEdge + iTriIndex);

                if (F(tgCM_NR0)(fAxisLen))
                {
                    continue;
                };

                /* Check to see if the resultant normal is approximately the same as that of the triangle normal. If this is the case skip this axis.  This check is */
                /* primarily to aid in contact generation, since a resultant in this context implies an edge-edge contact (1-2 point) instead of the more stable cases */
                /* (3-4 points). */

                if (
                    F(tgCM_NR1)(V(F_DOT)(psBX0->m.m.avAxis + 0, &vAxis)) ||
                    F(tgCM_NR1)(V(F_DOT)(psBX0->m.m.avAxis + 1, &vAxis)) ||
                    F(tgCM_NR1)(V(F_DOT)(psBX0->m.m.avAxis + 2, &vAxis)) ||
                    F(tgCM_NR1)(V(F_DOT)(&psST0->m_sCT.m_sET.m_sPT.m_vNormal, &vAxis))
                )
                {
                    continue;
                };

                /* Perform the separation test. */

                V(tgGM_ST_Project)(&sAxTest.m_fMin0, &sAxTest.m_fMax0, psST0, &vAxis);
                V(tgGM_BX_Project)(&sAxTest.m_fMin1, &sAxTest.m_fMax1, psBX0, &vAxis);
                sAxTest.m_fSpeed = V(F_DOT)(&vAxis, &psDT->m_vDT);

                iResult = V(tgCO_F_Test_Seperating_Axis)(&sAxTest);
                switch (iResult)
                {
                    case  1: /* Update has occurred */
                        if (!V(tgGM_ST_Test_Edge)(psST0, iTriIndex))
                        {
                            fSkipT = fSkipT > sAxTest.m_fMinT ? fSkipT : sAxTest.m_fMinT;
                            break;
                        };

                        psNFO->m_enSide = (sAxTest.m_fMax1 < sAxTest.m_fMin0) ? ETgCO_AXIS_CONTACT_DIRECTION__NEGATIVE : ETgCO_AXIS_CONTACT_DIRECTION__POSITIVE;
                        psNFO->m_vNormal = vAxis;
                        psNFO->m_fMinT = sAxTest.m_fMinT;

                    case  0: /* Contact occurred in valid interval, but earlier contact already recorded. */
                        break;
                    case -1: /* No contact occurred during valid interval, thus primitives are separated on this axis. */
                        return (KTgE_NO_INTERSECT);
                };
            };
        };
    }
    else
    {
        for (iTriIndex = 0; iTriIndex < 3; ++iTriIndex)
        {
            vAxis = psST0->m_avPlane[iTriIndex].m_vNormal;

            /* Check to see if the resultant normal is approximately the same as that of the triangle normal. If this is the case skip this axis.  This check is primarily*/
            /* to aid in contact generation, since a resultant in this context implies an edge-edge contact (1-2 point) instead of the more stable cases (3-4 points). */

            if (
                F(tgCM_NR1)(V(F_DOT)(psBX0->m.m.avAxis + 0, &vAxis)) ||
                F(tgCM_NR1)(V(F_DOT)(psBX0->m.m.avAxis + 1, &vAxis)) ||
                F(tgCM_NR1)(V(F_DOT)(psBX0->m.m.avAxis + 2, &vAxis))
            )
            {
                continue;
            };

            V(tgGM_ST_Project)(&sAxTest.m_fMin0, &sAxTest.m_fMax0, psST0, &vAxis);
            V(tgGM_BX_Project)(&sAxTest.m_fMin1, &sAxTest.m_fMax1, psBX0, &vAxis);
            sAxTest.m_fSpeed = V(F_DOT)(&vAxis, &psDT->m_vDT);

            iResult = V(tgCO_F_Test_Seperating_Axis)(&sAxTest);
            switch (iResult)
            {
                case  1: /* Update has occurred */
                    if (!V(tgGM_ST_Test_Edge)(psST0, iTriIndex))
                    {
                        fSkipT = fSkipT > sAxTest.m_fMinT ? fSkipT : sAxTest.m_fMinT;
                        break;
                    };

                    psNFO->m_enSide = (sAxTest.m_fMax1 < sAxTest.m_fMin0) ? ETgCO_AXIS_CONTACT_DIRECTION__NEGATIVE : ETgCO_AXIS_CONTACT_DIRECTION__POSITIVE;
                    psNFO->m_vNormal = vAxis;
                    psNFO->m_fMinT = sAxTest.m_fMinT;
                case  0: /* Contact occurred in valid interval, but earlier contact already recorded. */
                    break;
                case -1: /* No contact occurred during valid interval, thus primitives are separated on this axis. */
                    return (KTgE_NO_INTERSECT);
            };
        };
    };

    for (iBoxIndex = 0; iBoxIndex < 3; ++iBoxIndex)
    {
        TYPE                                fAxisLen;

        /* Axis is created by taking the cross product of the triangle edge and a box axis. */

        vAxis = V(F_UCX_LEN)(&fAxisLen, &psDT->m_vDT, psBX0->m.m.avAxis + iBoxIndex);

        if (F(tgCM_NR0)(fAxisLen))
        {
            continue;
        };

        /* Check to see if the resultant normal is approximately the same as that of the triangle normal. If this is the case skip this axis.  This check is primarily to */
        /* aid in contact generation, since a resultant in this context implies an edge-edge contact (1-2 point) instead of the more stable cases (3-4 points). */

        if (
            F(tgCM_NR1)(V(F_DOT)(psBX0->m.m.avAxis + 0, &vAxis)) ||
            F(tgCM_NR1)(V(F_DOT)(psBX0->m.m.avAxis + 1, &vAxis)) ||
            F(tgCM_NR1)(V(F_DOT)(psBX0->m.m.avAxis + 2, &vAxis)) ||
            F(tgCM_NR1)(V(F_DOT)(&psST0->m_sCT.m_sET.m_sPT.m_vNormal, &vAxis))
        )
        {
            continue;
        };

        /* Perform the separation test. */

        V(tgGM_ST_Project)(&sAxTest.m_fMin0, &sAxTest.m_fMax0, psST0, &vAxis);
        V(tgGM_BX_Project)(&sAxTest.m_fMin1, &sAxTest.m_fMax1, psBX0, &vAxis);
        sAxTest.m_fSpeed = V(F_DOT)(&vAxis, &psDT->m_vDT);

        iResult = V(tgCO_F_Test_Seperating_Axis)(&sAxTest);
        switch (iResult)
        {
            case  1: /* Update has occurred */
                psNFO->m_enSide = (sAxTest.m_fMax1 < sAxTest.m_fMin0) ? ETgCO_AXIS_CONTACT_DIRECTION__NEGATIVE : ETgCO_AXIS_CONTACT_DIRECTION__POSITIVE;
                psNFO->m_vNormal = vAxis;
                psNFO->m_fMinT = sAxTest.m_fMinT;
            case  0: /* Contact occurred in valid interval, but earlier contact already recorded. */
                break;
            case -1: /* No contact occurred during valid interval, thus primitives are separated on this axis. */
                return (KTgE_NO_INTERSECT);
        };
    };

    /*  In certain cases, because of feature reduction, the time of contact for an axis is not updated into the return data structure.  If this axis happens to be the */
    /* determining direction for the separation, then contact does not occur.  Specifically, since the return data structure has an earlier time stamp for the contact */
    /* between the triangle and the box, its known that the missing axis represents a separation between the triangle and the box. */

    if (fSkipT >= sAxTest.m_fMinT)
    {
        return (KTgE_NO_INTERSECT);
    };

    return (KTgS_OK);
}