//============================================================================= // Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. // // File: AnimatedIcon.cpp // // Description: Implement AnimatedIcon // // History: 10/3/2002 + Created -- Cary Brisebois // //============================================================================= //======================================== // System Includes //======================================== // Foundation Tech #include #include #include #include #include //======================================== // Project Includes //======================================== #include #include #include #include #include #include #include #include
//****************************************************************************** // // Global Data, Local Data, Local Classes // //****************************************************************************** AnimatedIcon* AnimatedIcon::sAnimatedIconPool = NULL; unsigned int AnimatedIcon::sNumAllocated = 0; // Setup default parameters for our watcher variables #ifdef RAD_TUNE float AnimatedIcon::sDbgMinArrowScale = MIN_ARROW_SCALE; float AnimatedIcon::sDbgMaxArrowScale = MAX_ARROW_SCALE; float AnimatedIcon::sDbgMinArrowScaleDist = MIN_ARROW_SCALE_DIST; float AnimatedIcon::sDbgMaxArrowScaleDist = MAX_ARROW_SCALE_DIST; bool AnimatedIcon::sDbgEnableArrowScaling = false; #endif //****************************************************************************** // // Public Member Functions // //****************************************************************************** //============================================================================== // AnimatedIcon::AnimatedIcon //============================================================================== // Description: Constructor. // // Parameters: None. // // Return: N/A. // //============================================================================== AnimatedIcon::AnimatedIcon() : mDSGEntity( NULL ), mRenderLayer( RenderEnums::LevelSlot ), mFlags( 0 ) { #ifdef RAD_TUNE AttachWatcherVariables(); #endif } //============================================================================== // AnimatedIcon::~AnimatedIcon //============================================================================== // Description: Destructor. // // Parameters: None. // // Return: N/A. // //============================================================================== AnimatedIcon::~AnimatedIcon() { Deallocate(); } //============================================================================= // AnimatedIcon::Init //============================================================================= // Description: Comment // // Parameters: ( const char* iconName, const rmt::Matrix& mat, bool render = true, bool oneShot = false ) // // Return: void // //============================================================================= void AnimatedIcon::Init( const char* iconName, const rmt::Matrix& mat, bool render, bool oneShot ) { MEMTRACK_PUSH_GROUP( "Mission - Animated Icon" ); rAssert( iconName ); rAssertMsg( mDSGEntity == NULL, "Never call this twice on the same object!!!! LEAK, LEAK!" ); //========================= SET UP THE ICON HeapMgr()->PushHeap( GetGameplayManager()->GetCurrentMissionHeap() ); SetUpContents( iconName ); mDSGEntity = new AnimIconDSG; mDSGEntity->mTranslucent = true; rAssert( mDSGEntity != NULL ); mDSGEntity->AddRef(); // // The entity takes overship of m, so spake Devin // rmt::Matrix* m = new rmt::Matrix; rAssert( m ); *m = mat; mDSGEntity->LoadSetUp( m, mAnimIcon.drawable, mAnimIcon.shadowDrawable ); mRenderLayer = static_cast(GetRenderManager()->rCurWorldRenderLayer()); if ( render ) { ShouldRender( true ); } SetFlag( (Flag)ONE_SHOT, oneShot ); SetUpEffects(); HeapMgr()->PopHeap( GetGameplayManager()->GetCurrentMissionHeap() ); MEMTRACK_POP_GROUP( "Mission - Animated Icon" ); } //============================================================================= // AnimatedIcon::Init //============================================================================= // Description: Comment // // Parameters: ( const char* iconName, const rmt::Vector& pos, bool render, bool oneShot ) // // Return: void // //============================================================================= void AnimatedIcon::Init( const char* iconName, const rmt::Vector& pos, bool render, bool oneShot ) { MEMTRACK_PUSH_GROUP( "Mission - Animated Icon" ); rAssert( iconName ); rAssertMsg( mDSGEntity == NULL, "Never call this twice on the same object!!!! LEAK, LEAK!" ); //========================= SET UP THE ICON HeapMgr()->PushHeap( GetGameplayManager()->GetCurrentMissionHeap() ); SetUpContents( iconName ); mDSGEntity = new AnimIconDSG; mDSGEntity->mTranslucent = true; rAssert( mDSGEntity != NULL ); mDSGEntity->AddRef(); mDSGEntity->SetName( iconName ); // // The entity takes overship of m, so spake Devin // rmt::Matrix* m = new rmt::Matrix; rAssert( m ); m->Identity(); m->FillTranslate( pos ); mDSGEntity->LoadSetUp( m, mAnimIcon.drawable, mAnimIcon.shadowDrawable ); mRenderLayer = static_cast(GetRenderManager()->rCurWorldRenderLayer()); if ( render ) { ShouldRender( true ); } SetFlag( (Flag)ONE_SHOT, oneShot ); SetUpEffects(); HeapMgr()->PopHeap( GetGameplayManager()->GetCurrentMissionHeap() ); MEMTRACK_POP_GROUP( "Mission - Animated Icon" ); } //============================================================================= // AnimatedIcon::ScaleByCameraDistance //============================================================================= // Description: Converts all billboardquadgroups in the icon drawable to quads that are // scaled by distance to camera // // Parameters: (float minScale, float maxScale, float minDist, float maxDist) // // Return: void // //============================================================================= void AnimatedIcon::ScaleByCameraDistance( float minScale, float maxScale, float minDist, float maxDist ) { // Default to no scaling mDSGEntity->SetScaleParameters( minScale, maxScale, minDist, maxDist ); } //============================================================================= // AnimatedIcon::Move //============================================================================= // Description: Comment // // Parameters: ( const rmt::Vector& newPos ) // // Return: void // //============================================================================= void AnimatedIcon::Move( const rmt::Vector& newPos ) { if ( mRenderLayer == static_cast(GetRenderManager()->rCurWorldRenderLayer()) ) { rmt::Box3D oldBox; mDSGEntity->GetBoundingBox( &oldBox ); mDSGEntity->pMatrix()->FillTranslate( newPos ); if ( !GetFlag( (Flag)RENDERING ) ) { ShouldRender( true ); } GetRenderManager()->pWorldScene()->Move( oldBox, mDSGEntity ); mDSGEntity->RecomputeShadowPosition(); } } //============================================================================= // AnimatedIcon::Update //============================================================================= // Description: Comment // // Parameters: ( unsigned int elapsedMilliseconds ) // // Return: void // //============================================================================= void AnimatedIcon::Update( unsigned int elapsedMilliseconds ) { rmt::Sphere iconBoundingSphere; if ( mDSGEntity ) { mDSGEntity->GetBoundingSphere( &iconBoundingSphere ); mDSGEntity->m_Visible = false; } else { iconBoundingSphere.centre = rmt::Vector(0,0,0); iconBoundingSphere.radius = 1.0f; } if ( GetFlag( (Flag)RENDERING ) && GetGameplayManager()->TestPosInFrustrumOfPlayer(iconBoundingSphere.centre, 0, iconBoundingSphere.radius)) { if ( mDSGEntity ) { mDSGEntity->m_Visible = true; } if ( mAnimIcon.multiController ) { BEGIN_PROFILE( mAnimIcon.multiController->GetName() ); //This allows me to ignore the extra updates caused by being part of //a substep. unsigned int frame = GetGame()->GetFrameCount(); if ( (mAnimIcon.multiController)->GetLastFrameUpdated() != frame ) { (mAnimIcon.multiController)->Advance( (float)elapsedMilliseconds ); (mAnimIcon.multiController)->SetLastFrameUpdated( frame ); // Handle particle systems if ( mAnimIcon.effectIndex != -1 ) { tCompositeDrawable* compDraw = static_cast< tCompositeDrawable* >( mAnimIcon.drawable ); tCompositeDrawable::DrawableEffectElement* effectElement = static_cast< tCompositeDrawable::DrawableEffectElement* > ( compDraw->GetDrawableElement( mAnimIcon.effectIndex ) ); tParticleSystem* system = static_cast< tParticleSystem* >( effectElement->GetDrawable() ); if ( system ) { rmt::Matrix mat; mat.Identity(); system->Update( &mat ); } } if ( GetFlag( (Flag)ONE_SHOT ) && (mAnimIcon.multiController)->LastFrameReached() > 0 ) { //This is a way to remove non-cyclic animations. Beware, //if the animation is intended to be cyclic it will disappear... ShouldRender( false ); } } END_PROFILE( mAnimIcon.multiController->GetName() ); } if ( mAnimIcon.shadowController != NULL ) { mAnimIcon.shadowController->Advance( (float)elapsedMilliseconds ); } #ifdef RAD_TUNE if ( sDbgEnableArrowScaling ) { // Jeff P. wants to have watcher variables to tune the AI scaling. // If we are in tune mode, lets override the input parameters and set them to be // the values of some static watcher variables ScaleByCameraDistance( sDbgMinArrowScale, sDbgMaxArrowScale, sDbgMinArrowScaleDist, sDbgMaxArrowScaleDist ); } #endif } } //============================================================================= // AnimatedIcon::Reset //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void AnimatedIcon::Reset() { if ( mAnimIcon.multiController ) { (mAnimIcon.multiController)->Reset(); } } //============================================================================= // AnimatedIcon::ShouldRender //============================================================================= // Description: Comment // // Parameters: ( bool shouldRender ) // // Return: void // //============================================================================= void AnimatedIcon::ShouldRender( bool shouldRender ) { if ( shouldRender && !GetFlag( (Flag)RENDERING ) ) { (reinterpret_cast(GetRenderManager()->mpLayer( mRenderLayer )))->pWorldScene()->Add( mDSGEntity ); SetFlag( (Flag)RENDERING, true ); } else if ( !shouldRender && GetFlag( (Flag)RENDERING ) ) { (reinterpret_cast(GetRenderManager()->mpLayer( mRenderLayer )))->pWorldScene()->RemoveQuietFail( mDSGEntity ); SetFlag( (Flag)RENDERING, false ); } } //============================================================================= // AnimatedIcon::GetPosition //============================================================================= // Description: Comment // // Parameters: ( rmt::Vector& pos ) // // Return: void // //============================================================================= void AnimatedIcon::GetPosition( rmt::Vector& pos ) { mDSGEntity->GetPosition( &pos ); } //============================================================================= // ::operator new //============================================================================= // Description: Comment // // Parameters: ( size_t size ) // // Return: void // //============================================================================= void* AnimatedIcon::operator new( size_t size ) { rAssert( sAnimatedIconPool != NULL ); rAssert( sNumAllocated < MAX_ICONS ); void* data = NULL; if ( sNumAllocated < MAX_ICONS ) { unsigned int i; for ( i = 0; i < MAX_ICONS; ++i ) { if ( !sAnimatedIconPool[ i ].mAllocated ) { sAnimatedIconPool[ i ].mAllocated = true; data = static_cast(&sAnimatedIconPool[ i ]); ++sNumAllocated; break; } } } return data; } //============================================================================= // ::operator new //============================================================================= // Description: Comment // // Parameters: ( size_t size, GameMemoryAllocator allocator ) // // Return: void // //============================================================================= void* AnimatedIcon::operator new( size_t size, GameMemoryAllocator allocator ) { return new AnimatedIcon(); } //============================================================================= // ::operator delete //============================================================================= // Description: Comment // // Parameters: ( void* mem ) // // Return: void // //============================================================================= void AnimatedIcon::operator delete( void* mem ) { AnimatedIcon* icon = static_cast( mem ); unsigned int i; for ( i = 0; i < MAX_ICONS; ++i ) { if ( icon == &sAnimatedIconPool[ i ] ) { icon->Deallocate(); sNumAllocated--; break; } } rAssert( i < MAX_ICONS ); } //============================================================================= // void operator delete //============================================================================= // Description: Comment // // Parameters: ( void* mem, GameMemoryAllocator allocator ) // // Return: void // //============================================================================= void AnimatedIcon::operator delete( void* mem, GameMemoryAllocator allocator ) { AnimatedIcon::operator delete( mem ); } //============================================================================= // AnimatedIcon::InitAnimatedIcons //============================================================================= // Description: Comment // // Parameters: ( GameMemoryAllocator allocator ) // // Return: void // //============================================================================= void AnimatedIcon::InitAnimatedIcons( GameMemoryAllocator allocator ) { rAssert( sAnimatedIconPool == NULL ); if ( sAnimatedIconPool == NULL ) { #ifdef RAD_GAMECUBE HeapMgr()->PushHeap( GMA_GC_VMM ); #else HeapMgr()->PushHeap( allocator ); #endif sAnimatedIconPool = new AnimatedIcon[ MAX_ICONS ]; unsigned int i; for ( i = 0; i < MAX_ICONS; ++i ) { sAnimatedIconPool[ i ].mAllocated = false; } #ifdef RAD_GAMECUBE HeapMgr()->PopHeap( GMA_GC_VMM ); #else HeapMgr()->PopHeap( allocator ); #endif } } //============================================================================= // AnimatedIcon::ShutdownAnimatedIcons //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void AnimatedIcon::ShutdownAnimatedIcons() { rAssert( sNumAllocated == 0 ); //Paranoia Test #ifdef RAD_DEBUG unsigned int i; for ( i = 0; i < MAX_ICONS; ++i ) { rAssert( sAnimatedIconPool[ i ].mDSGEntity == NULL ); } #endif delete[] sAnimatedIconPool; sAnimatedIconPool = NULL; } //****************************************************************************** // // Private Member Functions // //****************************************************************************** //============================================================================= // AnimatedIcon::SetFlag //============================================================================= // Description: Comment // // Parameters: ( Flag flag, bool value ) // // Return: void // //============================================================================= void AnimatedIcon::SetFlag( Flag flag, bool value ) { if ( value ) { mFlags |= ( 1 << flag ); } else { mFlags &= ~( 1 << flag ); } } //============================================================================= // AnimatedIcon::GetFlag //============================================================================= // Description: Comment // // Parameters: ( Flag flag ) // // Return: bool // //============================================================================= bool AnimatedIcon::GetFlag( Flag flag ) const { return ( (mFlags & ( 1 << flag )) > 0 ); } //============================================================================= // AnimatedIcon::Deallocate //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void AnimatedIcon::Deallocate() { if ( mDSGEntity ) { //Scary, scary! if ( GetFlag( (Flag)RENDERING ) ) { ShouldRender(false); } mDSGEntity->Release(); } mFlags = 0; mAllocated = false; mDSGEntity = NULL; tRefCounted::Release(mAnimIcon.drawable); tRefCounted::Release(mAnimIcon.multiController); tRefCounted::Release(mAnimIcon.shadowController); tRefCounted::Release(mAnimIcon.shadowDrawable); } //============================================================================= // AnimatedIcon::SetUpContents //============================================================================= // Description: Comment // // Parameters: ( const char* iconName ) // // Return: void // //============================================================================= void AnimatedIcon::SetUpContents( const char* iconName ) { tRefCounted::Assign(mAnimIcon.drawable, p3d::find( iconName )); if ( mAnimIcon.drawable == NULL ) { rReleasePrintf( "ERORR!!!!! Can not init Animicon with missing (%s) drawable!!!!\n", iconName ); tRefCounted::Assign(mAnimIcon.drawable, p3d::find( "triggersphere_000" )); } rAssert( mAnimIcon.drawable != NULL ); char controllerName[256]; sprintf( controllerName, "%s_controller", iconName ); tRefCounted::Assign(mAnimIcon.multiController, p3d::find( controllerName ) ); // Try and find the shadows (Collector cards have them, others are optional) // Append _shadow to the icon name to get the shadow name char shadowDrawableName[256]; sprintf( shadowDrawableName, "%s_shadow", iconName ); tRefCounted::Assign(mAnimIcon.shadowDrawable, p3d::find( shadowDrawableName )); // Now try and find the shadow multicontroller char shadowControllerName[256]; sprintf( shadowControllerName, "%s_controller", shadowDrawableName ); tRefCounted::Assign(mAnimIcon.shadowController, p3d::find( shadowControllerName ) ); } //============================================================================= // AnimatedIcon::SetUpEffects //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void AnimatedIcon::SetUpEffects() { //Only do this once. rAssert( mAnimIcon.effectIndex == -1 ); // Try and find particle systems tCompositeDrawable* compDraw = dynamic_cast< tCompositeDrawable* >( mAnimIcon.drawable ); if ( compDraw ) { for ( int i = 0 ; i < compDraw->GetNumDrawableElement() ; i++ ) { tCompositeDrawable::DrawableEffectElement* effectElement = dynamic_cast< tCompositeDrawable::DrawableEffectElement* > ( compDraw->GetDrawableElement( i ) ); if (effectElement) { tEffect* effect = static_cast< tEffect* >( effectElement->GetDrawable() ); if ( effect != NULL ) { tParticleSystem* ps = static_cast< tParticleSystem* >( effect ); tParticleSystemFactory* factory = static_cast< tParticleSystemFactory* >( ps->GetFactory() ); factory->SetAlwaysUpdateAfterDisplay( false ); ps->ConvertEmittersToLocal(); mAnimIcon.effectIndex = i; break; } } } } } #ifdef RAD_TUNE void AnimatedIcon::AttachWatcherVariables() { static bool sDbgArrowsAttachedToWatcher = false; // has the watcher variables been // attached already ? dont attach them more than once if ( sDbgArrowsAttachedToWatcher == false ) { const char* ANIMATED_ICON_DBG_NAMESPACE = "Animated Icons"; radDbgWatchAddBoolean( &sDbgEnableArrowScaling, "Enable Arrow Scaling", ANIMATED_ICON_DBG_NAMESPACE ); radDbgWatchAddFloat( &sDbgMinArrowScale, "Min Arrow Scale", ANIMATED_ICON_DBG_NAMESPACE, NULL, NULL, 0, 20.0f ); radDbgWatchAddFloat( &sDbgMaxArrowScale, "Max Arrow Scale", ANIMATED_ICON_DBG_NAMESPACE, NULL, NULL, 0, 20.0f ); radDbgWatchAddFloat( &sDbgMinArrowScaleDist, "Min Arrow Scale Distance", ANIMATED_ICON_DBG_NAMESPACE, NULL, NULL, 0, 250.0f ); radDbgWatchAddFloat( &sDbgMaxArrowScaleDist, "Max Arrow Scale Distance", ANIMATED_ICON_DBG_NAMESPACE, NULL, NULL, 0, 250.0f ); } sDbgArrowsAttachedToWatcher = true; } #endif AnimatedIcon::AnimIconDSG::AnimIconDSG(): m_ScalingEnabled( false ) { // Default to no scaling SetScaleParameters( 1.0f, 1.0f, 1.0f, 1.0f ); } AnimatedIcon::AnimIconDSG::~AnimIconDSG(){ } float AnimatedIcon::AnimIconDSG::CalcScale() { rmt::Vector objPosition; GetPosition( &objPosition ); // Determine the distance to the camera rmt::Vector camPosition; p3d::context->GetView()->GetCamera()->GetWorldPosition( &camPosition ); float distToBillboard = (camPosition - objPosition ).Magnitude(); float billboardScale = m_Slope * ( distToBillboard - m_NearDist ) + m_MinSize; billboardScale = rmt::Clamp( billboardScale, m_MinSize, m_MaxSize ); return billboardScale; } void AnimatedIcon::AnimIconDSG::SetScaleParameters( float minSize, float maxSize, float nearDist, float farDist ) { // Compute m // The slope of the equation determining icon scaling if ( ( farDist - nearDist ) > 0.01f ) { // m = ( maxSize - 1.0f ) / ( far - near ) m_MaxSize = maxSize; m_MinSize = minSize; m_NearDist = nearDist; m_Slope = ( maxSize - minSize ) / ( farDist - nearDist ); m_ScalingEnabled = true; } else { m_ScalingEnabled = false; } } // Display with scaling. void AnimatedIcon::AnimIconDSG::Display() { if( m_Visible ) { extern bool g_ParticleLOD; g_ParticleLOD = true; bool wasBBQManagerEnabled = BillboardQuadManager::sEnabled; BillboardQuadManager::Enable(); if ( m_ScalingEnabled ) { float scale = CalcScale(); rmt::Matrix scaleMat; scaleMat.Identity(); scaleMat.FillScale( scale ); // Apply rotation/transform THEN scale to the local object rmt::Matrix origMatrix = *mpMatrix; mpMatrix->Mult( scaleMat, origMatrix ); InstStatEntityDSG::Display(); *mpMatrix = origMatrix; } else { InstStatEntityDSG::Display(); } if ( wasBBQManagerEnabled == false ) { BillboardQuadManager::Disable(); } g_ParticleLOD = false; } }