Home

Resume

Blog

Teikitu


/* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
/*  »Project«   Teikitu Gaming System (TgS) (∂)
    »File«      TgS Effect - Emitter - Render.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##Emitter##__VA_ARGS__
#define T_TYPE( A, ... ) A##EMITTER##__VA_ARGS__
#define T_TEXT( ... ) __VA_ARGS__ TgT("Emitter")
#define T_EFFECT_TIME_DEFAULT 0
#define T_EFFECT_NOTIFY 1

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


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

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

#include "TgS Effect - Effect - Render.c_inc"




/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  File Local Types                                                                                                                                                      */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

TgTYPE_STRUCT(STg2_FX__Emitter__Render_Point,)
{
    /* --------------- Input --------------- */
    P_STg2_FX__Emitter                          m_psEmitter;
    P_STg2_FX__Emitter__Extend_Data             m_psExtend;
    CP_STg2_FX_Emitter__File_Data               m_psFile_Data;
    TgUINT32                                    m_uiPad0[2];
    TgVEC_M_F32_04                              m_vCam_Pos_W;
    TgVEC_M_F32_04                              m_vCam_Right;
    TgVEC_M_F32_04                              m_vCam_Up;
    TgVEC_M_F32_04                              m_vCam_Forward;
    TgVEC_M_F32_04                              m_vUV_Mask[4];
    TgVEC_M_F32_04                              m_vPivotX;
    TgVEC_M_F32_04                              m_vPivotY;
    CP_TgMAT_F32_44                             m_pxFrustum_S2C; /*« Screen to Camera (Inverse Proj) */
    TgFLOAT32                                   m_fAspect_Ratio;
    TgUINT32                                    m_uiPad1;

    /* --------------- Output -------------- */
    TgVEC_M_F32_04                              m_vRight;
    TgVEC_M_F32_04                              m_vUp;
    TgVEC_M_F32_04                              m_avPos_W[4];
    TgVEC_M_F32_04                              m_avBasis[2];
};




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

static TgVOID                                        tgFX_Effect__Emitter__Render_Init_Point( P_STg2_FX__Emitter__Render_Point, PC_STg2_FX_Rnd_Output );
static TgVOID                                        tgFX_Effect__Emitter__Reference_Frame( P_STg2_FX__Emitter__Render_Point, C_TgVEC_M_F32_04 );
static TgVOID                                        tgFX_Effect__Emitter__Render_Calculate_Point( P_STg2_FX__Emitter__Render_Point, CP_STg2_FX__Emitter__Particle );
static TgUINT32                                      tgFX__Render__Emitter_Render_Generate_Particle_Tangent_00(
                                                         P_STg2_FX__Emitter__Render_Point, PC_STg2_FX_Rnd_Output, PC_STg2_RN_Particle_Header, P_STg2_FX__Emitter );
static TgUINT32                                      tgFX__Render__Emitter_Render_Generate_Particle_Tangent_01(
                                                         P_STg2_FX__Emitter__Render_Point, PC_STg2_FX_Rnd_Output, PC_STg2_RN_Particle_Header, P_STg2_FX__Emitter );
TgFORCEINLINE TgVOID                                 tgFX_Effect__Emitter__Render_Write_Quad_00(
                                                         P_STg2_RN_Vertex_Particle_00, CP_STg2_FX__Emitter__Render_Point, CP_STg2_FX__Emitter__Particle );
TgFORCEINLINE TgVOID                                 tgFX_Effect__Emitter__Render_Write_Quad_01(
                                                         P_STg2_RN_Vertex_Particle_01, CP_STg2_FX__Emitter__Render_Point, CP_STg2_FX__Emitter__Particle );
TgFORCEINLINE TgVOID                                 tgFX_Effect__Emitter__Render_Write_Quad_Tangent_00(
                                                         P_STg2_RN_Vertex_Particle_00, CP_STg2_FX__Emitter__Render_Point, CP_STg2_FX__Emitter__Particle );
TgFORCEINLINE TgVOID                                 tgFX_Effect__Emitter__Render_Write_Quad_Tangent_01(
                                                         P_STg2_RN_Vertex_Particle_01, CP_STg2_FX__Emitter__Render_Point, CP_STg2_FX__Emitter__Particle );




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

