Home

Resume

Blog

Teikitu


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


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

static TgBOOL                               T_NAME(tgFX__Update__, _Create_Command)( CP_STg2_FX_Instance, C_TgFX_DATA_INST_ID, CP_TgVOID );
static TgVOID                               T_NAME(tgFX__Update__, _Update)( TgVEC_M_F32_04, C_TgFLOAT32, C_ETgFX_UPDATE );
#if T_EFFECT_PROCESS_COMMMAND
static TgVOID                               T_NAME(tgFX__Update__, _Process_Update_Command)( C_ETgFX_COMMAND, CP_TgVOID, C_TgFX_DATA_INST_ID );
#endif




/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  External Functions and Data                                                                                                                                           */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

TgEXTN ETgFX_EFFECT_STATE                   T_NAME(g_aenFX__, __Shared__State)[T_TYPE(KTgFX_MAX_,)];
TgEXTN STg2_UTM_AM_ST_ISO                   T_NAME(g_sFX__, __Client__Stack);
TgEXTN T_NAME(STg2_FX__,)                   T_NAME(g_asFX__,)[T_TYPE(KTgFX_MAX_,)];
TgEXTN TgUINT08                             T_NAME(g_asFX_Command__, __ToClient)[ETgFX_COMMAND__TO_CLIENT__BYTE_MAX];
TgEXTN volatile TgATOMIC_UINTXX             T_NAME(g_uiFX_Command__, __ToClient_Offset);




/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  Exported Functions                                                                                                                                                    */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

TgEXTN TgVOID                               T_NAME(tgFX__Client__, _Init_Update)( TgVOID );
TgEXTN TgVOID                               T_NAME(tgFX__Client__, _Boot_Update)( TgVOID );

TgEXTN TgFX_DATA_INST_ID                    T_NAME(tgFX__, _Query_Effect_Update_Head)( C_ETgFX_UPDATE );
TgEXTN TgSIZE                               T_NAME(tgFX__Update__, _Process_Update_Command_Buffer)( CP_TgUINT08, TgSIZE );
TgEXTN P_TgUINT08                           T_NAME(tgFX_, __Reserve_Update_Command)( C_ETgFX_COMMAND );




/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  Profile Markers                                                                                                                                                       */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

static PROFILE_ARRAY_DEFINE( ETgFX_UPDATE__MAX + 1, T_TYPE(FX_, _UPDATE__UPDATE) );




/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  File Local Type                                                                                                                                                       */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

TgTYPE_STRUCT_ALIGN(STg2_FX_Job__Update_Data,16,)
{
    TgDELTA_F32_04                              m_sDelta;
    ETgFX_UPDATE                                m_enUpdate;
    TgUINT32                                    m_uiPad[3];
};
TgCOMPILER_ASSERT( sizeof( STg2_FX_Job__Update_Data ) <= KTgJOB_DATA_SIZE, 0 );




/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  File Local Functions - Default Behaviours                                                                                                                             */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

#if T_EFFECT_PROCESS_COMMMAND_DEFAULT
TgINLINE TgVOID                             T_NAME(tgFX__Update__, _Process_Update_Command_Default)( C_ETgFX_COMMAND, CP_TgVOID, C_TgFX_DATA_INST_ID );
#endif

#if T_EFFECT_TIME_DEFAULT
static TgBOOL                               T_NAME(tgFX__Update__, _Update_Life_Time)( C_TgSINT32, C_TgFLOAT32, TgVEC_M_F32_04 );
#endif




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

TgINLINE TgVOID                             T_NAME(tgFX__Update__, _Diag_Check_Effect)( TgFX_DATA_INST_ID );
static TgVOID                               T_NAME(tgFX__Update__, _Kill)( C_TgSINT32 );
static TgVOID                               T_NAME(tgFX__Update__Command__, _Kill_Self)( C_TgFX_DATA_INST_ID );

static TgRESULT                             T_NAME(tgFX__Update__Job__, _Update)( PC_STg2_Job );

static TgVOID                               T_NAME(tgFX__Update__, _Process_Mark_For_Delete)( TgVOID );
static TgVOID                               T_NAME(tgFX__Update__, _Process_New_Effects)( TgVOID );
static TgVOID                               T_NAME(tgFX__Update__, _Update_Finish)( TgVOID );
static TgRESULT                             T_NAME(tgFX__Update__Job__, _Update_Finish)( PC_STg2_Job );

static TgUINT08                             T_NAME(s_asFX_Command__, __Update_Command_Buffer)[ETgFX_COMMAND__CLIENT_TO_UPDATE__BYTE_MAX];
static volatile TgATOMIC_UINTXX             T_NAME(s_uiFX_Command__, __Update_Command_Offset);

static TgATOMIC_SINT32                      T_NAME(s_xiFX_Fence__, __Update);
static STg2_Job                             T_NAME(s_sFX__Job__, __Update)[ETgFX_UPDATE__MAX];

static TgATOMIC_SINT32                      T_NAME(s_xiFX_Fence__, __Update__Update_Finish);
static STg2_Job                             T_NAME(s_sFX__Job__, __Update__Update_Finish);

static TgFX_DATA_INST_ID                    T_NAME(s_atiFX__, __Update__Head)[ETgFX_UPDATE__MAX];
static TgSINT32                             T_NAME(s_niFX__, __Update__Active);




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

