//////////////////////////////////////////////////////////////////////////////
//
// Asura_Platform_Beam.cpp
//
// Copyright (c) 2003 Rebellion. All rights reserved.
//
// Description:
//
//     PS2 rendering of laserbeam-type things
//
//    (PSJE-12.4.2003 - Initial implementation)
//
//////////////////////////////////////////////////////////////////////////////

// I N C L U D E S ///////////////////////////////////////////////////////////

#include "Core/Asura.h"

// Engine independent.
#include "Camera/Asura_Camera.h"
#include "Core/Asura_TextureManagement.h"
#include "Core/Asura_TiledTextureManagement.h"
#include "Rendering/Asura_Render.h"
#include "SpecialFX/Asura_Beam_System.h"

// Engine platform-specific.
#include "Core/Asura_PS2_DMA.h"
#include "Rendering/Asura_PlatformRendering.h"
#include "Rendering/Asura_PlatformRenderStates.h"
#include "Rendering/Asura_PlatformTextureManagement.h"
#include "Rendering/Asura_PS2_BeamDefines.h"
#include "Rendering/Asura_PS2_DeferredRendering.h"
#include "Rendering/Asura_PS2_GS.h"
#include "Rendering/Asura_PS2_RenderingOptions.h"
#include "Rendering/Asura_PS2_VU1.h"

// T Y P E S /////////////////////////////////////////////////////////////////

// Info per camera for each beam.
struct BeamRenderInfo
{
    bool           bVis;      // Remaining fields only valid if this is true.
    bool           bEndBeam;
    Asura_Vector_3 xToCamDir;
    Asura_Vector_3 xHeadPos;
};

// C L A S S   I M P L E M E N T A T I O N S /////////////////////////////////

void Asura_Beam_System::Platform_Initialise()
{
}

void Asura_Beam_System::Platform_Shutdown()
{
}

void Asura_Beam_System::Platform_RenderStart( void )
{
    // Set the texture manager buffer layout - we probably don't need this because whatever mapping the TM is using the beam texture will fit... probably
	// (PSJE - 02.09.03 - We do need this to tell the texture manger we are starting a new type)
    Asura_PS2_TextureManagement::SetBufferLayout( ASURA_PS2_TEXBFRLAYOUT_2_LARGE );

    // Get the beam texture id (shouldn't this be part of each beam, or part of the beam system class ?)
	int iTextureID = s_iTiledTextureTextureID;

    // Upload the beam texture
    const bool bTextureUploaded = Asura_PS2_TextureManagement::UploadTexture( iTextureID );
    
    // And setup the texture environment
    Asura_PS2_TextureManagement::SetupTextureEnvironment( bTextureUploaded,
                                                          ASURA_PS2_TEXREGFLAG_ALL,
                                                          iTextureID,
                                                          Asura_PS2_TextureManagement::BFR_AUTO,
                                                          SCE_GS_LINEAR,
                                                          SCE_GS_NEAREST_MIPMAP_LINEAR );
    
    // Set the render state
    Asura_PlatformRenderStates::CreateDefaultRenderStatePacket( Asura_PlatformRenderStates::CONTEXT_1 );
    Asura_PlatformRenderStates::SetZBufferWriteEnabled(false);
// (MP - 03.07.2007) Crappy partial support that's sufficient for the Simpsons.
#ifdef ASURA_BEAMS_ALL_MODES
    if( s_apxBeamPtrs[0]->GetTranslucencyMode() != ASURA_TRANSLUCENCY_NORMAL )
    {
        Asura_PlatformRenderStates::SetTranslucencyMode( s_apxBeamPtrs[0]->GetTranslucencyMode() );
    }
#else
    Asura_PlatformRenderStates::SetTranslucencyMode( ASURA_TRANSLUCENCY_GLOWING );
#endif
    Asura_PlatformRenderStates::ApplyRenderStates();

    // Upload the renderer
    Asura_PS2_VU1::LoadRenderer( Asura_PS2_VU1::RENDERER_BEAM );

    // Initialise the renderer
    const u_int uSetupQWords = 2;

    Asura_PS2_QW* pxOut = Asura_PS2_DeferredRendering::GetVifBuffer(uSetupQWords+2);

    pxOut->u32s[0] = PY_DMA_CNT | (uSetupQWords+1);
    pxOut->u32s[1] = 0;
    pxOut->u32s[2] = SCE_VIF1_SET_STCYCL( 1, 1, 0 ),
    pxOut->u32s[3] = SCE_VIF1_SET_UNPACK(0, uSetupQWords, CMD_V4_32, 0);
    pxOut++;

    // Upload the camera setup gif tag
    pxOut->u64s[0] = SCE_GIF_SET_TAG( 2, 0, 0, 0, SCE_GIF_PACKED, 1 );
    pxOut->u64s[1] = SCE_GIF_PACKED_AD;
    pxOut++;

    // Upload the drawing gif tag
    const u_int uPrimType = (Asura_Render::GetWireframe()) ? SCE_GS_PRIM_LINESTRIP : SCE_GS_PRIM_TRISTRIP;
    pxOut->u64s[0] = SCE_GIF_SET_TAG( 0,                // NLOOP - set in micro code
                                      0,                // EOP (End Of Packet)
                                      1,                // PRE (PRIM field Enable)
                                      SCE_GS_SET_PRIM( uPrimType,                // PRIM (Type of drawing primitive)
                                                       1,                        // IIP (Flat Shading/Gouraud Shading)
                                                       1,                        // TME (Texture Mapping Enabled)
                                                       0,                        // FGE (Fogging Enabled)
                                                       1,                        // ABE (Alpha Blending Enabled)
                                                       0,                        // AA1 (1 Pass Anti-Aliasing Enabled)
                                                       0,                        // FST (Method of specifying Texture Coords)
                                                       0,                        // CTXT (Context)
                                                       0 ),                        // FIX (Fragment Value Control)
                                      SCE_GIF_PACKED,    // FLG (Data format, 0 = PACKED, 1 = REGLIST, 2 = IMAGE)
                                      3 );                // NREG (Number of registers)
    pxOut->u64s[1] = (SCE_GS_XYZ2<<8) | (SCE_GS_RGBAQ<<4) | (SCE_GS_ST<<0);
    pxOut++;

    // Kick off the setup code and set the double buffer layout
    pxOut->u32s[0] = SCE_VIF1_SET_NOP(0);
    pxOut->u32s[1] = SCE_VIF1_SET_MSCAL(0,0);
    pxOut->u32s[2] = SCE_VIF1_SET_BASE( ASURA_PS2_BEAM__ADDR__INPUT_BUFFER_0, 0 );
    pxOut->u32s[3] = SCE_VIF1_SET_OFFSET( ASURA_PS2_BEAM__SIZE__INPUT_BUFFER, 0 );
    pxOut++;
}

