Home

Resume

Blog

Teikitu


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


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

TgEXTN TgVOID                               tgFX__Client__Process_ToClient_Command_Buffer( TgVOID );




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

static TgVOID                               tgFX__Client__Flush_Deleted_Effects( TgVOID );
static TgVOID                               tgFX__Client__Flush_New_Effect_List( TgVOID );

static ETgMODULE_STATE                      s_enEffect_State = ETgMODULE_STATE__FREED;




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

/* ---- tgFX_Module_Init ------------------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgFX_Module_Init( TgVOID )
{
    TgSINT32                            iIndex;

    /* Verify the state of the system */
    TgERROR( ETgMODULE_STATE__FREED == s_enEffect_State );
    s_enEffect_State = ETgMODULE_STATE__INITIALIZING;

    PROFILE_INIT( FX_COMMANDS__CLIENT );
    PROFILE_ARRAY_INIT( 0, TgT("DEFAULT"), FX_UPDATE__UPDATE );
    PROFILE_ARRAY_INIT( 1, TgT("EXTERNAL"), FX_UPDATE__UPDATE );
    PROFILE_ARRAY_INIT( 2, TgT("NEW"), FX_UPDATE__UPDATE );
    PROFILE_ARRAY_INIT( 3, TgT("FINISH"), FX_UPDATE__UPDATE );
    PROFILE_INIT( FX_RENDER_PATCH_CONTEXT );
    PROFILE_INIT( FX_RENDER_PROCESS_COMMANDS );
    PROFILE_INIT( FX_RENDER_GENERATE );
    
    g_iFX_Quality_Setting = -1;
    g_tiFX_CN__Quality_Setting = KTgCN_VAR_ID__INVALID;
    g_fFX_Alpha_Threshold = 0.0F;
    g_tiFX_CN__Alpha_Threshold = KTgCN_VAR_ID__INVALID;

    g_xiFX_Fence__UPDATE = 0;
    g_xiFX_Fence__TO_CLIENT__COMMAND_QUEUE_FULL = 0;
    g_xiFX_Fence__CLIENT_TO_UPDATE__PROCESS_COMMAND_STREAM = 0;
    g_xiFX_Fence__CLIENT_TO_UPDATE__COMMAND_QUEUE_FULL = 0;
    g_xiFX_Fence__SCENE_CULLING = 0;
    g_xiFX_Fence__SCENE_BOUNDING_BOX = 0;
    g_xiFX_Fence__RENDER_PROCESS_HEADERS = 0;
    g_xiFX_Fence__RENDER_ALLOCATE = 0;
    g_xiFX_Fence__RENDER_GENERATE = 0;

    memset( g_apsFX_Descriptor, 0, sizeof( g_apsFX_Descriptor ) );

    g_uiParticle_Header_Index = 0;

    for (iIndex = 0; iIndex < KTgFX_MAX_EFFECT_INSTANCE; ++iIndex)
    {
        g_aiFX__Client__Shared_State[iIndex] = ETgFX_EFFECT_STATE__CLIENT__FREE;
    };
    tgCM_UTM_AM_ST_Init( &g_sFX_Effect__Client__Effect.m_sStack );

    for (iIndex = KTgFX_MAX_EFFECT_INSTANCE - 1; iIndex >= 0; --iIndex)
    {
        tgCM_UTM_AM_ST_Push( &g_sFX_Effect__Client__Effect.m_sStack, (P_STg2_UTM_Node)(g_asFX_Effect + iIndex) );
    };

    for (iIndex = 0; iIndex < ETgFX_UPDATE__MAX; ++iIndex)
    {
        g_atiFX__Client__Update__Head[iIndex] = KTgFX_CLIENT_INST_ID__INVALID;
    };
    g_niFX__Client__Update__Active = 0;

    g_tiFX_File_Default = KTgFX_EFFECT_ID__INVALID;
    g_tiFX_File_Error = KTgFX_EFFECT_ID__INVALID;

    memset( g_asFX_KN_File__Effect, 0, sizeof( g_asFX_KN_File__Effect ) );
    for (iIndex = 0; iIndex < ETgFX_DATA__EFFECT_MAX; ++iIndex)
    {
        g_auiFX_KN_File__Effect_Hash[iIndex] = KTgEMPTY_HASH;
        g_asFX_KN_File__Effect[iIndex].m_tiEffect = KTgFX_EFFECT_ID__INVALID;
        g_asFX_KN_File__Effect[iIndex].m_tiFile = KTgKN_FILE_ID__INVALID;
    };

    /* #FIX: Add tgFX_Load_File__Bind_Effect to Kernel, tgFX_Load_File__UnBind_Effect */

    g_xiFX__Decal__Memory_Current = 0;
    g_xiFX__Emitter__Memory_Current = 0;

    tgFX__Client__Beam_Init();
    tgFX__Client__Billboard_Init();
    tgFX__Client__Decal_Init();
    tgFX__Client__Emitter_Init();
    tgFX__Client__GIB_Init();
    tgFX__Client__Glass_Init();
    tgFX__Client__Group_Init();
    tgFX__Client__Light_Init();
    tgFX__Client__Liquid_Init();
    tgFX__Client__Post_Init();
    tgFX__Client__Sound_Init();
    tgFX__Client__Trail_Init();

