Home

Resume

Blog

Teikitu


/* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
/*  »Project«   Teikitu Gaming System (TgS) (∂)
    »File«      TgS Collision - F - System.c_inc
    »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 ========================================================================================================================================================= */

/*   Large switch statements are known to be particularly bad on the in-order CPUs in the current consoles.  However, all other methods would be equivalent.  Possible    */
/* solutions that were debated (not tested): (1) Function pointers - this would require the retrieval of the pointer and then a jump to the function.  Since jumps are    */
/* near-equivalent to a branch, nothing is gained.  (2) Virtual tables - at a compiler/machine level this is the same as (1).                                             */

/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  File Local Functions and Data                                                                                                                                         */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

static TgVOID                               V(tgCO_REQ_Copy_Common)( V(PC_STg2_CO_Request), V(CPC_STg2_CO_Request) );
TgINLINE TgVOID                             V(tgCO_REQ_Set_Owns_Data)( V(PC_STg2_CO_Request), C_TgBOOL );
TgINLINE TgBOOL                             V(tgCO_REQ_Query_Owns_Data)( V(PC_STg2_CO_Request) );




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

/* ---- V(tgCO_REQ_Ignore_Connection) ----------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT V(tgCO_REQ_Ignore_Connection)( V(PC_STg2_CO_Request) psRequest, PC_STg2_Connection psConnection, C_TgBOOL bFlag )
{
    C_TgSINT32                          niMax = psRequest->m_niConnection_Ignored;
    TgSINT32                            iIndex;

    TgPARAM_CHECK( nullptr != psRequest && nullptr != psConnection );

    /* Check to see if the object is in the ignore list. */
    for (iIndex = 0; iIndex < niMax; ++iIndex)
    {
        if (psRequest->m_apsConnection_Ignored[iIndex] != psConnection)
        {
            continue;
        };

        if (!bFlag)
        {
            if (iIndex + 1 != niMax)
            {
                psRequest->m_apsConnection_Ignored[iIndex] = psRequest->m_apsConnection_Ignored[niMax - 1];
            };

            --psRequest->m_niConnection_Ignored;
        };

        return (KTgS_OK);
    };

    if (niMax >= KTgCO_REQUEST__MAX_IGNORE || TgFALSE == bFlag)
    {
        return (KTgE_FAIL);
    };

    psRequest->m_apsConnection_Ignored[psRequest->m_niConnection_Ignored++] = psConnection;
    return (KTgS_OK);
}


/* ---- V(tgCO_REQ_Ignore_Connection_Graph) ----------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT V(tgCO_REQ_Ignore_Connection_Graph)( V(PC_STg2_CO_Request) psRequest, PC_STg2_Connection psConnection, C_TgBOOL bFlag )
{
    C_TgSINT32                          niMax = psRequest->m_niConnection_Graph_Ignored;
    TgSINT32                            iIndex;

    TgPARAM_CHECK( nullptr != psRequest && nullptr != psConnection );

    /* Check to see if the object is in the ignore list. */
    for (iIndex = 0; iIndex < niMax; ++iIndex)
    {
        if (psRequest->m_apsConnection_Graph_Ignored[iIndex] != psConnection)
        {
            continue;
        };

        if (!bFlag)
        {
            if (iIndex + 1 != niMax)
            {
                psRequest->m_apsConnection_Graph_Ignored[iIndex] = psRequest->m_apsConnection_Graph_Ignored[niMax - 1];
            };

            --psRequest->m_niConnection_Graph_Ignored;
        };

        return (KTgS_OK);
    };

    if (niMax >= KTgCO_REQUEST__MAX_IGNORE || TgFALSE == bFlag)
    {
        return (KTgE_FAIL);
    };

    psRequest->m_apsConnection_Graph_Ignored[psRequest->m_niConnection_Graph_Ignored++] = psConnection;
    return (KTgS_OK);
}


/* ---- V(tgCO_REQ_Ignore_Native_String) -------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT V(tgCO_REQ_Ignore_Native_String)( V(PC_STg2_CO_Request) psRequest, C_TgSINT32 nsVal, C_TgBOOL bFlag )
{
    C_TgSINT32                          niMax = psRequest->m_niNative_String;
    TgSINT32                            iIndex;

    if (KTgUID_NONE == nsVal)
    {
        return (KTgE_FAIL);
    };

    /* Check to see if the object is in the ignore list. */
    for (iIndex = 0; iIndex < niMax; ++iIndex)
    {
        if (psRequest->m_aiNative_String[iIndex] != nsVal)
        {
            continue;
        };

        if (!bFlag)
        {
            if (iIndex + 1 != niMax)
            {
                psRequest->m_aiNative_String[iIndex] = psRequest->m_aiNative_String[niMax - 1];
            };

            --psRequest->m_niNative_String;
        };

        return (KTgS_OK);
    };

    if (niMax >= KTgCO_REQUEST__MAX_IGNORE || TgFALSE == bFlag)
    {
        return (KTgE_FAIL);
    };

    psRequest->m_aiNative_String[psRequest->m_niNative_String++] = nsVal;
    return (KTgS_OK);
}