/* ---- tgFX__Render__Emitter_Render_Memory_Particle_00 ------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgSIZE tgFX__Render__Emitter_Render_Memory_Particle_00( P_STg2_FX__Emitter UNUSED_PARAM psEmitter )
{
    /* #IMPLEMENT */
    return (0);
}


/* ---- tgFX__Render__Emitter_Render_Memory_Particle_01 ------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgSIZE tgFX__Render__Emitter_Render_Memory_Particle_01( P_STg2_FX__Emitter UNUSED_PARAM psEmitter )
{
    /* #IMPLEMENT */
    return (0);
}


/* ---- tgFX__Render__Emitter_Render_Generate_Particle_00 --------------------------------------------------------------------------------------------------------------- */
/* Implements: tgFX__Render__Emitter_Render_Generate_Particle_00 and tgFX__Render__Emitter_Render_Generate_Particle_Tangent_00                                            */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
#define T(A) A##_00
#include "TgS Effect - Emitter - Render.c_inc"
#undef T


/* ---- tgFX__Render__Emitter_Render_Generate_Particle_01 ---------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
#define T(A) A##_01
#include "TgS Effect - Emitter - Render.c_inc"
#undef T




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

/* ---- tgFX_Effect__Emitter__Render_Init_Point ------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
static TgVOID tgFX_Effect__Emitter__Render_Init_Point( P_STg2_FX__Emitter__Render_Point psPoint, PC_STg2_FX_Rnd_Output psRndOut )
{
    psPoint->m_psExtend = &(psPoint->m_psEmitter->m_sExtend);
    psPoint->m_psFile_Data = psPoint->m_psEmitter->m_psFile_Data;
    psPoint->m_vCam_Pos_W = psRndOut->m_psCamera->m_sCamera.m_vCam_Position.m_mData;
    psPoint->m_vCam_Right = psRndOut->m_psCamera->m_vCam_Right.m_mData;
    psPoint->m_vCam_Up = psRndOut->m_psCamera->m_vCam_Up.m_mData;
    psPoint->m_vCam_Forward = psRndOut->m_psCamera->m_vCam_Forward.m_mData;

    psPoint->m_vUV_Mask[0] = MS_SET_F32_04( 0.0F, 0.0F, 0.0F, 0.0F );
    psPoint->m_vUV_Mask[1] = MS_SET_F32_04( 0.0F, 1.0F, 0.0F, 1.0F );
    psPoint->m_vUV_Mask[2] = MS_SET_F32_04( 1.0F, 1.0F, 1.0F, 1.0F );
    psPoint->m_vUV_Mask[3] = MS_SET_F32_04( 1.0F, 0.0F, 1.0F, 0.0F );

    psPoint->m_vPivotX = MS_SET1_F32_04( psPoint->m_psFile_Data->m_fEmission_Pivot_X );
    psPoint->m_vPivotY = MS_SET1_F32_04( psPoint->m_psFile_Data->m_fEmission_Pivot_Y );

    psPoint->m_pxFrustum_S2C = &psRndOut->m_psCamera->m_xFrustum_S2C;
    psPoint->m_fAspect_Ratio = psRndOut->m_psCamera->m_sCamera.m_fAspect_Ratio;

#if TgS_DEBUG_EFFECT
    {
        TgBOOL                              bDraw;
        if ((TgTRUE == tgCN_Var_Query_Bool( &bDraw, T_NAME(g_tiFX_Debug__, __Draw_Debug) )) && (TgTRUE == bDraw))
        {
            TgMAT_F32_34                        xM0;
            TgVEC_F32_04                        qRot_W;
            TgVEC_F32_04                        vPos_W;

            qRot_W.m_mData = psPoint->m_psEmitter->m_qRot_W;
            vPos_W.m_mData = psPoint->m_psEmitter->m_vPos_W;

            F_Init_Quat_F32_34( &xM0, &qRot_W );
            F_INIT_T_F32_34( &xM0, &vPos_W );
            tgRN_DBG_Axes( &xM0, 0.1F );
            tgRN_DBG_Sphere( KTg_WHITE_709_U32, psPoint->m_psEmitter->m_vPos_W, 0.1F );
        };
    }
/*# TgS_DEBUG_EFFECT */
#endif
}