#if TgS_DEBUG_EFFECT
    g_tiFX_Debug__OSD__Profile_Enable = KTgCN_VAR_ID__INVALID;
    g_tiFX_Debug__OSD__Profile_Sort = KTgCN_VAR_ID__INVALID;
    g_tiFX_Debug__Draw_BA = KTgCN_VAR_ID__INVALID;
    g_tiFX_Debug__Draw_Emitter = KTgCN_VAR_ID__INVALID;
    g_tiFX_Debug__Disable_Module = KTgCN_VAR_ID__INVALID;
    g_tiFX_Debug__Disable_Update = KTgCN_VAR_ID__INVALID;
    g_tiFX_Debug__Disable_Render = KTgCN_VAR_ID__INVALID;
    g_tiFX_Debug__Disable_Render_Buffer = KTgCN_VAR_ID__INVALID;
    g_tiFX_Debug__Disable_Cull_On_Spawn = KTgCN_VAR_ID__INVALID;
    g_tiFX_Debug__Disable_Cull_On_Render = KTgCN_VAR_ID__INVALID;
    memset( g_aszFX_Cache__EFfect_Name, 0, sizeof( g_aszFX_Cache__EFfect_Name ) );
/*# TgS_DEBUG_EFFECT */
#endif

    s_enEffect_State = ETgMODULE_STATE__INITIALIZED;
    return (KTgS_OK);
}


/* ---- tgFX_Module_Boot ------------------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgFX_Module_Boot( TgVOID )
{
    TgERROR( ETgMODULE_STATE__INITIALIZED == s_enEffect_State );
    s_enEffect_State = ETgMODULE_STATE__BOOTING;

    tgCN_PrintF( KTgCN_CHANEL_INITIALIZE_MEMORY, TgT( "%-16.16s(%-32.32s): %-48.48s % 14d\n" ), TgT("Effect"), TgT("Boot_Module"), TgT("Static Memory Size"),
                 tgFX_Query_Fixed_Memory() );

    tgFX__Client__Beam_Boot();
    tgFX__Client__Billboard_Boot();
    tgFX__Client__Decal_Boot();
    tgFX__Client__Emitter_Boot();
    tgFX__Client__GIB_Boot();
    tgFX__Client__Glass_Boot();
    tgFX__Client__Group_Boot();
    tgFX__Client__Light_Boot();
    tgFX__Client__Liquid_Boot();
    tgFX__Client__Post_Boot();
    tgFX__Client__Sound_Boot();
    tgFX__Client__Trail_Boot();

    /* #FIX: g_tiFX_File_Default = tgFX_Load_File( 0, nullptr, 0, nullptr ); */
    /* #FIX: g_tiFX_File_Error = tgFX_Load_File( 0, nullptr, 0, nullptr ); */

    s_enEffect_State = ETgMODULE_STATE__BOOTED;
    return (KTgS_OK);
}