void Asura_Beam_System::Platform_Render(void)
{
    BeamRenderInfo* const pxBeamRenderInfo = reinterpret_cast<BeamRenderInfo*>( Asura_PS2_SPR_Alloc(0, 1024) );
    Asura_Assert( ASURA_MAX_NO_OF_BEAMS * sizeof(BeamRenderInfo) <= (1024 << 4), "Beam render info won't fit in SPR since ASURA_MAX_NO_OF_BEAMS is so high." );

    const float fEndBeamThreshold = 1.0f - s_fEndEffectAngleTolerance;

    u_int uCameraBuffer = 0;
    for( int i = 0; i < Asura_Camera::GetNumberOfCameras(); ++i )
    {
        if( Asura_Camera::IsCameraActive() )
        {
            Asura_Camera::SetCameraIndex(i);

            const Asura_Vector_3& xCameraPos = *Asura_Camera::GetPosition();

            Asura_Vector_3 xCameraDir;
            Asura_Camera::GetForwardVector( xCameraDir );
            
            const Asura_Guid uEntityToIgnore = Asura_Camera::GetEntityToIgnore();

			// Calculate how much data we'll be sending and how many packets that will need
			u_int uVertexQty = 0;
			u_int uPacketQty = 1;
			u_int uSpaceInPacket = ASURA_PS2_BEAM__MAX_VERTICES_PER_BUFFER;

            for( u_int u = 0; u < s_uNumActiveBeams; ++u )
            {
                Asura_Beam*     pxBeam      = s_apxBeamPtrs[u];
                BeamRenderInfo& xRenderInfo = pxBeamRenderInfo[u];

                xRenderInfo.bVis = false;

#ifdef ASURA_BEAMS_SUPPORT_CAMERA_SELECTION
                if( pxBeam->m_uDontRenderIfCameraIgnoresThisGuid == uEntityToIgnore ) { continue; }
                if( pxBeam->m_uOnlyRenderIfCameraIgnoresThisGuid != ASURA_GUID_UNREGISTERED && pxBeam->m_uOnlyRenderIfCameraIgnoresThisGuid != uEntityToIgnore ) { continue; }
#endif

				if( pxBeam->IsInvisible() ) { continue; }
				pxBeam->SetDontUpdateUntilRenderedOnce( false );

                xRenderInfo.xHeadPos = pxBeam->CalcCurHeadPos();

                {
                    Asura_Vector_3 xCentre = pxBeam->m_xTailPosition;
                    xCentre += xRenderInfo.xHeadPos;
                    xCentre *= 0.5f;

                    if( !Asura_Camera::IsSphereInFrustum(xCentre, 0.5f * pxBeam->m_fLength) ) { continue; }
                }

                xRenderInfo.bVis = true;

                xRenderInfo.xToCamDir = xCameraPos - pxBeam->m_xTailPosition;
                xRenderInfo.xToCamDir.Normalise();

                xRenderInfo.bEndBeam = ( Asura_Maths::Abs(xRenderInfo.xToCamDir * pxBeam->m_xDirection) > fEndBeamThreshold );

                u_int uVertsInBeam = ( xRenderInfo.bEndBeam ? 8 : 6 );
                if( uSpaceInPacket < uVertsInBeam )
                {
                    uPacketQty++;
                    uSpaceInPacket = ASURA_PS2_BEAM__MAX_VERTICES_PER_BUFFER;
                }
                uSpaceInPacket -= uVertsInBeam;

                uVertexQty += uVertsInBeam;
            }

            if( !uVertexQty ) { continue; }

            // Setup camera buffer flags
            const u_int uCameraBufferAddr = ASURA_PS2_BEAM__ADDR__CAMERA_BUFFER_0 + (uCameraBuffer * ASURA_PS2_BEAM__SIZE__CAMERA_BUFFER);
            const u_int uCameraBufferFlag = ( uCameraBuffer ? ASURA_PS2_BEAM__FLAG__CAMERA_BUFFER : 0 );
            uCameraBuffer = 1 - uCameraBuffer;

            // Allocate space for the vertices in the draw list
            const u_int uPacketQWs = uVertexQty*3 + uPacketQty + 1;
            const u_int uCameraQWs = 14;
            const u_int uTotalDmaQws = uCameraQWs + uPacketQWs;

            Asura_PS2_QW* const pxBase = Asura_PS2_DeferredRendering::GetVifBuffer( uTotalDmaQws + 1 );
            Asura_PS2_QW* pxOut = pxBase;

            // Create dma tag and unpack camera        
            pxOut->u32s[0] = PY_DMA_CNT | uTotalDmaQws;
            pxOut->u32s[1] = 0;
            pxOut->u32s[2] = SCE_VIF1_SET_NOP(0);
            pxOut->u32s[3] = SCE_VIF1_SET_UNPACK( uCameraBufferAddr, uCameraQWs, CMD_V4_32, 0);
            pxOut++;

            // Upload this cameras matricies
            sceVu0CopyMatrix( &pxOut->Vu0FVec, Asura_PS2_VU1::GetWorldToScreenMat() );
            pxOut += 4;
            sceVu0CopyMatrix( &pxOut->Vu0FVec, Asura_PS2_VU1::GetWorldToClipMatScreen() );
            pxOut += 4;
            sceVu0CopyMatrix( &pxOut->Vu0FVec, Asura_PS2_VU1::GetClipToScreenMat() );
            pxOut += 4;

            // Add the SCISSOR and OFFSET settings
            pxOut = Asura_PS2_GS::GetViewportSetupGifCmds( i, Asura_PS2_GS::CONTEXT_1, pxOut );

            // Add the packets
            bool  bFirstPacket = true;
                  uSpaceInPacket = ASURA_PS2_BEAM__MAX_VERTICES_PER_BUFFER;;
            u_int uVertsInPacket = 0;
            Asura_PS2_QW *pxPacketStart = pxOut;
            pxOut++;

            for( u_int u = 0; u < s_uNumActiveBeams; ++u )
            {
                const Asura_Beam*     pxBeam          = s_apxBeamPtrs[u];
                const BeamRenderInfo& xBeamRenderInfo = pxBeamRenderInfo[u];

                if( !xBeamRenderInfo.bVis ) { continue; }

                const Asura_Vector_3& xBeamStart = pxBeam->m_xTailPosition;
                const Asura_Vector_3& xBeamEnd   = xBeamRenderInfo.xHeadPos;

                Asura_Vector_3 xPerpVector = pxBeam->m_xDirection ^ xBeamRenderInfo.xToCamDir;
                xPerpVector.Normalise();

                const Asura_Vector_3 xUp    = xCameraDir ^ xPerpVector;
                const Asura_Vector_3 xRight = xCameraDir ^ xUp;

                float fTailRadius, fHeadRadius;
                pxBeam->CalcCurRadii( &fTailRadius, &fHeadRadius );

                const u_int uVertsInBeam = ( xBeamRenderInfo.bEndBeam ? 8 : 6 );

                // Is there space in this packet for this beam ?
                if( uSpaceInPacket < uVertsInBeam )
                {
                    pxPacketStart->u32s[0] = (bFirstPacket) ? SCE_VIF1_SET_NOP(0) : SCE_VIF1_SET_MSCNT(0);
                    pxPacketStart->u32s[1] = SCE_VIF1_SET_NOP(0);
                    pxPacketStart->u32s[2] = SCE_VIF1_SET_ITOP( uVertsInPacket | uCameraBufferFlag, 0);
                    pxPacketStart->u32s[3] = SCE_VIF1_SET_UNPACKR( 0, uVertsInPacket*3, Asura_PS2_VU1::VIFPK_V4_32, false ); 

                    bFirstPacket   = false;
                    uSpaceInPacket = ASURA_PS2_BEAM__MAX_VERTICES_PER_BUFFER;
                    uVertsInPacket = 0;
                    pxPacketStart  = pxOut;
                    pxOut++;
                }

                // Update packet stats
                uSpaceInPacket -= uVertsInBeam;
                uVertsInPacket += uVertsInBeam;

                // Calculate colours.
                u_long128 uTailRGBA, uHeadRGBA;
                pxBeam->CalcCurColours( reinterpret_cast<Asura_RGBA*>(&uTailRGBA), reinterpret_cast<Asura_RGBA*>(&uHeadRGBA) ); // *cough*

                // Get tiled texture info for this beam.
	            const Asura_TiledTextureInfo* pxTileInfo = Asura_TiledTextureManagement::GetTileInfo( pxBeam->GetTemplate()->iTileHandle );
                
                // That shouldn't fail since we check for it in independent
                // code when trying to create the beam.
	            Asura_Assert( pxTileInfo, "" );

                const float fTLU  = pxTileInfo->m_fu1;
                const float fBRU  = pxTileInfo->m_fu2;
                const float fAvgU = 0.5f * (fTLU + fBRU);

                const float fBRV  = pxTileInfo->m_fv2;
                const float fTLV  = pxTileInfo->m_fv1;
                const float fAvgV = 0.5f * (fTLV + fBRV);

                if( xBeamRenderInfo.bEndBeam )
				{
                    {
                        const Asura_Vector_3 xVertex = xBeamStart + (xUp * (fTailRadius) );
                        pxOut->f32s[0] = xVertex.x;
                        pxOut->f32s[1] = xVertex.y;
                        pxOut->f32s[2] = xVertex.z;
                        pxOut->u32s[3] = 0x8000;
                        pxOut++;
                        pxOut->f32s[0] = fTLU; // uv 0
                        pxOut->f32s[1] = fTLV;
                        pxOut++;
                        pxOut->u128 = uTailRGBA;
                        pxOut++;
                    }
                    {
                        const Asura_Vector_3 xVertex = xBeamStart + (xRight * (-fTailRadius) );
                        pxOut->f32s[0] = xVertex.x;
                        pxOut->f32s[1] = xVertex.y;
                        pxOut->f32s[2] = xVertex.z;
                        pxOut->u32s[3] = 0x8000;
                        pxOut++;
                        pxOut->f32s[0] = fTLU;  // uv 1
                        pxOut->f32s[1] = fAvgV;
                        pxOut++;
                        pxOut->u128 = uTailRGBA;
                        pxOut++;
                    }
                    {
                        const Asura_Vector_3 xVertex = xBeamStart + (xRight * (fTailRadius) );
                        pxOut->f32s[0] = xVertex.x;
                        pxOut->f32s[1] = xVertex.y;
                        pxOut->f32s[2] = xVertex.z;
                        pxOut->u32s[3] = 0;
                        pxOut++;
                        pxOut->f32s[0] = fAvgU; // uv 2
                        pxOut->f32s[1] = fTLV;
                        pxOut++;
                        pxOut->u128 = uTailRGBA;
                        pxOut++;
                    }			 
                    {
                        const Asura_Vector_3 xVertex = xBeamStart + (xUp * (-fTailRadius) );
                        pxOut->f32s[0] = xVertex.x;
                        pxOut->f32s[1] = xVertex.y;
                        pxOut->f32s[2] = xVertex.z;
                        pxOut->u32s[3] = 0;
                        pxOut++;
                        pxOut->f32s[0] = fTLU; // uv 2
                        pxOut->f32s[1] = fTLV;
                        pxOut++;
                        pxOut->u128 = uTailRGBA;
                        pxOut++;
                    }
					{
                        const Asura_Vector_3 xVertex = xBeamEnd + (xUp * (fTailRadius) );
                        pxOut->f32s[0] = xVertex.x;
                        pxOut->f32s[1] = xVertex.y;
                        pxOut->f32s[2] = xVertex.z;
                        pxOut->u32s[3] = 0x8000;
                        pxOut++;
                        pxOut->f32s[0] = fBRU; // uv 0
                        pxOut->f32s[1] = fBRV;
                        pxOut++;
                        pxOut->u128 = uHeadRGBA;
                        pxOut++;
                    }
                    {
                        const Asura_Vector_3 xVertex = xBeamEnd + (xRight * (-fTailRadius) );
                        pxOut->f32s[0] = xVertex.x;
                        pxOut->f32s[1] = xVertex.y;
                        pxOut->f32s[2] = xVertex.z;
                        pxOut->u32s[3] = 0x8000;
                        pxOut++;
                        pxOut->f32s[0] = fBRU;  // uv 1
                        pxOut->f32s[1] = fAvgV;
                        pxOut++;
                        pxOut->u128 = uHeadRGBA;
                        pxOut++;
                    }
                    {
                        const Asura_Vector_3 xVertex = xBeamEnd + (xRight * (fTailRadius) );
                        pxOut->f32s[0] = xVertex.x;
                        pxOut->f32s[1] = xVertex.y;
                        pxOut->f32s[2] = xVertex.z;
                        pxOut->u32s[3] = 0;
                        pxOut++;
                        pxOut->f32s[0] = fAvgU; // uv 2
                        pxOut->f32s[1] = fBRV;
                        pxOut++;
                        pxOut->u128 = uHeadRGBA;
                        pxOut++;
                    }				 
                    {
                        const Asura_Vector_3 xVertex = xBeamEnd + (xUp * (-fTailRadius) );
                        pxOut->f32s[0] = xVertex.x;
                        pxOut->f32s[1] = xVertex.y;
                        pxOut->f32s[2] = xVertex.z;
                        pxOut->u32s[3] = 0;
                        pxOut++;
                        pxOut->f32s[0] = fBRU; // uv 2
                        pxOut->f32s[1] = fBRV;
                        pxOut++;
                        pxOut->u128 = uHeadRGBA;
                        pxOut++;
                    }
					// keep track of num triangles
					Asura_PS2_Render::UpdateTriStats( 6, 1 );
                }
                else 				
                {
                    // Add gif tag
                    // vertex 0 at top and nearest
                    //        +v0 
                    // + v1        + v2
                    // + v3        + v4
                    //        +v5
                    {
                        const Asura_Vector_3 xVertex = xBeamStart + (xUp * (fTailRadius) );
                        pxOut->f32s[0] = xVertex.x;
                        pxOut->f32s[1] = xVertex.y;
                        pxOut->f32s[2] = xVertex.z;
                        pxOut->u32s[3] = 0x8000;
                        pxOut++;
                        pxOut->f32s[0] = fTLU; // uv 0
                        pxOut->f32s[1] = fTLV;
                        pxOut++;
                        pxOut->u128 = uTailRGBA;
                        pxOut++;
                    }
                    {
                        const Asura_Vector_3 xVertex = xBeamStart + (xRight * (-fTailRadius) );
                        pxOut->f32s[0] = xVertex.x;
                        pxOut->f32s[1] = xVertex.y;
                        pxOut->f32s[2] = xVertex.z;
                        pxOut->u32s[3] = 0x8000;
                        pxOut++;
                        pxOut->f32s[0] = fTLU;  // uv 1
                        pxOut->f32s[1] = fAvgV;
                        pxOut++;
                        pxOut->u128 = uTailRGBA;
                        pxOut++;
                    }
                    {
                        const Asura_Vector_3 xVertex = xBeamStart + (xRight * (fTailRadius) );
                        pxOut->f32s[0] = xVertex.x;
                        pxOut->f32s[1] = xVertex.y;
                        pxOut->f32s[2] = xVertex.z;
                        pxOut->u32s[3] = 0;
                        pxOut++;
                        pxOut->f32s[0] = fAvgU; // uv 2
                        pxOut->f32s[1] = fTLV;
                        pxOut++;
                        pxOut->u128 = uTailRGBA;
                        pxOut++;
                    }
                    {
                        const Asura_Vector_3 xVertex = xBeamEnd + (xRight * (-fHeadRadius) );
                        pxOut->f32s[0] = xVertex.x;
                        pxOut->f32s[1] = xVertex.y;
                        pxOut->f32s[2] = xVertex.z;
                        pxOut->u32s[3] = 0;
                        pxOut++;
                        pxOut->f32s[0] = fAvgU; // uv 3
                        pxOut->f32s[1] = fBRV;
                        pxOut++;
                        pxOut->u128 = uHeadRGBA;
                        pxOut++;
                    }
                    {
                        const Asura_Vector_3 xVertex = xBeamEnd + (xRight * (fHeadRadius) );
                        pxOut->f32s[0] = xVertex.x;
                        pxOut->f32s[1] = xVertex.y;
                        pxOut->f32s[2] = xVertex.z;
                        pxOut->u32s[3] = 0;
                        pxOut++;
                        pxOut->f32s[0] = fBRU;  // uv 4
                        pxOut->f32s[1] = fAvgV;
                        pxOut++;
                        pxOut->u128 = uHeadRGBA;
                        pxOut++;
                    }
                    {
                        const Asura_Vector_3 xVertex = xBeamEnd + (xUp * (-fHeadRadius) );
                        pxOut->f32s[0] = xVertex.x;
                        pxOut->f32s[1] = xVertex.y;
                        pxOut->f32s[2] = xVertex.z;
                        pxOut->u32s[3] = 0;
                        pxOut++;
                        pxOut->f32s[0] = fBRU; // uv 5
                        pxOut->f32s[1] = fBRV;
                        pxOut++;
                        pxOut->u128 = uHeadRGBA;
                        pxOut++;
                    }
					// keep track of num triangles
					Asura_PS2_Render::UpdateTriStats( 4, 1 );
				}
            }

            // Finish of the last packet
            pxPacketStart->u32s[0] = ( bFirstPacket ? SCE_VIF1_SET_NOP(false) : SCE_VIF1_SET_MSCNT(false) );
            pxPacketStart->u32s[1] = SCE_VIF1_SET_NOP( false );
            pxPacketStart->u32s[2] = SCE_VIF1_SET_ITOP( uVertsInPacket | uCameraBufferFlag, false );
            pxPacketStart->u32s[3] = SCE_VIF1_SET_UNPACKR( 0, uVertsInPacket*3, Asura_PS2_VU1::VIFPK_V4_32, false );
            // And add it's kick
            pxOut->u32s[0] = SCE_VIF1_SET_MSCNT( false );
            pxOut->u32s[1] = SCE_VIF1_SET_NOP( false );
            pxOut->u32s[2] = SCE_VIF1_SET_NOP( false );
            pxOut->u32s[3] = SCE_VIF1_SET_NOP( false );
            pxOut++;
        }
    }

    ;// Add a final flush
    Asura_PS2_QW * const pxFlush = Asura_PS2_DeferredRendering::GetVifBuffer( 1 );
    pxFlush->u32s[0] = PY_DMA_CNT | 0;
    pxFlush->u32s[1] = 0;
    pxFlush->u32s[2] = SCE_VIF1_SET_FLUSH(0);
    pxFlush->u32s[3] = SCE_VIF1_SET_NOP(0);

    Asura_PS2_SPR_Dealloc( reinterpret_cast<Asura_PS2_QW*>(pxBeamRenderInfo) );
}
 
void Asura_Beam_System::Platform_RenderEnd( void )
{
}