/* ---- tgFX_Effect__Emitter__Reference_Frame --------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
static TgVOID tgFX_Effect__Emitter__Reference_Frame( P_STg2_FX__Emitter__Render_Point psPoint, C_TgVEC_M_F32_04 vPos_W )
{
    TgVEC_F32_04                        vDirTest;
    TgVEC_M_F32_04                      vForward;

    psPoint->m_vRight = psPoint->m_vCam_Right;
    psPoint->m_vUp = psPoint->m_vCam_Up;

    switch (psPoint->m_psExtend->m_psFile_Data__Particle->m_enOrientation)
    {
        case ETgFX_PARTICLE_ORIENTATION__CAMERA_FACE_SPHERE:

            vForward = M_SUB_F32_04( vPos_W, psPoint->m_vCam_Pos_W );
            vForward = M_NORM_F32_04( vForward );
            vDirTest.m_mData = M_DOT_F32_04( psPoint->m_vCam_Up, vForward );
            if (TgTRUE != tgCM_NR1_F32( tgPM_ABS_F32( vDirTest.m.x ) ))
            {
                psPoint->m_vRight = M_UCX_F32_04( psPoint->m_vCam_Up, vForward );
                psPoint->m_vUp = M_UCX_F32_04( vForward, psPoint->m_vRight );
            }
            else
            {
                psPoint->m_vUp = M_UCX_F32_04( vForward, psPoint->m_vCam_Right );
                psPoint->m_vRight = M_UCX_F32_04( psPoint->m_vUp, vForward );
            };
            break;

        case ETgFX_PARTICLE_ORIENTATION__CAMERA_FACE_PLANE:
            break;

        case ETgFX_PARTICLE_ORIENTATION__CAMERA_FACE_SPHERE__FIXED_Y:

            vForward = M_SUB_F32_04( vPos_W, psPoint->m_vCam_Pos_W );
            vForward = M_NORM_F32_04( vForward );
            vDirTest.m_mData = M_DOT_F32_04( KTgV_UNIT_Y_F32_04.m_mData, vForward );
            if (TgTRUE != tgCM_NR1_F32( tgPM_ABS_F32( vDirTest.m.x ) ))
            {
                psPoint->m_vUp = KTgV_UNIT_Y_F32_04.m_mData;
                psPoint->m_vRight = M_UCX_F32_04( KTgV_UNIT_Y_F32_04.m_mData, vForward );
            }
            else
            {
                psPoint->m_vUp = KTgV_ZERO_F32_04.m_mData;
                psPoint->m_vRight = KTgV_ZERO_F32_04.m_mData;
            };
            break;

        case ETgFX_PARTICLE_ORIENTATION__CAMERA_FACE_PLANE__FIXED_Y:

            vDirTest.m_mData = M_DOT_F32_04( KTgV_UNIT_Y_F32_04.m_mData, psPoint->m_vCam_Right );
            if (TgTRUE != tgCM_NR1_F32( tgPM_ABS_F32( vDirTest.m.x ) ))
            {
                psPoint->m_vRight = M_UCX_F32_04( KTgV_UNIT_Y_F32_04.m_mData, M_CX_F32_04( psPoint->m_vCam_Right, KTgV_UNIT_Y_F32_04.m_mData ) );
            }
            else
            {
                psPoint->m_vRight = psPoint->m_vCam_Up;
            };

            psPoint->m_vUp = KTgV_UNIT_Y_F32_04.m_mData;
            break;

        case ETgFX_PARTICLE_ORIENTATION__CAMERA_FACE_SPHERE__FIXED_XZ:

            vForward = M_SUB_F32_04( vPos_W, psPoint->m_vCam_Pos_W );
            vForward = M_NORM_F32_04( vForward );
            vDirTest.m_mData = M_DOT_F32_04( KTgV_UNIT_Y_F32_04.m_mData, vForward );
            if (TgTRUE != tgCM_NR1_F32( tgPM_ABS_F32( vDirTest.m.x ) ))
            {
                psPoint->m_vRight = M_UCX_F32_04( KTgV_UNIT_Y_F32_04.m_mData, vForward );
                psPoint->m_vUp = M_UCX_F32_04( psPoint->m_vRight, KTgV_UNIT_Y_F32_04.m_mData );
            }
            else
            {
                psPoint->m_vRight = psPoint->m_vCam_Forward;
            };
            break;

        case ETgFX_PARTICLE_ORIENTATION__CAMERA_FACE_PLANE__FIXED_XZ:

            vDirTest.m_mData = M_DOT_F32_04( KTgV_UNIT_Y_F32_04.m_mData, psPoint->m_vCam_Right );
            if (TgTRUE != tgCM_NR1_F32( tgPM_ABS_F32( vDirTest.m.x ) ))
            {
                psPoint->m_vUp = M_UCX_F32_04( psPoint->m_vCam_Right, KTgV_UNIT_Y_F32_04.m_mData );
                psPoint->m_vRight = M_UCX_F32_04( KTgV_UNIT_Y_F32_04.m_mData, psPoint->m_vUp );
            }
            else
            {
                psPoint->m_vRight = psPoint->m_vCam_Forward;
            };
            break;

        case ETgFX_PARTICLE_ORIENTATION__SCREEN_SPACE:
            psPoint->m_vRight = KTgV_UNIT_X_F32_04.m_mData;
            psPoint->m_vUp = KTgV_UNIT_Y_F32_04.m_mData;
            break;

        case ETgFX_PARTICLE_ORIENTATION__VELOCITY_TANGENT:
        case ETgFX_PARTICLE_ORIENTATION__NONE:
        default:
            TgS_NO_DEFAULT(break);
    };
}

/* ---- tgFX_Effect__Emitter__Render_Calculate_Point -------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
static TgVOID tgFX_Effect__Emitter__Render_Calculate_Point( P_STg2_FX__Emitter__Render_Point psPoint, CP_STg2_FX__Emitter__Particle psParticle )
{
    STg2_FX_Calc_Quad                   sData;
    TgVEC_M_F32_04                      vLive_Time_Squared;
    TgVEC_M_F32_04                      vSpin_Accel;
    TgVEC_F32_04                        vSpin;

    sData.m_vPivot_X = psPoint->m_vPivotX;
    sData.m_vPivot_Y = psPoint->m_vPivotY;
    sData.m_vSize_X = M_MUL_F32_04( M_SPX_F32_04( psParticle->m_vSize ), psPoint->m_psEmitter->m_vScale );
    sData.m_vSize_Y = M_MUL_F32_04( M_SPY_F32_04( psParticle->m_vSize ), psPoint->m_psEmitter->m_vScale );
    sData.m_vPos_W = M_ADD_F32_04( psParticle->m_vPos_W, psParticle->m_vTurbulence );
    sData.m_vDir_Right = psPoint->m_vRight;
    sData.m_vDir_Up = psPoint->m_vUp;

    vLive_Time_Squared = M_MUL_F32_04( psParticle->m_vLive_Time, psParticle->m_vLive_Time );
    vSpin_Accel = M_MUL_F32_04( psParticle->m_vRVel_M_Acceleration, vLive_Time_Squared );
    vSpin_Accel = M_MUL_F32_04( MS_SET1_F32_04( 0.5F ), vSpin_Accel );
    vSpin.m_mData = M_ADD_F32_04( psParticle->m_qRot_M, vSpin_Accel );

    if (ETgFX_PARTICLE_ORIENTATION__SCREEN_SPACE == psPoint->m_psExtend->m_psFile_Data__Particle->m_enOrientation)
    {
        sData.m_vSize_Y = M_MUL_F32_04( sData.m_vSize_Y, MS_SET1_F32_04( psPoint->m_fAspect_Ratio ) );
    };

    tgFX_Calc_Quad( /* Output */ psPoint->m_avPos_W, psPoint->m_avBasis, /* Input */ vSpin.m.x, &sData );

    if (ETgFX_PARTICLE_ORIENTATION__SCREEN_SPACE == psPoint->m_psExtend->m_psFile_Data__Particle->m_enOrientation)
    {
        TgVEC_M_F32_04                      vBound;
        TgVEC_M_F32_04                      vAdjust;
        TgVEC_M_F32_04                      vW;
        TgSINT32                            iVert;

        vBound = MS_SET_F32_04( 1.0F, 1.0F, KTgMAX_F32, KTgMAX_F32 );

        for (iVert = 0; iVert < 4; ++iVert)
        {
            psPoint->m_avPos_W[iVert] = M_BND_F32_04( psPoint->m_avPos_W[iVert], vBound );
            vAdjust = M_SETV_F32_04( psPoint->m_avPos_W[iVert] );
            vAdjust = M_TX_F32_44( psPoint->m_pxFrustum_S2C, vAdjust );
            vW = M_SPW_F32_04( vAdjust );
            vAdjust = M_DIV_F32_04( vAdjust, vW );
            psPoint->m_avPos_W[iVert] = M_SETP_F32_04( vAdjust );
        };
    };