/* ---- tgFX_Module_Stop ------------------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID tgFX_Module_Stop( TgVOID )
{
    TgSINT32                            iIndex;

    TgERROR( ETgMODULE_STATE__BOOTED == s_enEffect_State );
    s_enEffect_State = ETgMODULE_STATE__STOPPING;

    for (iIndex = 0; iIndex < KTgFX_MAX_EFFECT_INSTANCE; ++iIndex)
    {
        if (g_aiFX__Client__Shared_State[iIndex] < ETgFX_EFFECT_STATE__CLIENT__ACTIVE)
        {
            continue;
        };

        tgFX__Client__Free_Internal( iIndex );
    };

    tgFX__Client__Trail_Stop();
    tgFX__Client__Sound_Stop();
    tgFX__Client__Post_Stop();
    tgFX__Client__Liquid_Stop();
    tgFX__Client__Light_Stop();
    tgFX__Client__Group_Stop();
    tgFX__Client__Glass_Stop();
    tgFX__Client__GIB_Stop();
    tgFX__Client__Emitter_Stop();
    tgFX__Client__Decal_Stop();
    tgFX__Client__Billboard_Stop();
    tgFX__Client__Beam_Stop();

    for (iIndex = 0; iIndex < ETgFX_DATA__EFFECT_MAX; ++iIndex)
    {
        if (KTgEMPTY_HASH == g_auiFX_KN_File__Effect_Hash[iIndex])
        {
            continue;
        };

        if (0 != g_asFX_KN_File__Effect[iIndex].m_nuiReference)
        {
            TgWARNING_MSGF( 0, TgT( "%-16.16s(%-32.32s): FX Cache Stopping with active instances.\n" ), TgT("FX"), TgT("tgFX_Cache_Stop") );
        };

        g_auiFX_KN_File__Effect_Hash[iIndex] = KTgEMPTY_HASH;

        tgKN_File__Decrement_Reference( g_asFX_KN_File__Effect[iIndex].m_tiFile );
        g_asFX_KN_File__Effect[iIndex].m_tiFile = KTgKN_FILE_ID__INVALID;
        g_asFX_KN_File__Effect[iIndex].m_tiEffect = KTgFX_EFFECT_ID__INVALID;
    };

    s_enEffect_State = ETgMODULE_STATE__STOPPED;
}


/* ---- tgFX_Module_Free ------------------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID tgFX_Module_Free( TgVOID )
{
    TgERROR( ETgMODULE_STATE__STOPPED == s_enEffect_State || ETgMODULE_STATE__INITIALIZED == s_enEffect_State );
    s_enEffect_State = ETgMODULE_STATE__FREEING;

    tgFX__Client__Trail_Free();
    tgFX__Client__Sound_Free();
    tgFX__Client__Post_Free();
    tgFX__Client__Liquid_Free();
    tgFX__Client__Light_Free();
    tgFX__Client__Group_Free();
    tgFX__Client__Glass_Free();
    tgFX__Client__GIB_Free();
    tgFX__Client__Emitter_Free();
    tgFX__Client__Decal_Free();
    tgFX__Client__Billboard_Free();
    tgFX__Client__Beam_Free();

    TgERROR( TgTRUE != tgFX_EFFECT_ID_Is_Valid( g_tiFX_File_Error ) );
    TgERROR( TgTRUE != tgFX_EFFECT_ID_Is_Valid( g_tiFX_File_Default ) );

    s_enEffect_State = ETgMODULE_STATE__FREED;
}


/* ---- tgFX_Module_Update ---------------------------------------------------------------------------------------------------------------------------------------------- */
/* NOTE: Execute all ToClient Commands, Remove all deleted effects from lists, Add all new effects to update lists */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgFX_Module_Update( C_TgFLOAT32 UNUSED_PARAM fDT )
{
    TgSINT32                            iVal;
    TgFLOAT32                           fVal;

    if (TgFALSE != tgCN_VAR_ID_Is_Valid( g_tiFX_CN__Quality_Setting ) && TgTRUE == tgCN_Var_Query_S32( &iVal, g_tiFX_CN__Quality_Setting ))
        g_iFX_Quality_Setting = iVal;
    if (TgFALSE != tgCN_VAR_ID_Is_Valid( g_tiFX_CN__Alpha_Threshold ) && TgTRUE == tgCN_Var_Query_F32( &fVal, g_tiFX_CN__Alpha_Threshold ))
        g_fFX_Alpha_Threshold = fVal;
    if (TgFALSE == tgCN_VAR_ID_Is_Valid( g_tiFX_CN__Decal_Memory_Max ) && TgTRUE == tgCN_Var_Query_S32( &iVal, g_tiFX_CN__Decal_Memory_Max ))
        g_iFX_Decal_Memory_Max = iVal;
    if (TgFALSE == tgCN_VAR_ID_Is_Valid( g_tiFX_CN__Decal_Normal_Threshold ) && TgTRUE == tgCN_Var_Query_F32( &fVal, g_tiFX_CN__Decal_Normal_Threshold ))
        g_fFX_Decal_Normal_Threshold = fVal;
    if (TgFALSE == tgCN_VAR_ID_Is_Valid( g_tiFX_CN__Emitter_Memory_Max ) && TgTRUE == tgCN_Var_Query_S32( &iVal, g_tiFX_CN__Emitter_Memory_Max ))
        g_iFX_Emitter_Memory_Max = iVal;

#if TgS_DEBUG_EFFECT
    {
        TgBOOL                              bDisable;
        if ((TgTRUE == tgCN_Var_Query_Bool( &bDisable, g_tiFX_Debug__Disable_Module )) && (TgTRUE == bDisable))
            return (KTgS_OK);
    }
/*# TgS_DEBUG_EFFECT */
#endif

    TgERROR( 0 == g_xiFX_Fence__UPDATE );
    TgERROR( 0 == g_xiFX_Fence__SCENE_CULLING );

    PROFILE_START( FX_COMMANDS__CLIENT );
    tgFX__Client__Process_ToClient_Command_Buffer();
    tgFX__Client__Flush_Deleted_Effects();
    tgFX__Client__Flush_New_Effect_List(); /* #TODO: Move effects from new to update */
    PROFILE_STOP( FX_COMMANDS__CLIENT );

    return (KTgS_OK);
}


