Home

Resume

Blog

Teikitu


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

#define T_NAME( A, ... ) A##Trail##__VA_ARGS__
#define T_TYPE( A, ... ) A##TRAIL##__VA_ARGS__
#define T_TEXT( ... ) __VA_ARGS__ TgT("Trail")
#define T_EFFECT_FRAME 0
#define T_EFFECT_TIME_DEFAULT 0
#define T_EFFECT_PROCESS_COMMMAND_DEFAULT 0

#include "TgS Effect - Effect - Type.h_inc"


/* == Effect ============================================================================================================================================================ */

/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  Shared Implementation                                                                                                                                                 */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

#include "TgS Effect - Effect - Update.i_inc"
#include "TgS Effect - Effect - Update.c_inc"




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

static TgVOID                               tgFX__Update__Trail_Add_Point( C_TgSINT32, TgVEC_M_F32_04 );




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

/* ---- tgFX__File__Trail_Patch_File_Data ------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID tgFX__File__Trail_Patch_File_Data( P_STg2_FX_Trail__File_Data psData )
{
    TgUINTPTR                           uiData_Top;

    uiData_Top = (TgUINTPTR)psData;

    psData->m_sAnim.m_sData_Offset.m_uiColour += uiData_Top;
    psData->m_sAnim.m_sData_Offset.m_uiWidth += uiData_Top;
}




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

/* ---- tgFX__Update__Trail_Create_Command ------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
static TgBOOL tgFX__Update__Trail_Create_Command( CP_STg2_FX_Instance psInst, C_TgFX_DATA_INST_ID tiData, CP_TgVOID UNUSED_PARAM pData1 )
{
    P_STg2_FX__Trail                    psTrail;
    CP_STg2_FX_Trail__File_Data         psFile_Data;
    TgRN_MATERIAL_ID                    tiMaterial;
    ETgRN_VERTEX                        enVertex;

    psTrail = g_asFX__Trail + tiData.m.iI;
    psFile_Data = psTrail->m_psFile_Data;

    tiMaterial = KTgRN_MATERIAL_ID__INVALID;
    enVertex = ETgRN_VERTEX_MAX;
    tgFX__Update__Set_Render_Data_From_Material_Hash( nullptr, &tiMaterial, &enVertex, psFile_Data->m_uiHash_Material );

    if (TgTRUE != tgRN_MATERIAL_ID_Is_Valid( tiMaterial ))
    {
        return (TgFALSE);
    }

    psTrail->m_tiMesh_Set = KTgRN_MESH_SET_ID__PARTICLE;

    psTrail->m_sExtend.m_vPos_W[0] = psInst->m_vPos_W.m_mData;
    psTrail->m_sExtend.m_vScaleFactor = MS_SET1_F32_04( psInst->m_vScale.m_aData[0] );
    psTrail->m_sExtend.m_fU[0] = 0.0F;
    psTrail->m_sExtend.m_uiPoint_Head = 0;
    psTrail->m_sExtend.m_uiPoint_Tail = 0;
    psTrail->m_sExtend.m_uiHead_Offset = 0;
    psTrail->m_vLive_Time = MS_SET1_F32_04( 0.0F );
    psTrail->m_sExtend.m_vColour = tgFX_Evaluate_AnimData_F32_04( psFile_Data->m_sAnim.m_sParameter.m_psColour, MS_SET1_F32_04( 0.0F ) );
    psTrail->m_sExtend.m_vWidth = tgFX_Evaluate_AnimData_F32_04( psFile_Data->m_sAnim.m_sParameter.m_psWidth, MS_SET1_F32_04( 0.0F ) );
    tgRN_M_Calc_UV_Animation(
        &psTrail->m_sExtend.m_vUV_01_Constant, &psTrail->m_sExtend.m_vUV_01_Scale, tiMaterial, KTgV_ZERO_F32_04.m_mData, KTgV_ZERO_F32_04.m_mData );
    psTrail->m_fLife_Time = psTrail->m_fTime_Total;

    if (psTrail->m_fTime_End__Start < 0.0F)
        g_aenFX__Trail__Shared__State[tiData.m.iI] = ETgFX_EFFECT_STATE__UPDATE__ACTIVE_INFINITE;
    else
        g_aenFX__Trail__Shared__State[tiData.m.iI] = ETgFX_EFFECT_STATE__UPDATE__ACTIVE_FIRST;

    return (TgTRUE);
}


/* ---- tgFX__Update__Trail_Update -------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
static TgVOID tgFX__Update__Trail_Update( TgVEC_M_F32_04 vdT, C_TgFLOAT32 fDT, C_ETgFX_UPDATE enUpdate )
{
    TgFX_DATA_INST_ID                   tiActive;
    P_STg2_FX__Trail                    psTrail;
    CP_STg2_FX_Trail__File_Data         psFile_Data;

    tiActive = T_NAME( s_atiFX__, __Update__Head )[enUpdate];

    while (TgFALSE != tgFX_DATA_INST_ID_Is_Valid( tiActive ))
    {
        TgVEC_M_F32_04                      vRolling_Sum_Of_Pos_W_Delta;
        TgVEC_F32_04                        vTrail_Length;
        TgVEC_F32_04                        vRolling_Sum_Of_Length[KTgFX_MAX_POINTS_IN_TRAIL];
        TgVEC_M_F32_04                      vFollow_Fraction;
        TgUINT32                            uiIndex;
        TgUINT32                            uiRead_Index;
        TgUINT32                            uiWrite_Index;
        TgFLOAT32                           fInv_Max_Trail_Length;

        tgFX__Update__Trail_Diag_Check_Effect( tiActive );

        psTrail = g_asFX__Trail + tiActive.m.iI;
        psFile_Data = psTrail->m_psFile_Data;

        if (ETgFX_EFFECT_STATE__UPDATE__ACTIVE_WAITING_TO_DIE == g_aenFX__Trail__Shared__State[tiActive.m.iI])
        {
            if (psTrail->m_sExtend.m_uiPoint_Tail == psTrail->m_sExtend.m_uiPoint_Head)
            {
                tgFX__Update__Command__Trail_Kill_Self( psTrail->m_tiData );
                continue;
            }
            else
            {
                psTrail->m_sExtend.m_uiHead_Offset += 1;
                psTrail->m_sExtend.m_uiPoint_Tail = (psTrail->m_sExtend.m_uiPoint_Tail + 1) % KTgFX_MAX_POINTS_IN_TRAIL;
            };
        }
        else if (ETgFX_EFFECT_STATE__UPDATE__ACTIVE == g_aenFX__Trail__Shared__State[tiActive.m.iI])
        {
            if (psTrail->m_fLife_Time < fDT)
            {
                g_aenFX__Trail__Shared__State[tiActive.m.iI] = ETgFX_EFFECT_STATE__UPDATE__ACTIVE_WAITING_TO_DIE;
            };
        }
        else if (ETgFX_EFFECT_STATE__UPDATE__ACTIVE_FIRST == g_aenFX__Trail__Shared__State[tiActive.m.iI])
        {
            g_aenFX__Trail__Shared__State[tiActive.m.iI] = ETgFX_EFFECT_STATE__UPDATE__ACTIVE;
        };

        psTrail->m_vLive_Time = M_ADD_F32_04( psTrail->m_vLive_Time, vdT );
        psTrail->m_sExtend.m_vColour = tgFX_Evaluate_AnimData_F32_04( psFile_Data->m_sAnim.m_sParameter.m_psColour, psTrail->m_vLive_Time );
        psTrail->m_sExtend.m_vWidth = tgFX_Evaluate_AnimData_F32_04( psFile_Data->m_sAnim.m_sParameter.m_psWidth, psTrail->m_vLive_Time );
        psTrail->m_fLife_Time -= fDT;

        if (psTrail->m_sExtend.m_uiPoint_Tail == psTrail->m_sExtend.m_uiPoint_Head)
            continue;

        /* Update Trail Points - Collapse any near positions and shrink the trail tail */
        vRolling_Sum_Of_Pos_W_Delta = MS_SET1_F32_04( 0.0F );
        vTrail_Length.m_mData = MS_SET1_F32_04( 0.0F );
        vFollow_Fraction = MS_SET1_F32_04( psFile_Data->m_fFollow_Fraction );
        TgERROR_INDEX( psTrail->m_sExtend.m_uiPoint_Head, vRolling_Sum_Of_Length );
        vRolling_Sum_Of_Length[psTrail->m_sExtend.m_uiPoint_Head].m_mData = MS_SET1_F32_04( 0.0F );

        uiRead_Index = psTrail->m_sExtend.m_uiPoint_Head;
        uiIndex = psTrail->m_sExtend.m_uiPoint_Head;
        uiWrite_Index = ((KTgFX_MAX_POINTS_IN_TRAIL + uiIndex - 1) % KTgFX_MAX_POINTS_IN_TRAIL);
        while (1)
        {
            TgVEC_F32_04                        vDelta_Length;
            TgVEC_M_F32_04                      vNext_Pos_W;
            TgVEC_M_F32_04                      vDelta;
            TgVEC_M_F32_04                      vDirection;
            TgVEC_M_F32_04                      vNew_Delta_Length;
            TgVEC_M_F32_04                      vNew_Delta;

            uiRead_Index = ((KTgFX_MAX_POINTS_IN_TRAIL + uiRead_Index - 1) % KTgFX_MAX_POINTS_IN_TRAIL);
            if (uiRead_Index == psTrail->m_sExtend.m_uiPoint_Tail)
            {
                break;
            }

            vNext_Pos_W = M_ADD_F32_04( psTrail->m_sExtend.m_vPos_W[uiRead_Index], vRolling_Sum_Of_Pos_W_Delta );
            vDelta = M_SUB_F32_04( vNext_Pos_W, psTrail->m_sExtend.m_vPos_W[uiIndex] );
            vDirection = M_NORM_LEN_F32_04( &vDelta_Length.m_mData, vDelta );

            if (vDelta_Length.m_aData[0] < 0.001F)
            {
                continue;
            }

            vNew_Delta_Length = M_MUL_F32_04( vDelta_Length.m_mData, vFollow_Fraction );
            vNew_Delta = M_MUL_F32_04( vDelta, vNew_Delta_Length );
            psTrail->m_sExtend.m_vPos_W[uiWrite_Index] = M_ADD_F32_04( psTrail->m_sExtend.m_vPos_W[uiIndex], vNew_Delta );
            vTrail_Length.m_mData = M_ADD_F32_04( vTrail_Length.m_mData, vNew_Delta_Length );
            vRolling_Sum_Of_Length[uiWrite_Index] = vTrail_Length;
            vRolling_Sum_Of_Pos_W_Delta = M_ADD_F32_04( vRolling_Sum_Of_Pos_W_Delta, M_SUB_F32_04( vNew_Delta, vDelta ) );

            uiIndex = uiWrite_Index;
            uiWrite_Index = ((KTgFX_MAX_POINTS_IN_TRAIL + uiWrite_Index - 1) % KTgFX_MAX_POINTS_IN_TRAIL);
        }

        if (uiWrite_Index != ((KTgFX_MAX_POINTS_IN_TRAIL + psTrail->m_sExtend.m_uiPoint_Head - 1) % KTgFX_MAX_POINTS_IN_TRAIL))
        {
            psTrail->m_sExtend.m_uiPoint_Tail = uiWrite_Index;
        }

        /* Calculate the texel values */
        fInv_Max_Trail_Length = vTrail_Length.m_aData[0] > FLT_EPSILON ? 1.0F / vTrail_Length.m_aData[0] : 0.0F;
        for (uiIndex = psTrail->m_sExtend.m_uiPoint_Head; uiIndex != psTrail->m_sExtend.m_uiPoint_Tail;)
        {
            psTrail->m_sExtend.m_fU[uiIndex] = vRolling_Sum_Of_Length[uiIndex].m_aData[0] * fInv_Max_Trail_Length;
            uiIndex = ((KTgFX_MAX_POINTS_IN_TRAIL + uiIndex - 1) % KTgFX_MAX_POINTS_IN_TRAIL);
        }

        tiActive = psTrail->m_tiNext[ETgFX_NEXT__UPDATE];
    };
}


