Home

Resume

Blog

Teikitu


/* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
/*  »Project«   Teikitu Gaming System (TgS) (∂)
    »File«      TgS Effect - Client - Effect.c
    »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".                                                   */
/* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
/* == Effects =========================================================================================================================================================== */


/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  External Functions                                                                                                                                                    */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

TgEXTN TgVOID                               tgFX__Client__Group_Add_Child( C_TgFX_DATA_INST_ID, C_TgUINT32, C_TgFX_CLIENT_INST_ID );
TgEXTN TgVOID                               tgFX__Client__Group_On_Kill( C_TgFX_CLIENT_INST_ID, C_TgFX_DATA_INST_ID, C_TgFX_DATA_INST_ID );




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

static TgFX_CLIENT_INST_ID                  tgFX__Client__Inst_FX_Internal( C_ETgFX__EFFECT, CP_TgVOID, C_TgFX_EFFECT_ID, CPCU_STg2_FX_Instance );




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

/* ---- Instance Management --------------------------------------------------------------------------------------------------------------------------------------------- */

/* ---- tgFX__Client__Inst_FX_RAW --------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgFX_CLIENT_INST_ID tgFX__Client__Inst_FX_RAW( C_ETgFX__EFFECT enEffect, CP_TgVOID pData0, CPCU_STg2_FX_Instance psInstance, C_TgBOOL bUseErrorFX )
{
    TgFX_CLIENT_INST_ID                 tiClient;

    TgERROR( nullptr != psInstance );

    if (nullptr != pData0)
    {
        tiClient = tgFX__Client__Inst_FX_Internal( enEffect, pData0, KTgFX_EFFECT_ID__INVALID, psInstance );
        if (TgTRUE == tgFX_CLIENT_INST_ID_Is_Valid( tiClient ))
        {
            return (tiClient);
        };
    };

    if (TgTRUE == bUseErrorFX)
    {
        return (tgFX__Client__Inst_FX( g_tiFX_File_Error, psInstance, TgFALSE ));
    }
    else
    {
        return (KTgFX_CLIENT_INST_ID__INVALID);
    };
}


/* ---- tgFX__Client__Inst_FX_Hash -------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgFX_CLIENT_INST_ID tgFX__Client__Inst_FX_Hash( C_TgUINTXX uiHash, CPCU_STg2_FX_Instance psInstance, C_TgBOOL bUseErrorFX )
{
    TgFX_CLIENT_INST_ID                 tiClient;

    TgERROR( nullptr != psInstance );

    if (KTgEMPTY_HASH != uiHash)
    {
        TgSINT32                            iIndex;
        P_STg2_FX_Data__Effect              psData__Effect;

        /* #PERF: Put the cache list into a unordered set */
        for (iIndex = 0; iIndex < ETgFX_DATA__EFFECT_MAX; ++iIndex)
        {
            if (uiHash != g_auiFX_KN_File__Effect_Hash[iIndex])
            {
                continue;
            };

            psData__Effect = g_asFX_KN_File__Effect + iIndex;
            tiClient = tgFX__Client__Inst_FX_Internal( psData__Effect->m_enEffect, psData__Effect->m_psFile_Data, psData__Effect->m_tiEffect, psInstance );
            if (TgTRUE == tgFX_CLIENT_INST_ID_Is_Valid( tiClient ))
            {
                return (tiClient);
            };
            break;
        };
    };

    if (TgTRUE == bUseErrorFX)
    {
        return (tgFX__Client__Inst_FX( g_tiFX_File_Error, psInstance, TgFALSE ));
    }
    else
    {
        return (KTgFX_CLIENT_INST_ID__INVALID);
    };
}