/* ---- tgFX__Client__, _Init_Update ------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID T_NAME(tgFX__Client__, _Init_Update)( TgVOID )
{
    TgSINT32                            iIndex;

    PROFILE_ARRAY_INIT( 0, TgT("DEFAULT"), T_TYPE(FX_, _UPDATE__UPDATE) );
    PROFILE_ARRAY_INIT( 1, TgT("EXTERNAL"), T_TYPE(FX_, _UPDATE__UPDATE) );
    PROFILE_ARRAY_INIT( 2, TgT("NEW"), T_TYPE(FX_, _UPDATE__UPDATE) );
    PROFILE_ARRAY_INIT( 3, TgT("FINISH"), T_TYPE(FX_, _UPDATE__UPDATE) );

    T_NAME(s_uiFX_Command__, __Update_Command_Offset) = 0;

    T_NAME(s_xiFX_Fence__, __Update) = 0;
    for (iIndex = 0; iIndex < ETgFX_UPDATE__MAX; ++iIndex)
    {
        memset( &T_NAME(s_sFX__Job__, __Update)[iIndex], 0, sizeof( STg2_Job ) );
    };

    T_NAME(s_xiFX_Fence__, __Update__Update_Finish) = 0;
    memset( &T_NAME(s_sFX__Job__, __Update__Update_Finish), 0, sizeof( STg2_Job ) );

    for (iIndex = 0; iIndex < ETgFX_UPDATE__MAX; ++iIndex)
    {
        T_NAME( s_atiFX__, __Update__Head )[iIndex] = KTgFX_DATA_INST_ID__INVALID;
    };
    T_NAME(s_niFX__, __Update__Active) = 0;
}


/* ---- tgFX__Client__, _Boot_Update ------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID T_NAME(tgFX__Client__, _Boot_Update)( TgVOID )
{
    T_NAME(s_sFX__Job__, __Update)[ETgFX_UPDATE__DEFAULT].m_pfnExecute = T_NAME(tgFX__Update__Job__, _Update);
    T_NAME(s_sFX__Job__, __Update)[ETgFX_UPDATE__DEFAULT].m_pxiFinish = &T_NAME(s_xiFX_Fence__, __Update);

    T_NAME(s_sFX__Job__, __Update)[ETgFX_UPDATE__EXTERNAL].m_pfnExecute = T_NAME(tgFX__Update__Job__, _Update);
    T_NAME(s_sFX__Job__, __Update)[ETgFX_UPDATE__EXTERNAL].m_pxiFinish = &T_NAME(s_xiFX_Fence__, __Update);

    T_NAME(s_sFX__Job__, __Update__Update_Finish).m_pfnExecute = T_NAME(tgFX__Update__Job__, _Update_Finish);
    T_NAME(s_sFX__Job__, __Update__Update_Finish).m_pxiTrigger = &T_NAME(s_xiFX_Fence__, __Update);
    T_NAME(s_sFX__Job__, __Update__Update_Finish).m_pxiFinish = &T_NAME(s_xiFX_Fence__, __Update__Update_Finish);
}


/* ---- tgFX__Client__, _Update_Command --------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgBOOL T_NAME(tgFX__Client__, _Update_Command)( C_ETgFX_COMMAND enCommand, CP_TgVOID pData )
{
    P_TgUINT08                          puiCommand_Stream;

    if (g_uiFX_Command_Size[enCommand] <= 0)
        return (TgFALSE);

    puiCommand_Stream = T_NAME(tgFX_, __Reserve_Update_Command)( enCommand );
    if (nullptr == puiCommand_Stream)
        return (TgFALSE);

    TgMEMCPY( puiCommand_Stream, g_uiFX_Command_Size[enCommand], pData, g_uiFX_Command_Size[enCommand] );
    return (TgTRUE);
}


/* ---- tgFX__Client__Submit_Job__, _Update ----------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID T_NAME(tgFX__Client__Submit_Job__, _Update)( TgVEC_M_F32_04 vDT, C_TgFLOAT32 fDT, C_ETgFX_UPDATE enUpdate )
{
    union
    {
        P_TgUINT08                          pui;
        P_STg2_FX_Job__Update_Data          psJob_Data;
    }                                   sUnion;

    TgERROR( 0 == T_NAME(s_xiFX_Fence__, __Update) );

    sUnion.pui = T_NAME(s_sFX__Job__, __Update)[enUpdate].m_auiData;
    sUnion.psJob_Data->m_sDelta.m_fDT = fDT;
    sUnion.psJob_Data->m_sDelta.m_vDT.m_mData = vDT;
    sUnion.psJob_Data->m_enUpdate = enUpdate;

    /* #PERF: Come up with a better load balancer than a single submission */
    tgAM32_INC( &g_xiFX_Fence__UPDATE );
    tgAM32_INC( &T_NAME(s_xiFX_Fence__, __Update) );
    tgJM_Queue_Job( g_sJob_Queue__Client_Normal, T_NAME(s_sFX__Job__, __Update) + enUpdate );
}