/* ---- tgFX__Update__Trail_Process_Update_Command ---------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
static TgVOID tgFX__Update__Trail_Process_Update_Command( C_ETgFX_COMMAND enCommand, CP_TgVOID pData, C_TgFX_DATA_INST_ID tiData )
{
    P_STg2_FX__Trail                    psTrail;

    TgPARAM_CHECK_INDEX( tiData.m.iI, g_aenFX__Trail__Shared__State );

    psTrail = g_asFX__Trail + 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: /* Fall Through - Treated as the same command */
        case ETgFX_COMMAND__CLIENT_TO_UPDATE__POSITION_UPDATE_FROM_PARENT:
            TgERROR( g_aenFX__Trail__Shared__State[tiData.m.iI] >= ETgFX_EFFECT_STATE__UPDATE__ACTIVE );
            tgFX__Update__Trail_Add_Point( tiData.m.iI, MS_SETU_F32_04( (CP_TgFLOAT32)pData ) );
            break;
        case ETgFX_COMMAND__CLIENT_TO_UPDATE__ROTATION_SET: /* Fall Through - Rotation is not conceptually valid */
        case ETgFX_COMMAND__CLIENT_TO_UPDATE__ROTATION_UPDATE_FROM_PARENT: /* Fall Through - Rotation is not conceptually valid */
        case ETgFX_COMMAND__CLIENT_TO_UPDATE__VISIBLE: /* Fall Through - Intentionally Blank */
            break;
    };
}




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