/* ---- tgFX__Client__Inst_FX ------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgFX_CLIENT_INST_ID tgFX__Client__Inst_FX( C_TgFX_EFFECT_ID tiEffect, CPCU_STg2_FX_Instance psInstance, C_TgBOOL bUseErrorFX )
{
    TgFX_CLIENT_INST_ID                 tiClient;

    TgERROR( nullptr != psInstance );

    if ((TgTRUE == tgFX_EFFECT_ID_Is_Valid( tiEffect )) && (TgTRUE == tgEQ_FX_EFFECT_ID( g_asFX_Cache__Effect[tiEffect.m.iI].m_tiEffect, tiEffect )))
    {
        P_STg2_FX_Data__Effect              psData__Effect;

        psData__Effect = g_asFX_KN_File__Effect + tiEffect.m.iI;
        tiClient = tgFX__Client__Inst_FX_Internal( psData__Effect->m_enEffect, psData__Effect->m_psFile_Data, psData__Effect->m_tiEffect, psInstance );
        if (TgTRUE == tgFX_CLIENT_INST_ID_Is_Valid( tiClient ))
        {
            return (tiClient);
        };
    };

    if (TgTRUE == bUseErrorFX)
    {
        return (tgFX__Client__Inst_FX( g_tiFX_File_Error, psInstance, TgFALSE ));
    }
    else
    {
        return (KTgFX_CLIENT_INST_ID__INVALID);
    };
}


/* ---- tgFX__Client__Stop ---------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID tgFX__Client__Stop( C_TgFX_CLIENT_INST_ID tiClient )
{
    TgSINT32                            iIndex;
    STg2_FX_Command__Update__NoParam    sCommand;

    iIndex = tgFX__Client__Get_Client_Index( tiClient );
    if (0 > iIndex)
    {
        return;
    };

    sCommand.m_enCommand = ETgFX_COMMAND__CLIENT_TO_UPDATE__STOP;
    sCommand.m_sDest.m_tiData = g_asFX_Effect[iIndex].m_tiData;
    tgFX__Client__Queue_Update_Command( g_asFX_Effect[iIndex].m_enEffect, sCommand.m_enCommand, &sCommand );
}


/* ---- tgFX__Client__Kill ---------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID tgFX__Client__Kill( C_TgFX_CLIENT_INST_ID tiClient )
{
    TgSINT32                            iIndex;
    STg2_FX_Command__Update__NoParam    sCommand;

    iIndex = tgFX__Client__Get_Client_Index( tiClient );
    if (0 > iIndex)
    {
        return;
    };

    sCommand.m_enCommand = ETgFX_COMMAND__CLIENT_TO_UPDATE__KILL;
    sCommand.m_sDest.m_tiData = g_asFX_Effect[iIndex].m_tiData;
    tgFX__Client__Queue_Update_Command( g_asFX_Effect[iIndex].m_enEffect, sCommand.m_enCommand, &sCommand );
}


/* ---- tgFX__Client__Kill_All ------------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID tgFX__Client__Kill_All( P_TgUINT32 puiNotify_Flag )
{
    TgSINT32                            iIndex;

    for (iIndex = 0; iIndex < KTgFX_MAX_EFFECT_INSTANCE; ++iIndex)
    {
        if (ETgFX_EFFECT_STATE__CLIENT__FREE != g_aiFX__Client__Shared_State[iIndex])
        {
            tgFX__Client__Kill( g_asFX_Effect[iIndex].m_tiClient );
        }
    }

    if (0 != puiNotify_Flag)
    {
        STg2_FX_Command__Notify             sCommand;

        sCommand.m_enCommand = ETgFX_COMMAND__CLIENT_TO_UPDATE__NOTIFY;
        sCommand.m_uiMessage = ETgFX_NOTIFY__FRAME_COMPLETE;
        sCommand.m_pNotify = puiNotify_Flag;
        tgFX__Client__Queue_Update_Command( ETgFX__INVALID, sCommand.m_enCommand, &sCommand );
    }
}

/* ---- Accessors ------------------------------------------------------------------------------------------------------------------------------------------------------- */