/* ---- tgFX_Load_Config ------------------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgFX_Load_Config( TgVOID )
{
    if (TgFAILED( tgCM_Config_Query_S32( &g_iFX_Quality_Setting, tgSZ_Hash( TgT("FX") ), tgSZ_Hash( TgT("Quality Setting") ) ) ))
        g_iFX_Quality_Setting = 0;
    if (TgFAILED( tgCM_Config_Query_F32( &g_fFX_Alpha_Threshold, tgSZ_Hash( TgT("FX") ), tgSZ_Hash( TgT("Alpha Threshold") ) ) ))
        g_fFX_Alpha_Threshold = 0.01F;
    if (TgFAILED( tgCM_Config_Query_S32( &g_iFX_Decal_Memory_Max, tgSZ_Hash( TgT("FX") ), tgSZ_Hash( TgT("Decal Memory Max") ) ) ))
        g_iFX_Decal_Memory_Max = 0;
    if (TgFAILED( tgCM_Config_Query_F32( &g_fFX_Decal_Normal_Threshold, tgSZ_Hash( TgT("FX") ), tgSZ_Hash( TgT("Decal Normal Threshold") ) ) ))
        g_fFX_Decal_Normal_Threshold = 0.01F;
    if (TgFAILED( tgCM_Config_Query_S32( &g_iFX_Emitter_Memory_Max, tgSZ_Hash( TgT("FX") ), tgSZ_Hash( TgT("Emitter Memory Max") ) ) ))
        g_iFX_Emitter_Memory_Max = 0;

    g_tiFX_CN__Quality_Setting = tgCN_Var_Init_S32( TgT("FX Quality_Setting"), TgT("Configuration: 0 is Normal"), KTgCN_VAR_CHEAT, g_iFX_Quality_Setting, -5, 5 );
    g_tiFX_CN__Alpha_Threshold = tgCN_Var_Init_F32(
        TgT("FX Alpha Threshold"), TgT("Below this value the effect will not draw"), KTgCN_VAR_CHEAT, g_fFX_Alpha_Threshold, 0.0F, 1.0F );
    g_tiFX_CN__Decal_Memory_Max = tgCN_Var_Init_S32(
        TgT("FX Decal Memory Max"), TgT("Max Amount of Memory that Decals will consume in MB"), KTgCN_VAR_CHEAT, g_iFX_Decal_Memory_Max, 0, 1024 );
    g_tiFX_CN__Decal_Normal_Threshold = tgCN_Var_Init_F32(
        TgT("FX Decal Normal Threshold"), TgT("Below this value the decal face will fade out"), KTgCN_VAR_CHEAT, g_fFX_Decal_Normal_Threshold, 0.0F, 1.0F );
    g_tiFX_CN__Emitter_Memory_Max = tgCN_Var_Init_S32(
        TgT("FX Emitter Memory Max"), TgT("Max Amount of Memory that Emitters will consume in MB"), KTgCN_VAR_CHEAT, g_iFX_Emitter_Memory_Max, 0, 1024 );

#if TgS_DEBUG_EFFECT
    tgFX_Debug__Load_Config();
#endif

    return (KTgS_OK);
}


/* ---- tgFX_Save_Config ------------------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgFX_Save_Config( TgVOID )
{
    TgSINT32                            iVal;
    TgFLOAT32                           fVal;
    TgUINTXX                            uiFX;

    uiFX = tgSZ_Hash( TgT("FX") );
    if (TgFALSE != tgCN_VAR_ID_Is_Valid( g_tiFX_CN__Quality_Setting ) && TgTRUE == tgCN_Var_Query_S32( &iVal, g_tiFX_CN__Quality_Setting ))
        g_iFX_Quality_Setting = iVal;
    tgCM_Config_Set_S32( g_iFX_Quality_Setting, uiFX, tgSZ_Hash( TgT("Quality Setting") ) );

    if (TgFALSE != tgCN_VAR_ID_Is_Valid( g_tiFX_CN__Alpha_Threshold ) && TgTRUE == tgCN_Var_Query_F32( &fVal, g_tiFX_CN__Alpha_Threshold ))
        g_fFX_Alpha_Threshold = fVal;
    tgCM_Config_Set_F32( g_fFX_Alpha_Threshold, uiFX, tgSZ_Hash( TgT("Alpha Threshold") ) );

    if (TgFALSE == tgCN_VAR_ID_Is_Valid( g_tiFX_CN__Decal_Memory_Max ) && TgTRUE == tgCN_Var_Query_S32( &iVal, g_tiFX_CN__Decal_Memory_Max ))
        g_iFX_Decal_Memory_Max = iVal;
    tgCM_Config_Set_S32( g_iFX_Decal_Memory_Max, uiFX, tgSZ_Hash( TgT("Decal Memory Max") ) );

    if (TgFALSE == tgCN_VAR_ID_Is_Valid( g_tiFX_CN__Emitter_Memory_Max ) && TgTRUE == tgCN_Var_Query_S32( &iVal, g_tiFX_CN__Emitter_Memory_Max ))
        g_iFX_Emitter_Memory_Max = iVal;
    tgCM_Config_Set_S32( g_iFX_Emitter_Memory_Max, uiFX, tgSZ_Hash( TgT("Emitter Memory Max") ) );

    if (TgFALSE != tgCN_VAR_ID_Is_Valid( g_tiFX_CN__Decal_Normal_Threshold ) && TgTRUE == tgCN_Var_Query_F32( &fVal, g_tiFX_CN__Decal_Normal_Threshold ))
        g_fFX_Decal_Normal_Threshold = fVal;
    tgCM_Config_Set_F32( g_fFX_Decal_Normal_Threshold, uiFX, tgSZ_Hash( TgT("Decal Normal Threshold") ) );

    return (KTgS_OK);
}


/* ---- tgFX_Query_Init ------------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgBOOL tgFX_Query_Init( TgVOID )
{
    return (ETgMODULE_STATE__INITIALIZED <= s_enEffect_State && s_enEffect_State <= ETgMODULE_STATE__STOPPED);
}


/* ---- tgFX_Query_Boot ------------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgBOOL tgFX_Query_Boot( TgVOID )
{
    return (ETgMODULE_STATE__BOOTED == s_enEffect_State);
}




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

/* ---- tgFX__Client__Flush_Deleted_Effect ------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
static TgVOID tgFX__Client__Flush_Deleted_Effects( TgVOID )
{
    TgFX_CLIENT_INST_ID                 tiPrev_Client;
    TgFX_CLIENT_INST_ID                 tiCurrent_Client;
    TgFX_CLIENT_INST_ID                 tiNext_Client;
    TgSINT32                            iIndex;

    for (iIndex = 0; iIndex < ETgFX_UPDATE__NEW_CLIENT; ++iIndex)
    {
        tiPrev_Client = KTgFX_CLIENT_INST_ID__INVALID;
        tiCurrent_Client = g_atiFX__Client__Update__Head[iIndex];

        while (TgFALSE != tgFX_CLIENT_INST_ID_Is_Valid( tiCurrent_Client ))
        {
            tiNext_Client = g_asFX_Effect[tiCurrent_Client.m.iI].m_tiUpdate_Next;

            /* Clear out all effects that were marked for delete in the last frame */
            if (TgFALSE == tgEQ_FX_CLIENT_INST_ID( tiCurrent_Client, g_asFX_Effect[tiCurrent_Client.m.iI].m_tiClient ))
            {
                if (TgFALSE != tgFX_CLIENT_INST_ID_Is_Valid( tiPrev_Client ))
                {
                    g_asFX_Effect[tiPrev_Client.m.iI].m_tiUpdate_Next = tiNext_Client;
                }
                else
                {
                    g_atiFX__Client__Update__Head[iIndex] = tiNext_Client;
                };
                tgCM_UTM_AM_ST_Push( &g_sFX_Effect__Client__Effect.m_sStack, (P_STg2_UTM_Node)(g_asFX_Effect + tiCurrent_Client.m.iI) );
            }
            else
            {
                tiPrev_Client = tiCurrent_Client;
            };

            tiCurrent_Client = tiNext_Client;
        };
    };
}