/* ---- tgFX__Client__Submit_Job__, _Update_Finish ---------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID T_NAME(tgFX__Client__Submit_Job__, _Update_Finish)( TgVOID )
{
    TgERROR( 0 == T_NAME(s_xiFX_Fence__, __Update__Update_Finish) );

    tgAM32_INC( &g_xiFX_Fence__CLIENT_TO_UPDATE__PROCESS_COMMAND_STREAM );
    tgAM32_INC( &T_NAME(s_xiFX_Fence__, __Update__Update_Finish) );
    tgJM_Queue_Job( g_sJob_Queue__Client_Normal, & T_NAME(s_sFX__Job__, __Update__Update_Finish) );
}




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

/* ---- tgFX__, _Query_Effect_Update_Head ------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgFX_DATA_INST_ID T_NAME(tgFX__, _Query_Effect_Update_Head)( C_ETgFX_UPDATE enUpdate )
{
    return (T_NAME(s_atiFX__, __Update__Head)[enUpdate]);
}


/* ---- tgFX__Update__, _Process_Update_Command_Buffer ------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
/* This is the only place where effect data can be created and deleted */
TgSIZE T_NAME(tgFX__Update__, _Process_Update_Command_Buffer)( CP_TgUINT08 puiCommand_Stream, TgSIZE uiIndex )
{
    ETgFX_COMMAND                       enCommand;

    puiCommand_Stream = puiCommand_Stream + uiIndex;
    {
        union
        {
            CP_TgUINT08                         pui;
            P_ETgFX_COMMAND                     penCommand;
        }                                   sUnion;

        sUnion.pui = puiCommand_Stream;
        enCommand = *sUnion.penCommand;
    }
    uiIndex += g_uiFX_Command_Size[enCommand];

#if T_EFFECT_NOTIFY
    if (ETgFX_COMMAND__CLIENT_TO_UPDATE__NOTIFY == enCommand)
    {
        union
        {
            CP_TgUINT08                         pui;
            CP_STg2_FX_Command__Notify          psNotify;
        }                                   sUnion;

        sUnion.pui = puiCommand_Stream;
        if (enCommand == (ETgFX_COMMAND)sUnion.psNotify->m_uiMessage)
        {
            T_NAME(tgFX__Update__Command__, _Notify)( sUnion.psNotify );
            return (uiIndex);
        };
    }
/*# T_EFFECT_NOTIFY */
#else
    TgERROR(ETgFX_COMMAND__CLIENT_TO_UPDATE__NOTIFY != enCommand);
/*# T_EFFECT_NOTIFY */
#endif

    /* Create commands are a special case of the regular commands - they have a different function signature (responsible for binding tiClient and tiData) */
    if (ETgFX_COMMAND__CLIENT_TO_UPDATE__CREATE == enCommand)
    {
        union
        {
            CP_TgUINT08                         pui;
            P_STg2_FX_Command__Update__Create   ps;
        }                                   sCreate;
        T_NAME(P_STg2_FX__,)                psEffect;

        sCreate.pui = puiCommand_Stream;

        TgERROR( TgTRUE == tgFX_Debug__Is_Valid( sCreate.ps->m_tiClient, sCreate.ps->m_tiData ) );
        TgERROR( sCreate.ps->m_tiClient.m.iI < KTgFX_MAX_EFFECT_INSTANCE );
        TgERROR( ETgFX_EFFECT_STATE__CLIENT__INIT == T_NAME(g_aenFX__, __Shared__State)[sCreate.ps->m_tiData.m.iI] );
        TgERROR( ETgFX_EFFECT_STATE__CLIENT__ACTIVE == g_aiFX__Client__Shared_State[sCreate.ps->m_tiClient.m.iI] );
        TgERROR( sCreate.ps->m_tiData.m.iI < T_TYPE(KTgFX_MAX_,) );

        psEffect = T_NAME(g_asFX__,) + sCreate.ps->m_tiData.m.iI;

    #if T_EFFECT_RENDER
        psEffect->m_tiNext[ETgFX_NEXT__RENDER] = KTgFX_DATA_INST_ID__INVALID;
    /*# T_EFFECT_RENDER */
    #endif
    #if T_EFFECT_SCENE
        psEffect->m_tiNext[ETgFX_NEXT__SCENE] = KTgFX_DATA_INST_ID__INVALID;
    /*# T_EFFECT_SCENE */
    #endif
        psEffect->m_tiNext[ETgFX_NEXT__UPDATE] = KTgFX_DATA_INST_ID__INVALID;

        psEffect->m_psFile_Data = sCreate.ps->m_psFile_Data_0;
        psEffect->m_tiClient = sCreate.ps->m_tiClient;
        psEffect->m_tiData = sCreate.ps->m_tiData;

    #if T_EFFECT_TIME
        psEffect->m_fTime_Total = tgCM_RAND_F32()*psEffect->m_psFile_Data->m_fTime_Total_RNG + psEffect->m_psFile_Data->m_fTime_Total_MID;
        psEffect->m_fTime_Start__Duration = tgCM_RAND_F32()*psEffect->m_psFile_Data->m_fTime_Start_RNG + psEffect->m_psFile_Data->m_fTime_Start_MID;
        psEffect->m_fTime_End__Start = tgCM_RAND_F32()*psEffect->m_psFile_Data->m_fTime_End_RNG + psEffect->m_psFile_Data->m_fTime_End_MID;
        psEffect->m_fTime_End__Duration =  tgCM_MAX_F32( 0.0F, psEffect->m_fTime_Total - psEffect->m_fTime_End__Start );
        psEffect->m_fLive_Time = 0.0F;
        psEffect->m_fLife_Time = psEffect->m_fTime_Total;
        psEffect->m_vLive_Time = MS_SET1_F32_04( 0.0F );
    /*# T_EFFECT_TIME */
    #endif

    #if T_EFFECT_FRAME
        psEffect->m_qRot_M = MS_SET1_F32_04( 0.0F );
        psEffect->m_qRot_M2W = sCreate.ps->m_sInstance.m_qRot_W.m_mData;
        psEffect->m_qRot_W = M_QT_MUL_F32_04( psEffect->m_qRot_M, psEffect->m_qRot_M2W );
        psEffect->m_vPos_M = MS_SET1_F32_04( 0.0F );
        psEffect->m_vPos_M2W = sCreate.ps->m_sInstance.m_vPos_W.m_mData;
        psEffect->m_vPos_W = M_ADD_F32_04( psEffect->m_vPos_M2W, M_QT_TX_F32_04( psEffect->m_vPos_M, psEffect->m_qRot_M2W ) );
        psEffect->m_vScale = sCreate.ps->m_sInstance.m_vScale.m_mData;
    /*# T_EFFECT_FRAME */
    #endif

    #if T_EFFECT_RENDER
        psEffect->m_enVertex = ETgRN_VERTEX_MAX;
        psEffect->m_tiMesh_Set = KTgRN_MESH_SET_ID__INVALID;
        psEffect->m_tiMaterial = KTgRN_MATERIAL_ID__INVALID;
        /*psEffect->m_uiUpdate = psCreate->m_sInstance.m_ui; */
        psEffect->m_uiRender__Visible = 0;
        psEffect->m_iIndex_In_SE_Context = -1;
        psEffect->m_vBA_Max_W = MS_SET1_F32_04( -KTgMAX_F32 );
        psEffect->m_vBA_Min_W = MS_SET1_F32_04( KTgMAX_F32 );
    /*# T_EFFECT_RENDER */
    #endif

        if (TgTRUE == T_NAME(tgFX__Update__, _Create_Command)( &sCreate.ps->m_sInstance, sCreate.ps->m_tiData, sCreate.ps->m_psFile_Data_1 ))
        {
            TgUINT32                            uiUpdate;

            uiUpdate = ((sCreate.ps->m_sInstance.m_uiInternal >> 8) & 0xFF);
            TgERROR_INDEX( uiUpdate, T_NAME(s_atiFX__, __Update__Head) );
            psEffect->m_tiNext[ETgFX_NEXT__UPDATE] = T_NAME(s_atiFX__, __Update__Head)[uiUpdate];
            T_NAME(s_atiFX__, __Update__Head)[uiUpdate] = psEffect->m_tiData;

            ++T_NAME(s_niFX__, __Update__Active);
        }
        else
        {
        #if T_EFFECT_RENDER
            psEffect->m_tiNext[ETgFX_NEXT__RENDER] = KTgFX_DATA_INST_ID__INVALID;
        /*# T_EFFECT_RENDER */
        #endif
        #if T_EFFECT_SCENE
            psEffect->m_tiNext[ETgFX_NEXT__SCENE] = KTgFX_DATA_INST_ID__INVALID;
        /*# T_EFFECT_SCENE */
        #endif
            psEffect->m_tiNext[ETgFX_NEXT__UPDATE] = KTgFX_DATA_INST_ID__INVALID;

            psEffect->m_psFile_Data = nullptr;
            psEffect->m_tiClient = KTgFX_CLIENT_INST_ID__INVALID;
            psEffect->m_tiData = KTgFX_DATA_INST_ID__INVALID;

            T_NAME(g_aenFX__, __Shared__State)[sCreate.ps->m_tiData.m.iI] = ETgFX_EFFECT_STATE__CLIENT__FREE;

            tgAM_WRITE_FENCE();
            tgCM_UTM_AM_ST_Push( &T_NAME(g_sFX__, __Client__Stack).m_sStack, (P_STg2_UTM_Node)(psEffect) );

            T_NAME(tgFX__Update__Command__, _Free)( sCreate.ps->m_tiClient, sCreate.ps->m_tiData );
        };

        return (uiIndex);
    };

    {
        union
        {
            CP_TgUINT08                         pui;
            P_STg2_FX_Command__Update__NoParam  psCommand;
        }                                   sUnion;

        sUnion.pui = puiCommand_Stream;

        /* Ignore stale messages to effects that have been freed on the update thread */
        if (TgFALSE == tgEQ_FX_DATA_INST_ID( sUnion.psCommand->m_sDest.m_tiData, T_NAME(g_asFX__,)[sUnion.psCommand->m_sDest.m_tiData.m.iI].m_tiData ))
        {
            return (uiIndex);
        }
        TgERROR( T_NAME(g_aenFX__, __Shared__State)[sUnion.psCommand->m_sDest.m_tiData.m.iI] > ETgFX_EFFECT_STATE__CLIENT__FREE );

        /* Process non-create commands to active effects */
        TgERROR( T_NAME(g_aenFX__, __Shared__State)[sUnion.psCommand->m_sDest.m_tiData.m.iI] >= ETgFX_EFFECT_STATE__UPDATE__ACTIVE );
    #if T_EFFECT_PROCESS_COMMMAND
        T_NAME(tgFX__Update__, _Process_Update_Command)( enCommand, puiCommand_Stream, sUnion.psCommand->m_sDest.m_tiData );
    #endif

        if (ETgFX_COMMAND__CLIENT_TO_UPDATE__KILL == enCommand)
        {
        #if T_EFFECT_GROUP
            T_NAME(tgFX__Update__Command__, _Free)(
                T_NAME(g_asFX__,)[sUnion.psCommand->m_sDest.m_tiData.m.iI].m_tiClient, T_NAME(g_asFX__,)[sUnion.psCommand->m_sDest.m_tiData.m.iI].m_tiData );
        /*# T_EFFECT_GROUP */
        #else
            T_NAME(tgFX__Update__, _Kill)( sUnion.psCommand->m_sDest.m_tiData.m.iI );
        /*# T_EFFECT_GROUP */
        #endif
        }
        else if (ETgFX_COMMAND__CLIENT_TO_UPDATE__STOP == enCommand)
        {
            T_NAME(g_aenFX__, __Shared__State)[sUnion.psCommand->m_sDest.m_tiData.m.iI] = ETgFX_EFFECT_STATE__UPDATE__ACTIVE_WAITING_TO_DIE;
        };
    };

    return (uiIndex);
}