/* ---- tgFX__Update__Trail_Add_Point ----------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
static TgVOID tgFX__Update__Trail_Add_Point( C_TgSINT32 iIndex, TgVEC_M_F32_04 vNewPoint )
{
    P_STg2_FX__Trail                    psTrail;
    CP_STg2_FX_Trail__File_Data         psFile_Data;
    TgUINT32                            nuiPoints;

    if (g_aenFX__Trail__Shared__State[iIndex] < ETgFX_EFFECT_STATE__UPDATE__ACTIVE)
    {
        TgDIAG( ETgFX_EFFECT_STATE__UPDATE__ACTIVE_WAITING_TO_DIE == g_aenFX__Trail__Shared__State[iIndex] );
        return;
    }

    psTrail = g_asFX__Trail + iIndex;
    psFile_Data = psTrail->m_psFile_Data;

    if (TgTRUE == M_PRX3_F32_04( psTrail->m_sExtend.m_vPos_W[psTrail->m_sExtend.m_uiPoint_Head], vNewPoint ))
    {
        return;
    }

    nuiPoints = (KTgFX_MAX_POINTS_IN_TRAIL + psTrail->m_sExtend.m_uiPoint_Head - psTrail->m_sExtend.m_uiPoint_Tail) % KTgFX_MAX_POINTS_IN_TRAIL;

    if (nuiPoints >= psFile_Data->m_nuiMax_Points)
    {
        psTrail->m_sExtend.m_uiPoint_Tail = (psTrail->m_sExtend.m_uiPoint_Tail + 1) % KTgFX_MAX_POINTS_IN_TRAIL;
    }

    psTrail->m_sExtend.m_uiPoint_Head = (psTrail->m_sExtend.m_uiPoint_Head + 1) % KTgFX_MAX_POINTS_IN_TRAIL;
    psTrail->m_sExtend.m_vPos_W[psTrail->m_sExtend.m_uiPoint_Head] = vNewPoint;
}