/* ---- tgFX__Client__Flush_New_Effect_List ----------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
static TgVOID tgFX__Client__Flush_New_Effect_List( TgVOID )
{
    TgFX_CLIENT_INST_ID                 tiCurrent_Client;
    TgFX_CLIENT_INST_ID                 tiNext_Client;

    tiCurrent_Client = g_atiFX__Client__Update__Head[ETgFX_UPDATE__NEW_CLIENT];

    while (TgFALSE != tgFX_CLIENT_INST_ID_Is_Valid( tiCurrent_Client ))
    {
        tiNext_Client = g_asFX_Effect[tiCurrent_Client.m.iI].m_tiUpdate_Next;

        /* Clear out all effects that were marked for delete in the last frame */
        if (TgFALSE == tgEQ_FX_CLIENT_INST_ID( tiCurrent_Client, g_asFX_Effect[tiCurrent_Client.m.iI].m_tiClient ))
        {
            tgCM_UTM_AM_ST_Push( &g_sFX_Effect__Client__Effect.m_sStack, (P_STg2_UTM_Node)(g_asFX_Effect + tiCurrent_Client.m.iI) );
        }
        else
        {
            TgERROR_INDEX( g_asFX_Effect[tiCurrent_Client.m.iI].m_uiUpdate, g_atiFX__Client__Update__Head );
            g_asFX_Effect[tiCurrent_Client.m.iI].m_tiUpdate_Next = g_atiFX__Client__Update__Head[g_asFX_Effect[tiCurrent_Client.m.iI].m_uiUpdate];
            g_atiFX__Client__Update__Head[g_asFX_Effect[tiCurrent_Client.m.iI].m_uiUpdate] = tiCurrent_Client;
        };

        tiCurrent_Client = tiNext_Client;
    };

    g_atiFX__Client__Update__Head[ETgFX_UPDATE__NEW_CLIENT] = KTgFX_CLIENT_INST_ID__INVALID;
}