/* ---- tgFX_, __ClientToUpdate__Reserve_Command ------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
P_TgUINT08 T_NAME(tgFX_, __Reserve_Update_Command)( C_ETgFX_COMMAND enCommand )
{
    TgSIZE                              uiCommand_Size;
    TgSIZE                              uiCommand_Offset;

    TgPARAM_CHECK( ETgFX_COMMAND__CLIENT_TO_UPDATE__BEGIN <= enCommand && ETgFX_COMMAND__CLIENT_TO_UPDATE__END >= enCommand );
    uiCommand_Size = g_uiFX_Command_Size[enCommand];
    while (1)
    {
        uiCommand_Offset = T_NAME(s_uiFX_Command__, __Update_Command_Offset);
        if ((uiCommand_Offset + uiCommand_Size) >= ETgFX_COMMAND__CLIENT_TO_UPDATE__BYTE_MAX)
        {
            return (nullptr);
        };

        if (uiCommand_Offset == tgAMXX_XCMP( &T_NAME(s_uiFX_Command__, __Update_Command_Offset), uiCommand_Offset + uiCommand_Size, uiCommand_Offset ))
        {
            return (T_NAME(s_asFX_Command__, __Update_Command_Buffer) + uiCommand_Offset);
        };
    };
}




/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  File Local Functions - Default Behaviours                                                                                                                             */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