/* ---- V(tgCO_REQ_Is_Ignored_Connection) ------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgBOOL V(tgCO_REQ_Is_Ignored_Connection)(V(CPC_STg2_CO_Request) psRequest, CPC_STg2_Connection psConnection)
{
    TgSINT32                            iIndex;

    TgPARAM_CHECK( nullptr != psRequest && nullptr != psConnection );

    /* Check to see if all objects are being ignored. */
    if (V(tgCO_REQ_Is_Ignored_All)(psRequest))
    {
        return (TgTRUE);
    };

    /* Check to see if the object is in the ignore list. */
    for (iIndex = 0; iIndex < psRequest->m_niConnection_Ignored; ++iIndex)
    {
        if (psRequest->m_apsConnection_Ignored[iIndex] == psConnection)
        {
            return (TgTRUE);
        };
    };

    /* Not ignored. */
    return (TgFALSE);
}


/* ---- V(tgCO_REQ_Is_Ignored_Native_String) ---------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgBOOL V(tgCO_REQ_Is_Ignored_Native_String)(V(CPC_STg2_CO_Request) psRequest, C_TgSINT32 nsVal)
{
    TgSINT32                            iIndex;

    TgPARAM_CHECK( nullptr != psRequest && KTgUID_NONE != nsVal );

    /* Check to see if all objects are being ignored. */
    if (V(tgCO_REQ_Is_Ignored_All)(psRequest))
    {
        return (TgTRUE);
    };

    /* Check to see if the object is in the ignore list. */
    for (iIndex = 0; iIndex < psRequest->m_niNative_String; ++iIndex)
    {
        if (psRequest->m_aiNative_String[iIndex] == nsVal)
        {
            return (TgTRUE);
        };
    };

    /* Not ignored. */
    return (TgFALSE);
}


/* ---- V(tgCO_REQ_Reset) ----------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID V(tgCO_REQ_Reset)(V(PC_STg2_CO_Request) psRequest)
{
    if (V(tgCO_REQ_Query_Owns_Data)(psRequest))
    {
        TgFREE_POOL( psRequest->m_psResult );
    };

    memset( psRequest, 0, sizeof( V(STg2_CO_Request) ) );

    psRequest->m_sPacket.m_psContact = psRequest->m_asContact;
    psRequest->m_sPacket.m_fSweepTol = F(KTgROOT_EPS);
    psRequest->m_sPacket.m_fSnapTol = F(KTgEPS);
    psRequest->m_sPacket.m_niMaxContact = 8;

    psRequest->m_psResult = psRequest->m_asInternal_Result;
    psRequest->m_niResult_End = KTgCO_REQUEST__INTERNAL_RESULTS;
}


/* ---- V(tgCO_REQ_F_TX) ------------------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID  V(tgCO_REQ_F_TX)( V(PC_STg2_CO_Request) psRequest, M34(CPC_TgMAT) pxM0 )
{
    TgSINT32                            iIndex;

    V(tgGM_DT_TX)( &psRequest->m_sDT, pxM0 );

    for (iIndex = 0; iIndex < psRequest->m_niResult_Last; ++iIndex)
    {
        psRequest->m_psResult[iIndex].m_sContact.m_vS0 = M34(F_TX_P)( pxM0, &psRequest->m_psResult[iIndex].m_sContact.m_vS0 );
        psRequest->m_psResult[iIndex].m_sContact.m_vN0 = M34(F_TX_V)( pxM0, &psRequest->m_psResult[iIndex].m_sContact.m_vN0 );
        V(tgGM_PT_TX)( &psRequest->m_psResult[iIndex].m_sPT, pxM0 );
    };
}


/* ---- V(tgCO_REQ_F_Copy_TX) ------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID  V(tgCO_REQ_F_Copy_TX)( V(PC_STg2_CO_Request) psDest, V(CPC_STg2_CO_Request) psSrc, M34(CPC_TgMAT) pxM0 )
{
    TgSINT32                            iIndex;

    V(tgCO_REQ_Reset)( psDest );
    V(tgCO_REQ_Copy_Common)( psDest, psSrc );

    V(tgGM_DT_Copy_TX)( &psDest->m_sDT, &psSrc->m_sDT, pxM0 );

    for (iIndex = 0; iIndex < psSrc->m_niResult_Last; ++iIndex)
    {
        psDest->m_psResult[iIndex].m_sContact.m_vS0 = M34(F_TX_P)( pxM0, &psSrc->m_psResult[iIndex].m_sContact.m_vS0 );
        psDest->m_psResult[iIndex].m_sContact.m_vN0 = M34(F_TX_V)( pxM0, &psSrc->m_psResult[iIndex].m_sContact.m_vN0 );
        V(tgGM_PT_Copy_TX)( &psDest->m_psResult[iIndex].m_sPT, &psSrc->m_psResult[iIndex].m_sPT, pxM0 );
    };
}




/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  Private Functions                                                                                                                                                     */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

