//=========================================================================== // Copyright (C) 2000 Radical Entertainment Ltd. All rights reserved. // // Component: CGuiScreenLoadingFE // // Description: Implementation of the CGuiScreenLoadingFE class. // // Authors: Tony Chu // // Revisions Date Author Revision // 2002/07/23 TChu Created for SRR2 // //=========================================================================== //=========================================================================== // Includes //=========================================================================== #include #include #include #include #include #include #include #include #include #include #include #include #include // Foundation #include #include #include #include #include #include #include #include //=========================================================================== // Global Data, Local Data, Local Classes //=========================================================================== #define ENABLE_DYNA_LOADED_RESOURCES //#define LOADING_BAR_FE_EXPLOSION #ifdef ENABLE_DYNA_LOADED_RESOURCES const char* LOADING_FE_PURE3D_FILE = "art\\frontend\\scrooby\\resource\\pure3d\\loading.p3d"; const char* LOADING_FE_INVENTORY = "LoadingFEScreen"; const char* LOADING_FE_DRAWABLE = "loading_screen"; const char* LOADING_FE_CAMERA = "loading_screen_cameraShape"; const char* LOADING_FE_MULTICONTROLLER = "loading_screen_MasterController"; #endif //=========================================================================== // Public Member Functions //=========================================================================== //=========================================================================== // CGuiScreenLoadingFE::CGuiScreenLoadingFE //=========================================================================== // Description: Constructor. // // Constraints: None. // // Parameters: None. // // Return: N/A. // //=========================================================================== CGuiScreenLoadingFE::CGuiScreenLoadingFE ( Scrooby::Screen* pScreen, CGuiEntity* pParent ) : CGuiScreen( pScreen, pParent, GUI_SCREEN_ID_LOADING_FE ), m_loadingText( NULL ), m_itchyAndScratchy( NULL ), m_elapsedTime( 0 ), m_loadingBarGroup( NULL ), m_currentMemoryUsage( 0.0f ), m_startingMemoryAvailable( 0 ), m_elapsedFireTime( 0 ), m_explosionLayer( NULL ), m_explosion( NULL ), m_elapsedExplosionTime( 0 ) { // Retrieve the Scrooby drawing elements. // Scrooby::Page* pPage = m_pScroobyScreen->GetPage( "LoadingFE" ); rAssert( pPage != NULL ); Scrooby::Layer* foreground = pPage->GetLayer( "Foreground" ); Scrooby::Layer* background = pPage->GetLayer( "Background" ); m_loadingText = foreground->GetText( "Loading" ); rAssert( m_loadingText != NULL ); m_itchyAndScratchy = background->GetPure3dObject( "Loading" ); if( m_itchyAndScratchy != NULL ) { m_itchyAndScratchy->SetDrawable( NULL ); m_itchyAndScratchy->SetCamera( NULL ); m_itchyAndScratchy->SetMultiController( NULL ); m_itchyAndScratchy->SetClearDepthBuffer( true ); } // get loading bar // m_loadingBarGroup = pPage->GetGroup( "LoadingBar" ); rAssert( m_loadingBarGroup != NULL ); m_loadingBar.m_type = Slider::HORIZONTAL_SLIDER_RIGHT; m_loadingBar.SetScroobyPolygon( m_loadingBarGroup->GetPolygon( "Wick" ), m_loadingBarGroup->GetSprite( "Fire" ) ); // get explosion overlay (from Explosion.pag) // pPage = m_pScroobyScreen->GetPage( "Explosion" ); if( pPage != NULL ) { m_explosionLayer = pPage->GetLayer( "Explosion" ); rAssert( m_explosionLayer != NULL ); m_explosion = m_explosionLayer->GetPolygon( "Explosion0" ); rAssert( m_explosion != NULL ); } #ifdef ENABLE_DYNA_LOADED_RESOURCES p3d::inventory->AddSection( LOADING_FE_INVENTORY ); #endif } //=========================================================================== // CGuiScreenLoadingFE::~CGuiScreenLoadingFE //=========================================================================== // Description: Destructor. // // Constraints: None. // // Parameters: None. // // Return: N/A. // //=========================================================================== CGuiScreenLoadingFE::~CGuiScreenLoadingFE() { #ifdef ENABLE_DYNA_LOADED_RESOURCES p3d::inventory->DeleteSection( LOADING_FE_INVENTORY ); #endif } //=========================================================================== // CGuiScreenLoadingFE::HandleMessage //=========================================================================== // Description: // // Constraints: None. // // Parameters: None. // // Return: N/A. // //=========================================================================== void CGuiScreenLoadingFE::HandleMessage ( eGuiMessage message, unsigned int param1, unsigned int param2 ) { switch( message ) { case GUI_MSG_UPDATE: { // update loading text // const unsigned int LOADING_TEXT_LOOP_TIME = 500; // in msec m_elapsedTime += param1; if( m_elapsedTime > LOADING_TEXT_LOOP_TIME ) { rAssert( m_loadingText != NULL ); int nextIndex = (m_loadingText->GetIndex() + 1) % m_loadingText->GetNumOfStrings(); m_loadingText->SetIndex( nextIndex ); m_elapsedTime %= LOADING_TEXT_LOOP_TIME; } ContextEnum currentContext = GetGameFlow()->GetCurrentContext(); if( currentContext == CONTEXT_FRONTEND || currentContext == CONTEXT_LOADING_DEMO || currentContext == CONTEXT_LOADING_SUPERSPRINT || currentContext == CONTEXT_LOADING_GAMEPLAY ) { // update loading bar // rAssert( m_loadingBarGroup != NULL ); m_loadingBarGroup->SetVisible( true ); float newMemoryUsage = this->GetCurrentMemoryUsage( currentContext ); // don't allow loading bar to go backwards // if( newMemoryUsage > m_currentMemoryUsage ) { m_currentMemoryUsage = newMemoryUsage; if( m_currentMemoryUsage < 1.0f ) { m_loadingBar.SetValue( 1.0f - m_currentMemoryUsage ); } else { #ifdef LOADING_BAR_FE_EXPLOSION if( m_explosionLayer != NULL && m_explosion != NULL ) { m_explosionLayer->SetVisible( true ); m_elapsedExplosionTime += param1; /* float explosionScale = EXPLOSION_SCALE_START + m_elapsedExplosionTime / 1000.0f * EXPLOSION_SCALE_RATE; m_explosion->ResetTransformation(); m_explosion->ScaleAboutCenter( explosionScale ); */ const unsigned int EXPLOSION_FLICKER_PERIOD = 50; bool isBlinked = GuiSFX::Blink( m_explosion, (float)m_elapsedExplosionTime, (float)EXPLOSION_FLICKER_PERIOD ); if( isBlinked ) { m_elapsedExplosionTime %= EXPLOSION_FLICKER_PERIOD; } /* tColour currentColour; GuiSFX::ModulateColour( ¤tColour, (float)m_elapsedExplosionTime, 100.0f, tColour( 255, 255, 0 ), tColour( 255, 0, 0 ) ); for( int i = 0; i < m_explosion->GetNumOfVertexes(); i++ ) { m_explosion->SetVertexColour( i, currentColour ); } */ } #else #ifndef RAD_DEBUG rReleaseWarningMsg( false, "Current memory usage for loading bar exceeds 100%!" ); #endif #endif // LOADING_BAR_FE_EXPLOSION } } // flicker loading bar flame // const unsigned int LOADING_BAR_FIRE_TIME = 50; // in msec m_elapsedFireTime += param1; if( m_elapsedFireTime > LOADING_BAR_FIRE_TIME ) { rAssert( m_loadingBar.m_pImage != NULL ); m_loadingBar.m_pImage->SetIndex( 1 - m_loadingBar.m_pImage->GetIndex() ); m_elapsedFireTime %= LOADING_BAR_FIRE_TIME; } } break; } case GUI_MSG_LOAD_RESOURCES: { this->LoadResources(); #ifdef RAD_XBOX m_startingMemoryAvailable = Memory::GetTotalMemoryFree(); #else m_startingMemoryAvailable = GetTotalMemoryFreeInAllHeaps(); #endif rReleasePrintf( "Starting Memory Available = %.2f MB\n", (float)m_startingMemoryAvailable / MB ); #ifdef RAD_WIN32 GetLoadingManager()->ResetRequestsProcessed(); #endif break; } default: { break; } } // Propogate the message up the hierarchy. // CGuiScreen::HandleMessage( message, param1, param2 ); } void CGuiScreenLoadingFE::LoadResources() { #ifdef ENABLE_DYNA_LOADED_RESOURCES if( m_itchyAndScratchy != NULL ) { m_itchyAndScratchy->SetDrawable( NULL ); } GameMemoryAllocator heapAllocator = GMA_DEFAULT; ContextEnum nextContext = GetGameFlow()->GetNextContext(); switch( nextContext ) { case CONTEXT_FRONTEND: { heapAllocator = GMA_LEVEL_MOVIE; break; } case CONTEXT_LOADING_GAMEPLAY: case CONTEXT_LOADING_DEMO: { heapAllocator = GMA_LEVEL_OTHER; break; } case CONTEXT_LOADING_SUPERSPRINT: case CONTEXT_SUPERSPRINT_FE: { heapAllocator = GMA_LEVEL_HUD; break; } default: { break; } } rAssert( heapAllocator != GMA_DEFAULT ); GetLoadingManager()->AddRequest( FILEHANDLER_PURE3D, LOADING_FE_PURE3D_FILE, heapAllocator, LOADING_FE_INVENTORY, LOADING_FE_INVENTORY, this ); #endif } void CGuiScreenLoadingFE::OnProcessRequestsComplete( void* pUserData ) { if( m_itchyAndScratchy != NULL ) { // push and select inventory section for searching // p3d::inventory->PushSection(); p3d::inventory->SelectSection( LOADING_FE_INVENTORY ); bool currentSectionOnly = p3d::inventory->GetCurrentSectionOnly(); p3d::inventory->SetCurrentSectionOnly( true ); // search for drawable, camera, and multicontroller, and assign // them to the itchy & scratchy pure3d object // tDrawable* drawable = p3d::find( LOADING_FE_DRAWABLE ); m_itchyAndScratchy->SetDrawable( drawable ); tCamera* camera = p3d::find( LOADING_FE_CAMERA ); m_itchyAndScratchy->SetCamera( camera ); tMultiController* multiController = p3d::find( LOADING_FE_MULTICONTROLLER ); m_itchyAndScratchy->SetMultiController( multiController ); // pop inventory section and restore states // p3d::inventory->SetCurrentSectionOnly( currentSectionOnly ); p3d::inventory->PopSection(); } } //=========================================================================== // CGuiScreenLoadingFE::InitIntro //=========================================================================== // Description: // // Constraints: None. // // Parameters: None. // // Return: N/A. // //=========================================================================== void CGuiScreenLoadingFE::InitIntro() { RenderLayer* levelLayer = GetRenderManager()->mpLayer( RenderEnums::LevelSlot ); if( levelLayer != NULL ) { levelLayer->Freeze(); } m_loadingBar.SetValue( 1.0f ); // reset current memory usage // m_currentMemoryUsage = 0.0f; // hide loading bar by default // rAssert( m_loadingBarGroup != NULL ); m_loadingBarGroup->SetVisible( false ); // hide explosion overlay // if( m_explosionLayer != NULL && m_explosion != NULL ) { m_explosionLayer->SetVisible( false ); m_explosion->SetVisible( true ); m_elapsedExplosionTime = 0; } } //=========================================================================== // CGuiScreenLoadingFE::InitRunning //=========================================================================== // Description: // // Constraints: None. // // Parameters: None. // // Return: N/A. // //=========================================================================== void CGuiScreenLoadingFE::InitRunning() { } //=========================================================================== // CGuiScreenLoadingFE::InitOutro //=========================================================================== // Description: // // Constraints: None. // // Parameters: None. // // Return: N/A. // //=========================================================================== void CGuiScreenLoadingFE::InitOutro() { RenderLayer* levelLayer = GetRenderManager()->mpLayer( RenderEnums::LevelSlot ); if( levelLayer != NULL && levelLayer->IsFrozen() ) { levelLayer->Thaw(); } #ifdef ENABLE_DYNA_LOADED_RESOURCES p3d::pddi->DrawSync(); if( m_itchyAndScratchy != NULL ) { m_itchyAndScratchy->SetDrawable( NULL ); m_itchyAndScratchy->SetCamera( NULL ); m_itchyAndScratchy->SetMultiController( NULL ); } p3d::inventory->RemoveSectionElements( LOADING_FE_INVENTORY ); #endif rReleasePrintf( "Final memory usage value for loading bar = %.3f\n", m_currentMemoryUsage ); m_loadingBar.SetValue( 0.0f ); // reset loading text animation // m_elapsedTime = 0; rAssert( m_loadingText != NULL ); m_loadingText->SetIndex( 0 ); m_elapsedFireTime = 0; GetSoundManager()->ResetDucking(); } //--------------------------------------------------------------------- // Private Functions //--------------------------------------------------------------------- float CGuiScreenLoadingFE::GetCurrentMemoryUsage( ContextEnum currentContext ) const { float currentMemoryUsage = 0.0f; #ifdef RAD_XBOX int totalMemoryFree = Memory::GetTotalMemoryFree(); #else int totalMemoryFree = GetTotalMemoryFreeInAllHeaps(); #endif if( totalMemoryFree > 0 ) { switch( currentContext ) { case CONTEXT_LOADING_GAMEPLAY: { currentMemoryUsage = (m_startingMemoryAvailable - totalMemoryFree) / TOTAL_INGAME_MEMORY_USAGE; break; } case CONTEXT_LOADING_DEMO: { currentMemoryUsage = (m_startingMemoryAvailable - totalMemoryFree) / TOTAL_DEMO_MEMORY_USAGE; break; } case CONTEXT_LOADING_SUPERSPRINT: { #ifndef RAD_WIN32 currentMemoryUsage = (m_startingMemoryAvailable - totalMemoryFree) / TOTAL_SUPERSPRINT_MEMORY_USAGE; #else // this sucks but i just want to finish it. float memUsage = float( GetLoadingManager()->GetNumRequestsProcessed() ) / TOTAL_SUPERSPRINT_FILES; currentMemoryUsage = m_currentMemoryUsage; if( memUsage - currentMemoryUsage < LOAD_MIN_SPEED ) { currentMemoryUsage = memUsage; } else { float delta = (memUsage - currentMemoryUsage) / LOAD_BLEND_FACTOR; currentMemoryUsage += delta > LOAD_MIN_SPEED ? delta : LOAD_MIN_SPEED; } #endif break; } case CONTEXT_FRONTEND: { currentMemoryUsage = (m_startingMemoryAvailable - totalMemoryFree) / TOTAL_FE_MEMORY_USAGE; break; } default: { rWarningMsg( false, "Invalid context!" ); break; } } } else { rWarningMsg( false, "Why is total memory free negative??" ); } return currentMemoryUsage; }