/* ---- tgFX__Client__Set_Callback_Terminate ---------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID tgFX__Client__Set_Callback_Terminate( C_TgFX_CLIENT_INST_ID tiClient, TgFCN_CB_ON_TERMINATE pfnTerminate, C_TgUINTPTR uiTerminate_Parameter )
{
    TgSINT32                            iIndex;

    iIndex = tgFX__Client__Get_Client_Index( tiClient );
    if (0 > iIndex)
    {
        return;
    };

    g_asFX_Effect[iIndex].m_pfnTerminate = pfnTerminate;
    g_asFX_Effect[iIndex].m_uiTerminate_Parameter = uiTerminate_Parameter;
}


/* ---- tgFX__Client__Set_Callback_Contact ------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID tgFX__Client__Set_Callback_Contact( C_TgFX_CLIENT_INST_ID tiClient, TgFCN_CB_ON_CONTACT pfnContact, C_TgUINTPTR uiContact_Parameter )
{
    TgSINT32                            iIndex;

    iIndex = tgFX__Client__Get_Client_Index( tiClient );
    if (0 > iIndex)
    {
        return;
    };

    g_asFX_Effect[iIndex].m_pfnContact = pfnContact;
    g_asFX_Effect[iIndex].m_uiContact_Parameter = uiContact_Parameter;
}


/* ---- tgFX__Client__Set_Visible --------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID tgFX__Client__Set_Visible( C_TgFX_CLIENT_INST_ID tiClient, C_TgBOOL bVisible )
{
    TgSINT32                            iIndex;
    TgUINT32                            uiVisible;
    STg2_FX_Command__Update__1_UXX      sCommand;

    iIndex = tgFX__Client__Get_Client_Index( tiClient );
    if (0 > iIndex)
    {
        return;
    };

    uiVisible = TgTRUE == bVisible ? 1 : 0;
    if (0 != (g_asFX_Effect[iIndex].m_uiRender_Visible ^ uiVisible))
    {
        return;
    };

    g_asFX_Effect[iIndex].m_uiRender_Visible = uiVisible;

    sCommand.m_enCommand = ETgFX_COMMAND__CLIENT_TO_UPDATE__VISIBLE;
    sCommand.m_sDest.m_tiData = g_asFX_Effect[iIndex].m_tiData;
    sCommand.m_uiVal = TgTRUE == bVisible ? 1 : 0;
    tgFX__Client__Queue_Update_Command( g_asFX_Effect[iIndex].m_enEffect, sCommand.m_enCommand, &sCommand );
}


/* ---- tgFX__Client__Is_Attached --------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgBOOL tgFX__Client__Is_Attached( C_TgFX_CLIENT_INST_ID tiClient )
{
    TgSINT32                            iIndex;

    iIndex = tgFX__Client__Get_Client_Index( tiClient );
    if (0 > iIndex)
    {
        return (TgFALSE);
    };

    return (tgATTACHMENT_ID_Is_Valid( g_asFX_Effect[iIndex].m_tiAttachment ));
}


/* ---- tgFX__Client__Is_Valid ------------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgBOOL tgFX__Client__Is_Valid( C_TgFX_CLIENT_INST_ID tiClient )
{
    TgSINT32                            iIndex;

    iIndex = tgFX__Client__Get_Client_Index( tiClient );
    if (0 > iIndex)
    {
        return (TgFALSE);
    };

    if (TgTRUE != tgFX_DATA_INST_ID_Is_Valid( g_asFX_Effect[tiClient.m.iI].m_tiData ))
    {
        return (TgFALSE);
    };

    return (TgTRUE);
}




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

/* ---- tgFX__Client__Get_Client_Index ---------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgSINT32 tgFX__Client__Get_Client_Index( C_TgFX_CLIENT_INST_ID tiClient )
{
    if (TgTRUE != tgFX_CLIENT_INST_ID_Is_Valid( tiClient ))
    {
        return -1;
    };

    TgERROR_INDEX( tiClient.m.iI, g_asFX_Effect );

    if (TgFALSE == tgEQ_FX_CLIENT_INST_ID( tiClient, g_asFX_Effect[tiClient.m.iI].m_tiClient ))
    {
        return -1;
    };

    TgERROR( g_aiFX__Client__Shared_State[tiClient.m.iI] >= ETgFX_EFFECT_STATE__CLIENT__ACTIVE );
    return (tiClient.m.iI);
}


/* ---- tgFX__Client__Free_Internal ------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID tgFX__Client__Free_Internal( C_TgSINT32 iIndex )
{
    P_STg2_FX__Client                   psEffect;
    TgFX_EFFECT_ID                 tiEffect;
    P_STg2_FX__Client                   psParent;

    TgPARAM_CHECK( g_aiFX__Client__Shared_State[iIndex] >= ETgFX_EFFECT_STATE__CLIENT__ACTIVE );
    
    psEffect = g_asFX_Effect + iIndex;
    tiEffect = psEffect->m_tiEffect;
    psParent = nullptr;

    /* Termination call back is executed first (in case there is any necessary data read back) */
    if (nullptr != psEffect->m_pfnTerminate)
    {
        (*psEffect->m_pfnTerminate)(psEffect->m_tiClient, psEffect->m_uiTerminate_Parameter);
    };

    do
    {
        TgFX_DATA_INST_ID                   tiData;

        if (TgTRUE != tgFX_CLIENT_INST_ID_Is_Valid( psEffect->m_tiParent ))
        {
            break;
        };
        if (g_asFX_Effect[psEffect->m_tiParent.m.iI].m_tiClient.m_iKI != psEffect->m_tiParent.m_iKI)
        {
            break;
        };
        psParent = g_asFX_Effect + psEffect->m_tiParent.m.iI;
        if (ETgFX__GROUP != psParent->m_enEffect)
        {
            psParent = nullptr;
            break;
        }
        tiData = ETgFX__GROUP == psEffect->m_enEffect ? psEffect->m_tiData : KTgFX_DATA_INST_ID__INVALID;
        tgFX__Client__Group_On_Kill( psEffect->m_tiClient, tiData, psParent->m_tiData );
    }
    while(0);

    if ((nullptr == psParent) && (ETgFX__GROUP == psEffect->m_enEffect))
    {
        tgFX__Client__Group_On_Kill( psEffect->m_tiClient, psEffect->m_tiData, KTgFX_DATA_INST_ID__INVALID );
    };

    /* Tear down the effect and mark it for delete (invalidate the client id) */
    psEffect->m_tiData = KTgFX_DATA_INST_ID__INVALID;
    psEffect->m_tiClient = KTgFX_CLIENT_INST_ID__INVALID;
    psEffect->m_tiParent = KTgFX_CLIENT_INST_ID__INVALID;
    if (tgATTACHMENT_ID_Is_Valid( psEffect->m_tiAttachment ))
    {
        tgAttachment__Decrement_Reference( psEffect->m_tiAttachment );
        psEffect->m_tiAttachment = KTgATTACHMENT_ID__INVALID;
    };
    psEffect->m_tiTarget = KTgRN_TARGET_ID__INVALID;
    psEffect->m_pfnTerminate = nullptr;
    psEffect->m_pfnContact = nullptr;
    psEffect->m_enEffect = ETgFX__INVALID;
    psEffect->m_iPriority = 0;
    psEffect->m_tiEffect = KTgFX_EFFECT_ID__INVALID;
    psEffect->m_uiUpdate = 0;
    psEffect->m_uiRender_Visible = 0;

    g_aiFX__Client__Shared_State[iIndex] = ETgFX_EFFECT_STATE__CLIENT__FREE;

    tgFX_Effect__Decrement_Reference( tiEffect );
}