/* ---- V(tgCO_REQ_Next_Result) ----------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
V(P_STg2_CO_Result) V(tgCO_REQ_Next_Result)( V(PC_STg2_CO_Request) psRequest, V(CPC_TgVEC) pvS0, V(CPC_TgVEC) pvNormal, const TYPE fValue )
{
    TgSINT32                            niCount;
    V(TgVEC)                            vK0;

    for (niCount = 0; niCount < psRequest->m_niResult_Last; ++niCount)
    {
        vK0 = V(F_SUB)( pvS0, &psRequest->m_psResult[niCount].m_sContact.m_vS0 );
        if (V(F_LSQ)( &vK0 ) > F(KTgROOT_EPS))
        {
            continue;
        };

        vK0 = V(F_SUB)( pvNormal, &psRequest->m_psResult[niCount].m_sContact.m_vN0 );
        if (V(F_LSQ)( &vK0 ) > F(KTgROOT_EPS))
        {
            continue;
        };

        return (psRequest->m_psResult + niCount);
    };

    if (psRequest->m_niResult_Last < psRequest->m_niResult_End)
    {
        return (psRequest->m_psResult + psRequest->m_niResult_Last++);
    };

    if (tgBF_Query_Flag_U32( &psRequest->m_bfFlags, ETgCO_FLAGS_NO_SORT ))
    {
        return (nullptr);
    };

    if (tgBF_Query_Flag_U32( &psRequest->m_bfFlags, ETgCO_FLAGS_ORDER_PARAMETER ))
    {
        /* When sorting on depth, find the value closest to zero, and replace that entry. */

        TYPE                                fTMP = psRequest->m_psResult[0].m_sContact.m_fDepth;
        TgSINT32                            niCurrent = 0;

        for (niCount = 1; niCount < psRequest->m_niResult_End; ++niCount)
        {
            if (fTMP > psRequest->m_psResult[niCount].m_sContact.m_fDepth)
            {
                fTMP = psRequest->m_psResult[niCount].m_sContact.m_fDepth;
                niCurrent = niCount;
            };
        };

        return (fTMP > fValue ? nullptr : psRequest->m_psResult + niCurrent);
    }
    else
    {
        /* When sorting on time, find the value furthest from zero, and replace that entry. */

        TYPE                                fTMP = psRequest->m_psResult[0].m_sContact.m_fT0;
        TgSINT32                            niCurrent = 0;

        for (niCount = 1; niCount < psRequest->m_niResult_End; ++niCount)
        {
            if (fTMP < psRequest->m_psResult[niCount].m_sContact.m_fT0)
            {
                fTMP = psRequest->m_psResult[niCount].m_sContact.m_fT0;
                niCurrent = niCount;
            };
        };

        return (fTMP < fValue ? nullptr : psRequest->m_psResult + niCurrent);
    };
}




/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  File Local Functions and Data                                                                                                                                         */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

/* ---- V(tgCO_REQ_Copy_Common) ----------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
static TgVOID V(tgCO_REQ_Copy_Common)( V(PC_STg2_CO_Request) psDest, V(CPC_STg2_CO_Request) psSrc )
{
    V(P_STg2_CO_Result)                 psResult;
    TgSINT32                            niResult_End;
    TgBOOL                              bOwnsData = V(tgCO_REQ_Query_Owns_Data)(psDest);

    /* If there is a result size mismatch, free the current buffer and create a new buffer */
    if (psDest->m_niResult_End < psSrc->m_niResult_End)
    {
        if (bOwnsData)
        {
            TgFREE_POOL( psDest->m_psResult );
        };

        psResult = TgMALLOC_POOL( (TgSIZE)psSrc->m_niResult_End * sizeof( V(STg2_CO_Result) ) );
        niResult_End = psSrc->m_niResult_End;
        bOwnsData = TgTRUE;
    }
    else
    {
        psResult = psDest->m_psResult;
        niResult_End = psDest->m_niResult_End;
    }

    /* Copy the data */
    memcpy( psDest, psSrc, sizeof( V(STg2_CO_Request) ) );

    /* Reassign the buffer */
    psDest->m_psResult = psResult;
    psDest->m_niResult_End = niResult_End;
    V(tgCO_REQ_Set_Owns_Data)(psDest, bOwnsData);

    /* Copy the results */
    memcpy( psResult, psSrc->m_psResult, (TgSIZE)psSrc->m_niResult_Last*sizeof( V(P_STg2_CO_Result) ) );
    psDest->m_niResult_Last = psSrc->m_niResult_Last;
}


/* ---- V(tgCO_REQ_Set_Owns_Data) --------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgINLINE TgVOID V(tgCO_REQ_Set_Owns_Data)( V(PC_STg2_CO_Request) psRequest, C_TgBOOL bFlag )
{
    tgBF_Set_Flag_U32( &psRequest->m_bfFlags, ETgCO_FLAGS_OWNS_DATA, bFlag );
}


/* ---- V(tgCO_REQ_Query_Owns_Data) ------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgINLINE TgBOOL V(tgCO_REQ_Query_Owns_Data)( V(PC_STg2_CO_Request) psRequest )
{
    return (tgBF_Query_Flag_U32( &psRequest->m_bfFlags, ETgCO_FLAGS_OWNS_DATA ));
}