/* ---- tgFX__Update__, _Process_Update_Command_Default ----------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
#if T_EFFECT_PROCESS_COMMMAND_DEFAULT
TgINLINE TgVOID T_NAME(tgFX__Update__, _Process_Update_Command_Default)( C_ETgFX_COMMAND enCommand, CP_TgVOID pData, C_TgFX_DATA_INST_ID tiData )
{
    T_NAME(P_STg2_FX__,)                psEffect;
    union
    {
        CP_STg2_FX_Command__Update__1_F32_04 psCommand_1_F32_04;
        CP_STg2_FX_Command__Update__1_UXX   psCommand_1_UXX;
        CP_TgVOID                           pVoid;
    }                                   sUnion;

    TgPARAM_CHECK_INDEX( tiData.m.iI, T_NAME(g_aenFX__, __Shared__State) );

    sUnion.pVoid = pData;
    psEffect = T_NAME(g_asFX__,) + tiData.m.iI;
    switch (enCommand)
    {
        case ETgFX_COMMAND__CLIENT_TO_UPDATE__NOTIFY: /*« Fall Through - Invalid */
        case ETgFX_COMMAND__CLIENT_TO_UPDATE__CREATE: /*« Fall Through - Invalid */
        case ETgFX_COMMAND__CLIENT_TO_UPDATE__SPIN: /*« Fall Through - Invalid */
        case ETgFX_COMMAND__SCENE_TO_RENDER__BEGIN: /*« Fall Through - Invalid */
        case ETgFX_COMMAND__UPDATE_TO_CLIENT__BEGIN: /*« Fall Through - Invalid */
        case ETgFX_COMMAND__UPDATE_TO_CLIENT__NOTIFY: /*« Fall Through - Invalid */
        case ETgFX_COMMAND__UPDATE_TO_CLIENT__FREE: /*« Fall Through - Invalid */
        case ETgFX_COMMAND__MAX: /*« Fall Through - Invalid */
        default: TgS_NO_DEFAULT( break );

        case ETgFX_COMMAND__CLIENT_TO_UPDATE__KILL: /*« Fall Through - Intentionally Blank */
        case ETgFX_COMMAND__CLIENT_TO_UPDATE__STOP: /*« Fall Through - Intentionally Blank */
            break;

        case ETgFX_COMMAND__CLIENT_TO_UPDATE__POSITION_SET:
            psEffect->m_vPos_M2W = sUnion.psCommand_1_F32_04->m_vF32_04.m_mData;
            psEffect->m_vPos_W = M_ADD_F32_04( psEffect->m_vPos_M2W, M_QT_TX_F32_04( psEffect->m_vPos_M, psEffect->m_qRot_M2W ) );
            break;
        case ETgFX_COMMAND__CLIENT_TO_UPDATE__POSITION_UPDATE_FROM_PARENT:
            psEffect->m_vPos_M2W = M_ADD_F32_04( psEffect->m_vPos_M2W, sUnion.psCommand_1_F32_04->m_vF32_04.m_mData );
            psEffect->m_vPos_W = M_ADD_F32_04( psEffect->m_vPos_M2W, M_QT_TX_F32_04( psEffect->m_vPos_M, psEffect->m_qRot_M2W ) );
            break;
        case ETgFX_COMMAND__CLIENT_TO_UPDATE__ROTATION_SET:
            psEffect->m_qRot_M2W = sUnion.psCommand_1_F32_04->m_vF32_04.m_mData;
            psEffect->m_qRot_W = M_QT_MUL_F32_04( psEffect->m_qRot_M, psEffect->m_qRot_M2W );
            psEffect->m_vPos_W = M_ADD_F32_04( psEffect->m_vPos_M2W, M_QT_TX_F32_04( psEffect->m_vPos_M, psEffect->m_qRot_M2W ) );
            break;
        case ETgFX_COMMAND__CLIENT_TO_UPDATE__ROTATION_UPDATE_FROM_PARENT:
            psEffect->m_qRot_M2W = M_QT_MUL_F32_04( sUnion.psCommand_1_F32_04->m_vF32_04.m_mData, psEffect->m_qRot_M2W );
            psEffect->m_qRot_W = M_QT_MUL_F32_04( psEffect->m_qRot_M, psEffect->m_qRot_M2W );
            psEffect->m_vPos_W = M_ADD_F32_04( psEffect->m_vPos_M2W, M_QT_TX_F32_04( psEffect->m_vPos_M, psEffect->m_qRot_M2W ) );
            break;
        case ETgFX_COMMAND__CLIENT_TO_UPDATE__VISIBLE:
            psEffect->m_uiRender__Visible = 0 == sUnion.psCommand_1_UXX->m_uiVal ? 0 : 1;
            break;
    };
}
/*# T_EFFECT_PROCESS_COMMMAND_DEFAULT */
#endif


