The-Simpsons-Hit-and-Run/game/code/render/DSG/LensFlareDSG.cpp

589 lines
16 KiB
C++

//========================================================================
// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
//
// File: LensFlareDSG.cpp
//
// Description: Implementation for LensFlareDSG class.
//
//========================================================================
//========================================
// System Includes
//========================================
//========================================
// Project Includes
//========================================
#include <render/DSG/LensFlareDSG.h>
#include <p3d/anim/compositedrawable.hpp>
#include <p3d/billboardobject.hpp>
#include <p3d/utility.hpp>
#include <pddi/pddiext.hpp>
// DEBUG stuff
#include <worldsim/avatarmanager.h>
#include <worldsim/character/character.h>
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
//************************************************************************
//
// Global Data, Local Data, Local Classes
//
//************************************************************************
const float INTENSITY_CHANGE_PER_FRAME = 0.1f;
const int MAX_NUM_FLARES = 20;
SwapArray< LensFlareDSG* > LensFlareDSG::spDrawQueue(MAX_NUM_FLARES);
SwapArray< LensFlareDSG* > LensFlareDSG::spVisTestQueue(MAX_NUM_FLARES);
unsigned LensFlareDSG::sP3DVisibilityCounter = 0;
static rmt::Vector s_PixelPos(320,240,0);
#ifdef RAD_PS2
const tColour PS2_VISIBILITY_MESH_COLOUR = tColour( 0, 0,0,0 );
#endif
static rmt::Vector dstart,dend;
// Clears the flare draw queue. Should be done after they are drawn
void LensFlareDSG::ClearAllFlares()
{
for (int i = 0 ; i < spDrawQueue.mUseSize ; i++)
{
spDrawQueue[ i ]->Release();
}
spDrawQueue.ClearUse();
}
// Draws every flare in the draw queue
void LensFlareDSG::DisplayAllFlares()
{
// rTuneAssert( spDrawQueue.mUseSize < 2 );
for (int i = 0 ; i < spDrawQueue.mUseSize ; i++)
{
spDrawQueue[ i ]->DisplayImmediate();
}
ClearAllFlares();
}
// Adds a flare to the draw queue
void LensFlareDSG::PostDisplayFlare( LensFlareDSG* pFlare )
{
spDrawQueue.Add( pFlare );
pFlare->AddRef();
}
// Checks all queued flares to see if they are visible
void LensFlareDSG::ReadFrameBufferIntensities()
{
#ifndef RAD_PS2
pddiExtVisibilityTest* mVisibilityTestExtension = static_cast<pddiExtVisibilityTest*> (p3d::pddi->GetExtension( PDDI_EXT_VISIBILITY_TEST ) );
if ( mVisibilityTestExtension != NULL )
{
for (int i = 0 ; i < spVisTestQueue.mUseSize ; i++)
{
spVisTestQueue[ i ]->ReadFrameBufferIntensity();
spVisTestQueue[ i ]->Release();
}
// Clear the array
spVisTestQueue.ClearUse();
}
#endif
}
// LensFlareDSG constructor
LensFlareDSG::LensFlareDSG()
: mPosn( 0,0,0 ),
mpCompDraw( NULL ),
mVisTestGeoIndex( -1 ),
mP3DVisibilityId( sP3DVisibilityCounter++ ),
mNumPixelsVisible( 1 ),
mCurrentIntensity( 0 )
{
}
// LensFlareDSG destructor
LensFlareDSG::~LensFlareDSG()
{
int i;
for (i=mpBillBoards.mUseSize - 1 ; i > -1 ; i--)
{
mpBillBoards[i]->Release();
}
if ( mpCompDraw != NULL )
{
mpCompDraw->Release();
}
}
// Checks to see if this flare is visible to the camera
void LensFlareDSG::ReadFrameBufferIntensity()
{
#ifndef RAD_GAMECUBE
pddiExtVisibilityTest* mVisibilityTestExtension = static_cast<pddiExtVisibilityTest*> (p3d::pddi->GetExtension( PDDI_EXT_VISIBILITY_TEST ) );
if ( mVisibilityTestExtension != NULL )
{
int count = mVisibilityTestExtension->Result( mP3DVisibilityId );
mNumPixelsVisible = count;
}
#endif
}
// Called by the loader - allocates space for iNumGroups of billboards
void LensFlareDSG::SetNumBillBoardQuadGroups( int iNumGroups )
{
if (iNumGroups > 0)
{
mpBillBoards.Allocate( iNumGroups );
}
}
//========================================================================
// LensFlare::
//========================================================================
//
// Description:
//
// Parameters: None.
//
// Return: None.
//
// Constraints: None.
//
//========================================================================
void LensFlareDSG::AddBillBoardQuadGroup( tBillboardQuadGroup* pGroup )
{
mpBillBoards.Add( pGroup );
pGroup->AddRef();
}
//========================================================================
// WorldSphereDSG::SetCompositeDrawable
//========================================================================
//
// Description: Sets the single composite drawable
//
// Parameters: None.
//
// Return: None.
//
// Constraints: None.
//
//========================================================================
void LensFlareDSG::SetCompositeDrawable( tCompositeDrawable* ipCompDraw )
{
mpCompDraw = ipCompDraw;
mpCompDraw->AddRef();
rmt::Sphere sphere;
mpCompDraw->GetBoundingSphere( &sphere );
mPosn = sphere.centre;
// Find the visibility mesh. It will be the only piece of geo in this thing
for ( int i = 0 ; i <mpCompDraw->GetNumDrawableElement() ; i++ )
{
tCompositeDrawable::DrawableElement* elem = mpCompDraw->GetDrawableElement(i);
if ( elem->GetType() == tCompositeDrawable::DrawableElement::PROP_ELEMENT )
{
tCompositeDrawable::DrawablePropElement* propElem = static_cast< tCompositeDrawable::DrawablePropElement* >(elem);
rAssert( dynamic_cast < tCompositeDrawable::DrawablePropElement* >( elem ) != NULL );
if ( dynamic_cast< tGeometry* >( propElem->GetDrawable() ) != NULL )
{
// Found it, record the index of the composite drawable
mVisTestGeoIndex = i;
// Turn off visibility for this thing
propElem->SetVisibility( false );
propElem->SetLockVisibility( true );
break;
}
}
}
}
///////////////////////////////////////////////////////////////////////
// Drawable
///////////////////////////////////////////////////////////////////////
//========================================================================
// WorldSphereDSG::
//========================================================================
//
// Description:
//
// Parameters: None.
//
// Return: None.
//
// Constraints: None.
//
//========================================================================
void LensFlareDSG::Display()
{
#ifdef PROFILER_ENABLED
char profileName[] = " LensFlareDSG Display";
#endif
DSG_BEGIN_PROFILE(profileName)
LensFlareDSG::PostDisplayFlare( this );
DSG_END_PROFILE(profileName)
}
void LensFlareDSG::DisplayImmediate()
{
#ifdef RAD_WIN32
return;
#endif
#ifdef PROFILER_ENABLED
char profileName[] = " LensFlareDSG DisplayImmediate";
#endif
tView* view = p3d::context->GetView();
if ( view == NULL )
return;
tCamera* camera = view->GetCamera();
rmt::Vector cameraPosition;
camera->GetWorldPosition( &cameraPosition );
rmt::Matrix toCameraPosition;
toCameraPosition.Identity();
toCameraPosition.FillTranslate( cameraPosition );
p3d::stack->PushMultiply( toCameraPosition );
DSG_BEGIN_PROFILE(profileName)
DrawVisibilityChecker();
#ifdef RAD_PS2
// turn z compare to always
SetBillBoardIntensity( 1.0f );
pddiCompareMode origZCompare = p3d::pddi->GetZCompare();
p3d::pddi->SetZCompare(PDDI_COMPARE_ALWAYS);
mpCompDraw->Display();
p3d::pddi->SetZCompare(origZCompare);
#else
// Visible but not at full intensity, ramp up
if (mNumPixelsVisible > 0 && mCurrentIntensity < 1.0f)
{
mCurrentIntensity += INTENSITY_CHANGE_PER_FRAME;
if ( mCurrentIntensity > 1.0f )
mCurrentIntensity = 1.0f;
}
else if (mNumPixelsVisible == 0 && mCurrentIntensity > 0)
{
mCurrentIntensity -= INTENSITY_CHANGE_PER_FRAME;
if ( mCurrentIntensity < 0 )
mCurrentIntensity = 0;
}
SetBillBoardIntensity( mCurrentIntensity );
pddiCompareMode origZCompare = p3d::pddi->GetZCompare();
p3d::pddi->SetZCompare(PDDI_COMPARE_ALWAYS);
mpCompDraw->Display();
p3d::pddi->SetZCompare(origZCompare);
#endif
p3d::stack->Pop();
DSG_END_PROFILE(profileName)
}
//========================================================================
// WorldSphereDSG::
//========================================================================
//
// Description:
//
// Parameters: None.
//
// Return: None.
//
// Constraints: None.
//
//========================================================================
void LensFlareDSG::DisplayBoundingBox(tColour colour)
{
rTuneAssert(false);
}
//========================================================================
// WorldSphereDSG::
//========================================================================
//
// Description:
//
// Parameters: None.
//
// Return: None.
//
// Constraints: None.
//
//========================================================================
void LensFlareDSG::DisplayBoundingSphere(tColour colour)
{
rTuneAssert(false);
}
//========================================================================
// WorldSphereDSG::
//========================================================================
//
// Description:
//
// Parameters: None.
//
// Return: None.
//
// Constraints: None.
//
//========================================================================
void LensFlareDSG::GetBoundingBox(rmt::Box3D* box)
{
mpCompDraw->GetBoundingBox( box );
}
//========================================================================
// WorldSphereDSG::
//========================================================================
//
// Description:
//
// Parameters: None.
//
// Return: None.
//
// Constraints: None.
//
//========================================================================
void LensFlareDSG::GetBoundingSphere(rmt::Sphere* pSphere)
{
mpCompDraw->GetBoundingSphere( pSphere );
}
///////////////////////////////////////////////////////////////////////
// IEntityDSG
///////////////////////////////////////////////////////////////////////
//========================================================================
// WorldSphereDSG::
//========================================================================
//
// Description:
//
// Parameters: None.
//
// Return: None.
//
// Constraints: None.
//
//========================================================================
rmt::Vector* LensFlareDSG::pPosition()
{
rTuneAssert(false);
return NULL;
}
//========================================================================
// WorldSphereDSG::
//========================================================================
//
// Description:
//
// Parameters: None.
//
// Return: None.
//
// Constraints: None.
//
//========================================================================
const rmt::Vector& LensFlareDSG::rPosition()
{
return mPosn;
}
//==============================6==========================================
// WorldSphereDSG::
//========================================================================
//
// Description:
//
// Parameters: None.
//
// Return: None.
//
// Constraints: None.
//
//========================================================================
void LensFlareDSG::GetPosition( rmt::Vector* ipPosn )
{
*ipPosn = mPosn;
}
//========================================================================
// WorldSphereDSG::
//========================================================================
//
// Description:
//
// Parameters: None.
//
// Return: None.
//
// Constraints: None.
//
//========================================================================
void LensFlareDSG::RenderUpdate()
{
//Do Nothing
}
//************************************************************************
//
// Protected Member Functions : WorldSphereDSG
//
//************************************************************************
//************************************************************************
//
// Private Member Functions : WorldSphereDSG
//
//************************************************************************
#ifdef RAD_PS2
void LensFlareDSG::DrawVisibilityChecker()
{
}
#endif
#if defined( RAD_XBOX ) || defined( RAD_WIN32 )
void LensFlareDSG::DrawVisibilityChecker()
{
// We need to use a PDDI extension to draw the billboards
// with colour write off at a specific location
// This will fill the Z buffer (make sure to draw enable Z buffering!)
// with the billboard distances
// Then draw the scene as usual
// Fetch the extension from PDDI
pddiExtVisibilityTest* mVisibilityTestExtension = static_cast<pddiExtVisibilityTest*> (p3d::pddi->GetExtension( PDDI_EXT_VISIBILITY_TEST ) );
if ( mVisibilityTestExtension != NULL &&
mVisTestGeoIndex != -1 )
{
bool origZWrite = p3d::pddi->GetZWrite();
p3d::pddi->SetZWrite(false);
// Tell PDDI to begin logging my Z writes
// Force Z writes to true
// We know that lens flares never write into the Z buffer, so we don't have to save
// their Z write values
mpCompDraw->GetPose()->Evaluate();
p3d::pddi->SetColourWrite( false, false, false, false );
rTuneAssert( p3d::pddi->GetZCompare() != PDDI_COMPARE_ALWAYS );
tCompositeDrawable::DrawableElement* elem = mpCompDraw->GetDrawableElement( mVisTestGeoIndex );
elem->SetPose( mpCompDraw->GetPose() );
elem->SetLockVisibility( false );
elem->SetVisibility( true );
mVisibilityTestExtension->Begin();
elem->Display();
// Tell PDDI to stop logging z writes
mVisibilityTestExtension->End( mP3DVisibilityId );
elem->SetVisibility( false );
elem->SetLockVisibility( true );
// Restore Z write values
p3d::pddi->SetColourWrite( true, true, true, true );
p3d::pddi->SetZWrite(origZWrite);
// Insert a pointer to this DSG object into the vis test array
// so we can set it up to be retreived upon DSG removal
this->AddRef();
LensFlareDSG* pLensFlare = this;
spVisTestQueue.Add( pLensFlare );
}
}
#endif
#ifdef RAD_GAMECUBE
void LensFlareDSG::DrawVisibilityChecker()
{
rTuneAssert( p3d::pddi->GetZCompare() != PDDI_COMPARE_ALWAYS );
// Gamecube
// Have to read the Z value of the center of the visibility mesh before and after it
// was drawn
// Read Z value before it was drawn
// Determine position to read from
// Evaluate the composite drawable
mpCompDraw->GetPose()->Evaluate();
// and fetch the element's matrix
tCompositeDrawable::DrawableElement* elem = mpCompDraw->GetDrawableElement( mVisTestGeoIndex );
elem->SetPose( mpCompDraw->GetPose() );
const rmt::Matrix* pWorldMat = elem->GetWorldMatrix();
// Position is determined by using tContext::ObjectToDevice
p3d::stack->PushMultiply( *pWorldMat );
rmt::Vector deviceCoords;
p3d::context->ObjectToDevice( rmt::Vector(0,0,0), &deviceCoords );
p3d::stack->Pop();
// Check that the deviceCoords fall within valid Gamecube API range
// x from 0 to 639 inclusive
// y from 0 to 527 inclusive
// If either coordinate is not in this range, bail, its not visible
if ( deviceCoords.x < 0 || deviceCoords.x > 639 || deviceCoords.y < 0 || deviceCoords.y > 527 )
{
mNumPixelsVisible = 0;
}
else
{
// Make sure drawing is completed so far and read the z buffer depth at the point where
// the mesh will be drawn
GXDrawDone();
u32 depthBeforeVisMesh;
GXPeekZ( deviceCoords.x, deviceCoords.y, &depthBeforeVisMesh );
// Now draw the visibility mesh and see if it was actually written
p3d::pddi->SetColourWrite( false, false, false, true );
elem->SetLockVisibility( false );
elem->SetVisibility( true );
elem->Display();
elem->SetVisibility( false );
elem->SetLockVisibility( true );
GXDrawDone();
// Vis mesh has been drawn, read the pixel
u32 depthAfterVisMesh;
GXPeekZ( deviceCoords.x, deviceCoords.y, &depthAfterVisMesh );
if ( depthAfterVisMesh < depthBeforeVisMesh )
mNumPixelsVisible = 1;
else
mNumPixelsVisible = 0;
p3d::pddi->SetColourWrite( true, true, true, true );
}
}
#endif
void LensFlareDSG::SetBillBoardIntensity( float intensity )
{
for (int i = 0 ; i < mpBillBoards.mUseSize ; i++)
{
mpBillBoards[ i ]->SetIntensityBias( intensity );
}
}