#if TgS_DEBUG_EFFECT
    {
        TgBOOL                              bDraw;
        if ((TgTRUE == tgCN_Var_Query_Bool( &bDraw, T_NAME(g_tiFX_Debug__, __Draw_Debug) )) && (TgTRUE == bDraw))
        {
            tgRN_DBG_Sphere( KTg_RED_709_U32, sData.m_vPos_W, 0.1F );
        };
    }
/*# TgS_DEBUG_EFFECT */
#endif
}


/* ---- tgFX_Effect__Emitter__Render_Write_Quad_00 ---------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgFORCEINLINE TgVOID tgFX_Effect__Emitter__Render_Write_Quad_00(
    P_STg2_RN_Vertex_Particle_00 psVert, CP_STg2_FX__Emitter__Render_Point psPoint, CP_STg2_FX__Emitter__Particle psParticle )
{
    TgVEC_M_F32_04                      vUV;
    TgSINT32                            iVert;

    for (iVert = 0; iVert < 4; ++iVert)
    {
        vUV = M_MAD_F32_04( psPoint->m_vUV_Mask[iVert], psParticle->m_vUV_01_Scale, psParticle->m_vUV_01_Constant );

        psVert[iVert].m_vS0.m_mData = psPoint->m_avPos_W[iVert];
        psVert[iVert].m_vUV.m_mData = vUV;
        psVert[iVert].m_vCL.m_mData = psParticle->m_vColour;
    };
}


/* ---- tgFX_Effect__Emitter__Render_Write_Quad_01 ---------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgFORCEINLINE TgVOID tgFX_Effect__Emitter__Render_Write_Quad_01(
    P_STg2_RN_Vertex_Particle_01 psVert, CP_STg2_FX__Emitter__Render_Point psPoint, CP_STg2_FX__Emitter__Particle psParticle )
{
    TgVEC_M_F32_04                      vUV;
    TgSINT32                            iVert;

    for (iVert = 0; iVert < 4; ++iVert)
    {
        vUV = M_MAD_F32_04( psPoint->m_vUV_Mask[iVert], psParticle->m_vUV_01_Scale, psParticle->m_vUV_01_Constant );

        psVert[iVert].m_vS0.m_mData = psPoint->m_avPos_W[iVert];
        psVert[iVert].m_vT0.m_mData = psPoint->m_avBasis[0];
        psVert[iVert].m_vB0.m_mData = psPoint->m_avBasis[1];
        psVert[iVert].m_vUV.m_mData = vUV;
        psVert[iVert].m_vCL.m_mData = psParticle->m_vColour;
    };
}


/* ---- tgFX_Effect__Emitter__Render_Write_Quad_Tangent_00 ---------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgFORCEINLINE TgVOID tgFX_Effect__Emitter__Render_Write_Quad_Tangent_00(
    P_STg2_RN_Vertex_Particle_00 psVert, CP_STg2_FX__Emitter__Render_Point psPoint, CP_STg2_FX__Emitter__Particle psParticle )
{
    TgVEC_M_F32_04                      vUV;
    TgVEC_M_F32_04                      vE0;
    TgVEC_M_F32_04                      vN0;
    TgVEC_F32_04                        vDirTest;
    TgBOOL                              bQuad_Camera_Facing;
    TgSINT32                            iVert;

    vE0 = M_SUB_F32_04( psPoint->m_avBasis[0], psPoint->m_avBasis[1] );
    vN0 = M_CX_F32_04( vE0, psPoint->m_avBasis[1] );
    vDirTest.m_mData = M_DOT_F32_04( vN0, psPoint->m_vCam_Forward );
    bQuad_Camera_Facing = tgCM_NR0_F32( vDirTest.m.x );

    if (TgTRUE != bQuad_Camera_Facing)
    {
        for (iVert = 0; iVert < 4; ++iVert)
        {
            vUV = M_MAD_F32_04( psPoint->m_vUV_Mask[iVert], psParticle->m_vUV_01_Scale, psParticle->m_vUV_01_Constant );

            psVert[iVert].m_vS0.m_mData = psPoint->m_avPos_W[iVert];
            psVert[iVert].m_vUV.m_mData = vUV;
            psVert[iVert].m_vCL.m_mData = psParticle->m_vColour;
        };
    }
    else
    {
        for (iVert = 0; iVert < 4; ++iVert)
        {
            vUV = M_MAD_F32_04( psPoint->m_vUV_Mask[3 - iVert], psParticle->m_vUV_01_Scale, psParticle->m_vUV_01_Constant );

            psVert[iVert].m_vS0.m_mData = psPoint->m_avPos_W[3 - iVert];
            psVert[iVert].m_vUV.m_mData = vUV;
            psVert[iVert].m_vCL.m_mData = psParticle->m_vColour;
        };
    };
}


/* ---- tgFX_Effect__Emitter__Render_Write_Quad_Tangent_01 ---------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgFORCEINLINE TgVOID tgFX_Effect__Emitter__Render_Write_Quad_Tangent_01(
    P_STg2_RN_Vertex_Particle_01 psVert, CP_STg2_FX__Emitter__Render_Point psPoint, CP_STg2_FX__Emitter__Particle psParticle )
{
    TgVEC_M_F32_04                      vUV;
    TgVEC_M_F32_04                      vE0;
    TgVEC_M_F32_04                      vN0;
    TgVEC_F32_04                        vDirTest;
    TgBOOL                              bQuad_Camera_Facing;
    TgSINT32                            iVert;

    vE0 = M_SUB_F32_04( psPoint->m_avBasis[0], psPoint->m_avBasis[1] );
    vN0 = M_CX_F32_04( vE0, psPoint->m_avBasis[1] );
    vDirTest.m_mData = M_DOT_F32_04( vN0, psPoint->m_vCam_Forward );
    bQuad_Camera_Facing = tgCM_NR0_F32( vDirTest.m.x );

    if (TgTRUE != bQuad_Camera_Facing)
    {
        for (iVert = 0; iVert < 4; ++iVert)
        {
            vUV = M_MAD_F32_04( psPoint->m_vUV_Mask[iVert], psParticle->m_vUV_01_Scale, psParticle->m_vUV_01_Constant );

            psVert[iVert].m_vS0.m_mData = psPoint->m_avPos_W[iVert];
            psVert[iVert].m_vT0.m_mData = psPoint->m_avBasis[0];
            psVert[iVert].m_vB0.m_mData = psPoint->m_avBasis[1];
            psVert[iVert].m_vUV.m_mData = vUV;
            psVert[iVert].m_vCL.m_mData = psParticle->m_vColour;
        };
    }
    else
    {
        for (iVert = 0; iVert < 4; ++iVert)
        {
            vUV = M_MAD_F32_04( psPoint->m_vUV_Mask[3 - iVert], psParticle->m_vUV_01_Scale, psParticle->m_vUV_01_Constant );

            psVert[iVert].m_vS0.m_mData = psPoint->m_avPos_W[3 - iVert];
            psVert[iVert].m_vT0.m_mData = psPoint->m_avBasis[0];
            psVert[iVert].m_vB0.m_mData = psPoint->m_avBasis[1];
            psVert[iVert].m_vUV.m_mData = vUV;
            psVert[iVert].m_vCL.m_mData = psParticle->m_vColour;
        };
    };
}