/* ---- tgFX__Update__, _Update_Life_Time ------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
#if T_EFFECT_TIME_DEFAULT
static TgBOOL T_NAME(tgFX__Update__, _Update_Life_Time)( C_TgSINT32 iIndex, C_TgFLOAT32 fDT, TgVEC_M_F32_04 vdT )
{
    TgDIAG( ETgFX_EFFECT_STATE__UPDATE__ACTIVE_WAITING_TO_DIE >= T_NAME(g_aenFX__, __Shared__State)[iIndex] );
    TgDIAG( ETgFX_EFFECT_STATE__UPDATE__ACTIVE <= T_NAME(g_aenFX__, __Shared__State)[iIndex] );
    if (ETgFX_EFFECT_STATE__UPDATE__ACTIVE == T_NAME(g_aenFX__, __Shared__State)[iIndex])
    {
        T_NAME(g_asFX__,)[iIndex].m_fLife_Time -= fDT;
        if (T_NAME(g_asFX__,)[iIndex].m_fLife_Time <= T_NAME(g_asFX__,)[iIndex].m_fTime_End__Duration)
        {
            T_NAME(g_aenFX__, __Shared__State)[iIndex] = ETgFX_EFFECT_STATE__UPDATE__ACTIVE_WAITING_TO_DIE;
            if (T_NAME(g_asFX__,)[iIndex].m_fLife_Time <= 0.0F)
            {
                T_NAME(tgFX__Update__Command__, _Kill_Self)( T_NAME(g_asFX__,)[iIndex].m_tiData);
                T_NAME(g_asFX__,)[iIndex].m_fLife_Time = 0.0F;
                return (TgFALSE);
            };
        };
    }
    else if (ETgFX_EFFECT_STATE__UPDATE__ACTIVE_INFINITE == T_NAME(g_aenFX__, __Shared__State)[iIndex])
    {
        /* Intentionally left blank */
    }
    else if (ETgFX_EFFECT_STATE__UPDATE__ACTIVE_FIRST == T_NAME(g_aenFX__, __Shared__State)[iIndex])
    {
        T_NAME(g_aenFX__, __Shared__State)[iIndex] = ETgFX_EFFECT_STATE__UPDATE__ACTIVE;
    }
    else if (ETgFX_EFFECT_STATE__UPDATE__ACTIVE_WAITING_TO_DIE == T_NAME(g_aenFX__, __Shared__State)[iIndex])
    {
        if (T_NAME(g_asFX__,)[iIndex].m_fLife_Time <= fDT)
        {
            T_NAME(tgFX__Update__Command__, _Kill_Self)( T_NAME(g_asFX__,)[iIndex].m_tiData);
            T_NAME(g_asFX__,)[iIndex].m_fLife_Time = 0.0F;
            return (TgFALSE);
        };
        T_NAME(g_asFX__,)[iIndex].m_fLife_Time -= fDT;
    }
    else
    {
        T_NAME(tgFX__Update__Command__, _Kill_Self)( T_NAME(g_asFX__,)[iIndex].m_tiData);
        TgERROR_MSGF( 0, TgT( "%-16.16s(%-32.32s): Invalid Effect State.\n" ), TgT("Effect"), TgT("tgFX__ __Update_Life_Time") );
        return (TgFALSE);
    };

    T_NAME(g_asFX__,)[iIndex].m_vLive_Time = M_ADD_F32_04( T_NAME(g_asFX__,)[iIndex].m_vLive_Time, vdT );
    return (TgTRUE);
}
/*# T_EFFECT_TIME_DEFAULT */
#endif




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

/* ---- tgFX__Update__, _Diag_Check_Effect ------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgINLINE TgVOID T_NAME(tgFX__Update__, _Diag_Check_Effect)( TgFX_DATA_INST_ID tiData )
{
#if TgCOMPILE_ASSERT && TgCOMPILE_ASSERT__DIAG
    TgDIAG( TgTRUE == tgEQ_FX_DATA_INST_ID( T_NAME(g_asFX__,)[tiData.m.iI].m_tiData, tiData ) );
    TgDIAG( T_NAME(g_aenFX__, __Shared__State)[tiData.m.iI] >= ETgFX_EFFECT_STATE__UPDATE__ACTIVE );
    TgDIAG( TgTRUE == tgFX_Debug__Is_Valid( T_NAME(g_asFX__,)[tiData.m.iI].m_tiClient, T_NAME(g_asFX__,)[tiData.m.iI].m_tiData ) );
/*# TgCOMPILE_ASSERT && TgCOMPILE_ASSERT__DIAG */
#endif
}