/* ---- tgFX__Client__Set_Position_From_External_Update ----------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID tgFX__Client__Set_Position_From_External_Update( C_TgFX_CLIENT_INST_ID tiClient, TgVEC_M_F32_04 vPos_W )
{
    TgSINT32                            iIndex;
    STg2_FX_Command__Update__1_F32_04   sCommand;

    iIndex = tgFX__Client__Get_Client_Index( tiClient );
    if (0 > iIndex)
    {
        return;
    };

    sCommand.m_enCommand = ETgFX_COMMAND__CLIENT_TO_UPDATE__POSITION_SET;
    sCommand.m_sDest.m_tiData = g_asFX_Effect[iIndex].m_tiData;
    sCommand.m_vF32_04.m_mData = vPos_W;
    tgFX__Client__Queue_Update_Command( g_asFX_Effect[iIndex].m_enEffect, sCommand.m_enCommand, &sCommand );
}


/* ---- tgFX__Client__Set_Rotation_From_External_Update ----------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID tgFX__Client__Set_Rotation_From_External_Update( C_TgFX_CLIENT_INST_ID tiClient, TgVEC_M_F32_04 qRot_W )
{
    TgSINT32                            iIndex;
    STg2_FX_Command__Update__1_F32_04   sCommand;

    iIndex = tgFX__Client__Get_Client_Index( tiClient );
    if (0 > iIndex)
    {
        return;
    };

    sCommand.m_enCommand = ETgFX_COMMAND__CLIENT_TO_UPDATE__ROTATION_SET;
    sCommand.m_sDest.m_tiData = g_asFX_Effect[iIndex].m_tiData;
    sCommand.m_vF32_04.m_mData = qRot_W;
    tgFX__Client__Queue_Update_Command( g_asFX_Effect[iIndex].m_enEffect, sCommand.m_enCommand, &sCommand );
}


/* ---- tgFX__Client__Update_Position_From_Parent ----------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID tgFX__Client__Update_Position_From_Parent( C_TgFX_CLIENT_INST_ID tiClient, TgVEC_M_F32_04 vPos_W )
{
    TgSINT32                            iIndex;
    STg2_FX_Command__Update__1_F32_04   sCommand;

    iIndex = tgFX__Client__Get_Client_Index( tiClient );
    if (0 > iIndex)
    {
        return;
    };

    sCommand.m_enCommand = ETgFX_COMMAND__CLIENT_TO_UPDATE__POSITION_UPDATE_FROM_PARENT;
    sCommand.m_sDest.m_tiData = g_asFX_Effect[iIndex].m_tiData;
    sCommand.m_vF32_04.m_mData = vPos_W;
    tgFX__Client__Queue_Update_Command( g_asFX_Effect[iIndex].m_enEffect, sCommand.m_enCommand, &sCommand );
}


/* ---- tgFX__Client__Update_Rotation_From_Parent ----------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID tgFX__Client__Update_Rotation_From_Parent( C_TgFX_CLIENT_INST_ID tiClient, TgVEC_M_F32_04 qRot_W )
{
    TgSINT32                            iIndex;
    STg2_FX_Command__Update__1_F32_04   sCommand;

    iIndex = tgFX__Client__Get_Client_Index( tiClient );
    if (0 > iIndex)
    {
        return;
    };

    sCommand.m_enCommand = ETgFX_COMMAND__CLIENT_TO_UPDATE__ROTATION_UPDATE_FROM_PARENT;
    sCommand.m_sDest.m_tiData = g_asFX_Effect[iIndex].m_tiData;
    sCommand.m_vF32_04.m_mData = qRot_W;
    tgFX__Client__Queue_Update_Command( g_asFX_Effect[iIndex].m_enEffect, sCommand.m_enCommand, &sCommand );
}




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

/* ---- tgFX__Client__Inst_FX_Internal ---------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
static TgFX_CLIENT_INST_ID tgFX__Client__Inst_FX_Internal( C_ETgFX__EFFECT enEffect, CP_TgVOID pData0, C_TgFX_EFFECT_ID tiEffect, CPCU_STg2_FX_Instance psInstance )
{
    P_STg2_FX__Client                   psEffect;
    TgFX_DATA_INST_ID                   tiParent;
    TgSINT32                            iEffect_Index;

    /* Check to see if our parent is a group, and so need to ourselves to it as a child */
    tiParent = KTgFX_DATA_INST_ID__INVALID;
    do
    {
        P_STg2_FX__Client                   psParent;

        if (0 == (psInstance->m_uiInternal & 0xFF))
        {
            break;
        };
        if (TgTRUE != tgFX_CLIENT_INST_ID_Is_Valid( psInstance->m_tiParent ))
        {
            break;
        };
        if (g_asFX_Effect[psInstance->m_tiParent.m.iI].m_tiClient.m_iKI != psInstance->m_tiParent.m_iKI)
        {
            break;
        };
        psParent = g_asFX_Effect + psInstance->m_tiParent.m.iI;
        if (ETgFX__GROUP != psParent->m_enEffect)
        {
            break;
        };
        tiParent = psParent->m_tiData;
    }
    while(0);

    psEffect = (P_STg2_FX__Client)tgCM_UTM_AM_ST_Pop( &g_sFX_Effect__Client__Effect.m_sStack );
    if (nullptr == psEffect)
    {
        return (KTgFX_CLIENT_INST_ID__INVALID);
    };

    iEffect_Index = (TgSINT32)(psEffect - g_asFX_Effect);
    tgInit_FX_CLIENT_INST_ID( &psEffect->m_tiClient, iEffect_Index );
    g_aiFX__Client__Shared_State[iEffect_Index] = ETgFX_EFFECT_STATE__CLIENT__RESERVED;

    switch (enEffect)
    {
        case ETgFX__BEAM:      psEffect->m_tiData = tgFX__Client__Beam_Create_Data_Inst( psEffect->m_tiClient, pData0, psInstance ); break;
        case ETgFX__BILLBOARD: psEffect->m_tiData = tgFX__Client__Billboard_Create_Data_Inst( psEffect->m_tiClient, pData0, psInstance ); break;
        case ETgFX__DECAL:     psEffect->m_tiData = tgFX__Client__Decal_Create_Data_Inst( psEffect->m_tiClient, pData0, psInstance ); break;
        case ETgFX__EMITTER:   psEffect->m_tiData = tgFX__Client__Emitter_Create_Data_Inst( psEffect->m_tiClient, pData0, psInstance ); break;
        case ETgFX__GIB:       psEffect->m_tiData = tgFX__Client__GIB_Create_Data_Inst( psEffect->m_tiClient, pData0, psInstance ); break;
        case ETgFX__GLASS:     psEffect->m_tiData = tgFX__Client__Glass_Create_Data_Inst( psEffect->m_tiClient, pData0, psInstance ); break;
        case ETgFX__GROUP:     psEffect->m_tiData = tgFX__Client__Group_Create_Data_Inst( psEffect->m_tiClient, pData0, psInstance ); break;
        case ETgFX__LIGHT:     psEffect->m_tiData = tgFX__Client__Light_Create_Data_Inst( psEffect->m_tiClient, pData0, psInstance ); break;
        case ETgFX__LIQUID:    psEffect->m_tiData = tgFX__Client__Liquid_Create_Data_Inst( psEffect->m_tiClient, pData0, psInstance ); break;
        case ETgFX__POST:      psEffect->m_tiData = tgFX__Client__Post_Create_Data_Inst( psEffect->m_tiClient, pData0, psInstance ); break;
        case ETgFX__SOUND:     psEffect->m_tiData = tgFX__Client__Sound_Create_Data_Inst( psEffect->m_tiClient, pData0, psInstance ); break;
        case ETgFX__TRAIL:     psEffect->m_tiData = tgFX__Client__Trail_Create_Data_Inst( psEffect->m_tiClient, pData0, psInstance ); break;

        case ETgFX__INVALID:
        case ETgFX__EFFECT_MAX:
        default: TgS_NO_DEFAULT(break);
    };

    if (TgTRUE != tgFX_DATA_INST_ID_Is_Valid( psEffect->m_tiData ))
    {
        psEffect->m_tiClient = KTgFX_CLIENT_INST_ID__INVALID;
        g_aiFX__Client__Shared_State[iEffect_Index] = ETgFX_EFFECT_STATE__CLIENT__FREE;
        tgAM_WRITE_FENCE();

        tgCM_UTM_AM_ST_Push( &g_sFX_Effect__Client__Effect.m_sStack, (P_STg2_UTM_Node)psEffect );
        return (KTgFX_CLIENT_INST_ID__INVALID);
    };

    if (TgFALSE != tgFX_EFFECT_ID_Is_Valid( tiEffect ))
    {
        tgFX_Effect__Increment_Reference( tiEffect );
    };

    if (TgFALSE != tgFX_CLIENT_INST_ID_Is_Valid( psInstance->m_tiParent ))
    {
        TgERROR_INDEX( psInstance->m_tiParent.m.iI, g_asFX_Effect );
        psEffect->m_tiTarget = g_asFX_Effect[psInstance->m_tiParent.m.iI].m_tiTarget;
        psEffect->m_uiRender_Visible = g_asFX_Effect[psInstance->m_tiParent.m.iI].m_uiRender_Visible;
    }
    else
    {
        psEffect->m_tiTarget = psInstance->m_tiTarget;
        psEffect->m_uiRender_Visible = TgTRUE == psInstance->m_uiRender_Visible ? 1: 0;
    };
    
    /* Check for attachment and add effect into the client update list appropriately */
    psEffect->m_uiUpdate = ETgFX_UPDATE__DEFAULT;
    if (0 != (psInstance->m_uiInternal & (ETgFX_UPDATE__EXTERNAL << 8)) || (TgTRUE != tgATTACHMENT_ID_Is_Valid( psInstance->m_tiAttachment )))
        psEffect->m_uiUpdate = ETgFX_UPDATE__EXTERNAL;
    psEffect->m_tiAttachment = psInstance->m_tiAttachment;

    psEffect->m_tiUpdate_Next = g_atiFX__Client__Update__Head[ETgFX_UPDATE__NEW_CLIENT];
    g_atiFX__Client__Update__Head[ETgFX_UPDATE__NEW_CLIENT] = psEffect->m_tiClient;

    psEffect->m_tiParent = psInstance->m_tiParent;
    psEffect->m_pfnTerminate = psInstance->m_pfnTerminate;
    psEffect->m_uiTerminate_Parameter = psInstance->m_uiTerminate_Parameter;
    psEffect->m_pfnContact = psInstance->m_pfnContact;
    psEffect->m_uiContact_Parameter = psInstance->m_uiContact_Parameter;
    psEffect->m_enEffect = enEffect;
    psEffect->m_iPriority = psInstance->m_iPriority;
    psEffect->m_tiEffect = tiEffect;

    g_aiFX__Client__Shared_State[iEffect_Index] = ETgFX_EFFECT_STATE__CLIENT__ACTIVE;

    if (TgFALSE != tgFX_DATA_INST_ID_Is_Valid( tiParent ))
    {
        tgFX__Client__Group_Add_Child( tiParent, (psInstance->m_uiInternal & 0xFF), psEffect->m_tiClient );
    }

    return (psEffect->m_tiClient);
}