/* ---- tgFX__Update__, _Kill ------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
static TgVOID T_NAME(tgFX__Update__, _Kill)( C_TgSINT32 iIndex )
{
    TgFX_CLIENT_INST_ID                 tiClient;
    TgFX_DATA_INST_ID                   tiData;

    tiClient = T_NAME(g_asFX__,)[iIndex].m_tiClient;
    tiData = T_NAME(g_asFX__,)[iIndex].m_tiData;

#if T_EFFECT_RENDER
    /* Free render resources */
    if (TgFALSE == tgEQ_RN_MESH_SET_ID( KTgRN_MESH_SET_ID__PARTICLE, T_NAME(g_asFX__,)[iIndex].m_tiMesh_Set ))
    {
        tgRN_Release_Mesh_Set( T_NAME(g_asFX__,)[iIndex].m_tiMesh_Set );
        T_NAME(g_asFX__,)[iIndex].m_tiMesh_Set = KTgRN_MESH_SET_ID__INVALID;
    };

    if (TgFALSE != tgRN_MATERIAL_ID_Is_Valid( T_NAME(g_asFX__,)[iIndex].m_tiMaterial ))
    {
        tgRN_Release_Material( T_NAME(g_asFX__,)[iIndex].m_tiMaterial );
        T_NAME(g_asFX__,)[iIndex].m_tiMaterial = KTgRN_MATERIAL_ID__INVALID;
    };

    T_NAME(g_asFX__,)[iIndex].m_iIndex_In_SE_Context = -1;
/*# T_EFFECT_RENDER */
#endif

    /* Invalidate data instance and put it back into the free pool */
#if T_EFFECT_RENDER
    T_NAME(g_asFX__,)[iIndex].m_tiNext[ETgFX_NEXT__RENDER] = KTgFX_DATA_INST_ID__INVALID;
/*# T_EFFECT_RENDER */
#endif
#if T_EFFECT_SCENE
    T_NAME(g_asFX__,)[iIndex].m_tiNext[ETgFX_NEXT__SCENE] = KTgFX_DATA_INST_ID__INVALID;
/*# T_EFFECT_SCENE */
#endif
    T_NAME(g_asFX__,)[iIndex].m_tiNext[ETgFX_NEXT__UPDATE] = KTgFX_DATA_INST_ID__INVALID;

    T_NAME(g_asFX__,)[iIndex].m_psFile_Data = nullptr;
    T_NAME(g_asFX__,)[iIndex].m_tiClient = KTgFX_CLIENT_INST_ID__INVALID;
    T_NAME(g_asFX__,)[iIndex].m_tiData = KTgFX_DATA_INST_ID__INVALID;

    T_NAME(g_aenFX__, __Shared__State)[iIndex] = ETgFX_EFFECT_STATE__CLIENT__FREE;

    /* Invalidate effect */
    T_NAME(tgFX__Update__Command__, _Free)( tiClient, tiData );
}


/* ---- tgFX__Update__Command__, _Kill_Self ----------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
static TgVOID T_NAME(tgFX__Update__Command__, _Kill_Self)( C_TgFX_DATA_INST_ID tiData )
{
    union
    {
        P_TgUINT08                          puiCommand_Stream;
        P_STg2_FX_Command__Update__NoParam  psCommand;
    }                                   sUnion;

    sUnion.puiCommand_Stream = T_NAME(tgFX_, __Reserve_Update_Command)( ETgFX_COMMAND__CLIENT_TO_UPDATE__KILL );
    if (nullptr == sUnion.puiCommand_Stream)
        return;

    sUnion.psCommand->m_enCommand = ETgFX_COMMAND__CLIENT_TO_UPDATE__KILL;
    sUnion.psCommand->m_sDest.m_tiData = tiData;
}


/* ---- tgFX__Update__Job__, _Update ------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
static TgRESULT T_NAME(tgFX__Update__Job__, _Update)( PC_STg2_Job psJob )
{
    union
    {
        P_TgUINT08                          pui;
        P_STg2_FX_Job__Update_Data          psUpdate_Data;
    }                                   sUnion;

    sUnion.pui = psJob->m_auiData;

    PROFILE_ARRAY_START( sUnion.psUpdate_Data->m_enUpdate, T_TYPE(FX_, _UPDATE__UPDATE) );
    PROFILE_ARRAY_START( sUnion.psUpdate_Data->m_enUpdate, FX_UPDATE__UPDATE );

    T_NAME(tgFX__Update__, _Update)( sUnion.psUpdate_Data->m_sDelta.m_vDT.m_mData, sUnion.psUpdate_Data->m_sDelta.m_fDT, sUnion.psUpdate_Data->m_enUpdate  );

    PROFILE_ARRAY_STOP( sUnion.psUpdate_Data->m_enUpdate, FX_UPDATE__UPDATE );
    PROFILE_ARRAY_STOP( sUnion.psUpdate_Data->m_enUpdate, T_TYPE(FX_, _UPDATE__UPDATE) );

    TgVERIFY( 0 == tgAM32_DEC( &g_xiFX_Fence__UPDATE ) );
    return (KTgS_OK);
}


/* ---- tgFX__Update__, _Process_Mark_For_Delete ------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
/* This is the only place where effect data can be created and deleted */
static TgVOID T_NAME(tgFX__Update__, _Process_Mark_For_Delete)( TgVOID )
{
    TgFX_DATA_INST_ID                   tiPrev_Client;
    TgFX_DATA_INST_ID                   tiCurrent_Client;
    TgFX_DATA_INST_ID                   tiNext_Client;
    TgSIZE                              uiIndex;

    for (uiIndex = 0; uiIndex < TgARRAY_COUNT( T_NAME(s_atiFX__, __Update__Head) ); ++uiIndex)
    {
        tiPrev_Client = KTgFX_DATA_INST_ID__INVALID;
        tiCurrent_Client = T_NAME(s_atiFX__, __Update__Head)[uiIndex];

        while (TgFALSE != tgFX_DATA_INST_ID_Is_Valid( tiCurrent_Client ))
        {
            tiNext_Client = T_NAME(g_asFX__,)[tiCurrent_Client.m.iI].m_tiNext[ETgFX_NEXT__UPDATE];

            /* Clear out all effects that were marked for delete in the last frame */
            if (TgFALSE == tgEQ_FX_DATA_INST_ID( tiCurrent_Client, T_NAME(g_asFX__,)[tiCurrent_Client.m.iI].m_tiData ))
            {
                if (TgFALSE != tgFX_DATA_INST_ID_Is_Valid( tiPrev_Client ))
                {
                    T_NAME(g_asFX__,)[tiPrev_Client.m.iI].m_tiNext[ETgFX_NEXT__UPDATE] = tiNext_Client;
                }
                else
                {
                    T_NAME(s_atiFX__, __Update__Head)[uiIndex] = tiNext_Client;
                };

                tgCM_UTM_AM_ST_Push( &T_NAME(g_sFX__, __Client__Stack).m_sStack, (P_STg2_UTM_Node)(T_NAME(g_asFX__,) + uiIndex) );
                tiCurrent_Client = tiNext_Client;
                --T_NAME(s_niFX__, __Update__Active);
                continue;
            };

            tiPrev_Client = tiCurrent_Client;
            tiCurrent_Client = tiNext_Client;
        };
    };
}


/* ---- tgFX__Update__, _Process_New_Effects ---------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
/* This is the only place where effect data can be created and deleted */
static TgVOID T_NAME(tgFX__Update__, _Process_New_Effects)( TgVOID )
{
    TgFX_DATA_INST_ID                   tiCurrent;
    TgFX_DATA_INST_ID                   tiNext;

    tiCurrent = T_NAME(s_atiFX__, __Update__Head)[ETgFX_UPDATE__NEW_CLIENT];

    while (TgFALSE != tgFX_DATA_INST_ID_Is_Valid( tiCurrent ))
    {
        T_NAME(P_STg2_FX__,)                psEffect;

        psEffect = T_NAME(g_asFX__,) + tiCurrent.m.iI;
        tiNext = psEffect ->m_tiNext[ETgFX_NEXT__UPDATE];

        psEffect->m_tiNext[ETgFX_NEXT__UPDATE] = T_NAME(s_atiFX__, __Update__Head)[psEffect->m_uiUpdate];
        T_NAME(s_atiFX__, __Update__Head)[psEffect->m_uiUpdate] = tiCurrent;

        tiCurrent = tiNext;
    };


    /* #TODO: Need to run update on all new effects */
    /* #TODO: Update Effect */
    /* #TODO: Cull Effect */
}


/* ---- tgFX__Update__, _Update_Finish ---------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
/* This is the only place where effect data can be created and deleted */
static TgVOID T_NAME(tgFX__Update__, _Update_Finish)( TgVOID )
{
    TgSIZE                              uiBuffer_Size;
    TgSIZE                              uiIndex;

    PROFILE_ARRAY_START( ETgFX_UPDATE__MAX, T_TYPE(FX_, _UPDATE__UPDATE) );
    PROFILE_ARRAY_START( ETgFX_UPDATE__MAX, FX_UPDATE__UPDATE );

    uiBuffer_Size = T_NAME(s_uiFX_Command__, __Update_Command_Offset);
    TgERROR( uiBuffer_Size <= ETgFX_COMMAND__CLIENT_TO_UPDATE__BYTE_MAX );
    for (uiIndex = 0; uiIndex < uiBuffer_Size; )
    {
        uiIndex = T_NAME(tgFX__Update__, _Process_Update_Command_Buffer)( T_NAME(s_asFX_Command__, __Update_Command_Buffer), uiIndex );
        TgERROR( uiIndex <= uiBuffer_Size );
    };

    tgAM_WRITE_FENCE();

    T_NAME(tgFX__Update__, _Process_Mark_For_Delete)();
    T_NAME(tgFX__Update__, _Process_New_Effects)();

#if T_EFFECT_SCENE
    T_NAME(tgFX__Client__Submit_Job__, _Refresh_BA)();
/*# T_EFFECT_SCENE */
#endif

    PROFILE_ARRAY_STOP( ETgFX_UPDATE__MAX, FX_UPDATE__UPDATE  );
    PROFILE_ARRAY_STOP( ETgFX_UPDATE__MAX, T_TYPE(FX_, _UPDATE__UPDATE) );
}


/* ---- tgFX__Update__Job__, _Update_Finish -------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
static TgRESULT T_NAME(tgFX__Update__Job__, _Update_Finish)( PC_STg2_Job UNUSED_PARAM psJob )
{
    T_NAME(tgFX__Update__, _Update_Finish)();
    TgVERIFY( 0 == tgAM32_DEC( &g_xiFX_Fence__CLIENT_TO_UPDATE__PROCESS_COMMAND_STREAM  ) );
    return (KTgS_OK);
}


/*# T_EFFECT_UPDATE */
#endif