From 12d556c759df738f1ab457760cb7a6bce514001c Mon Sep 17 00:00:00 2001 From: Chris Danford Date: Thu, 9 Dec 2004 09:41:06 +0000 Subject: [PATCH] allow multiple, simultaneous prepared screens --- stepmania/src/GameCommand.cpp | 18 +++++- stepmania/src/GameCommand.h | 2 + stepmania/src/Screen.cpp | 1 + stepmania/src/ScreenGameplay.cpp | 6 ++ stepmania/src/ScreenManager.cpp | 91 ++++++++++++++++----------- stepmania/src/ScreenManager.h | 22 +++---- stepmania/src/ScreenOptionsMaster.cpp | 7 ++- stepmania/src/ScreenPlayerOptions.cpp | 5 ++ stepmania/src/ScreenSelectMusic.cpp | 2 + stepmania/src/ScreenSongOptions.cpp | 5 ++ stepmania/src/ScreenStage.cpp | 8 +-- stepmania/src/StepMania.cpp | 1 + 12 files changed, 114 insertions(+), 54 deletions(-) diff --git a/stepmania/src/GameCommand.cpp b/stepmania/src/GameCommand.cpp index 8260aa1eb0..996a38adaf 100644 --- a/stepmania/src/GameCommand.cpp +++ b/stepmania/src/GameCommand.cpp @@ -45,7 +45,9 @@ void GameCommand::Init() m_SortOrder = SORT_INVALID; m_iUnlockIndex = -1; m_sSoundPath = ""; - + m_vsScreensToPrepare.clear(); + m_bDeletePreparedScreens = false; + m_bClearBookkeepingData = false; m_bClearMachineStats = false; m_bDownloadMachineStats = false; @@ -245,6 +247,16 @@ void GameCommand::Load( int iIndex, const Commands& cmds ) { m_sSoundPath = sValue; } + + else if( sName == "preparescreen" ) + { + m_vsScreensToPrepare.push_back( sValue ); + } + + else if( sName == "deletepreparedscreens" ) + { + m_bDeletePreparedScreens = true; + } else if( sName == "clearbookkeepingdata" ) { @@ -548,6 +560,10 @@ void GameCommand::Apply( PlayerNumber pn ) const UNLOCKMAN->UnlockCode( m_iUnlockIndex ); if( m_sSoundPath != "" ) SOUND->PlayOnce( THEME->GetPathToS( m_sSoundPath ) ); + FOREACH_CONST( CString, m_vsScreensToPrepare, s ) + SCREENMAN->PrepareScreen( *s ); + if( m_bDeletePreparedScreens ) + SCREENMAN->DeletePreparedScreens(); if( m_bClearBookkeepingData ) { diff --git a/stepmania/src/GameCommand.h b/stepmania/src/GameCommand.h index 2c2dfc7b22..216ef9c1db 100644 --- a/stepmania/src/GameCommand.h +++ b/stepmania/src/GameCommand.h @@ -51,6 +51,8 @@ struct GameCommand // used in SelectMode SortOrder m_SortOrder; int m_iUnlockIndex; // -1 for no unlock CString m_sSoundPath; // "" for no sound + vector m_vsScreensToPrepare; + bool m_bDeletePreparedScreens; bool m_bClearBookkeepingData; bool m_bClearMachineStats; diff --git a/stepmania/src/Screen.cpp b/stepmania/src/Screen.cpp index c1dc7b35f7..8e03c27e75 100644 --- a/stepmania/src/Screen.cpp +++ b/stepmania/src/Screen.cpp @@ -156,6 +156,7 @@ void Screen::HandleScreenMessage( const ScreenMessage SM ) SCREENMAN->SetNewScreen( NEXT_SCREEN ); break; case SM_GoToPrevScreen: + SCREENMAN->DeletePreparedScreens(); SCREENMAN->SetNewScreen( PREV_SCREEN ); break; } diff --git a/stepmania/src/ScreenGameplay.cpp b/stepmania/src/ScreenGameplay.cpp index a19de70055..5778febd93 100644 --- a/stepmania/src/ScreenGameplay.cpp +++ b/stepmania/src/ScreenGameplay.cpp @@ -2295,6 +2295,7 @@ void ScreenGameplay::HandleScreenMessage( const ScreenMessage SM ) GAMESTATE->CancelStage(); + SCREENMAN->DeletePreparedScreens(); SCREENMAN->SetNewScreen( PREV_SCREEN ); break; @@ -2364,9 +2365,14 @@ void ScreenGameplay::HandleScreenMessage( const ScreenMessage SM ) if( PREFSMAN->m_bEventMode ) { if(EVAL_ON_FAIL) // go to the eval screen if we fail + { SCREENMAN->SetNewScreen( "ScreenEvaluationStage" ); + } else // the theme says just fail and go back to the song select for event mode + { + SCREENMAN->DeletePreparedScreens(); SCREENMAN->SetNewScreen( PREV_SCREEN ); + } } else if( GAMESTATE->IsExtraStage() || GAMESTATE->IsExtraStage2() ) SCREENMAN->SetNewScreen( "ScreenEvaluationStage" ); diff --git a/stepmania/src/ScreenManager.cpp b/stepmania/src/ScreenManager.cpp index 0fe669a6a0..d7a4cda70b 100644 --- a/stepmania/src/ScreenManager.cpp +++ b/stepmania/src/ScreenManager.cpp @@ -30,6 +30,7 @@ #include "ThemeManager.h" #include "ScreenSystemLayer.h" #include "BGAnimation.h" +#include "Foreach.h" ScreenManager* SCREENMAN = NULL; // global and accessable from anywhere in our program @@ -54,15 +55,14 @@ ScreenManager::ScreenManager() m_pSharedBGA = new BGAnimation; m_SystemLayer = NULL; + m_MessageSendOnPop = SM_None; + /* By the time this is constructed, THEME has already been set up and set to * the current theme. Call ThemeChanged(), to handle the starting theme * and set up m_SystemLayer. */ ASSERT( THEME ); ASSERT( !THEME->GetCurThemeName().empty() ); this->ThemeChanged(); - - m_ScreenBuffered = NULL; - m_MessageSendOnPop = SM_None; } @@ -74,9 +74,9 @@ ScreenManager::~ScreenManager() SAFE_DELETE( m_pSharedBGA ); for( unsigned i=0; im_sName == sScreenName ) + { + SAFE_DELETE( *s ); + break; + } + } + + m_vPreparedScreens.push_back( MakeNewScreen(sScreenName) ); } -void ScreenManager::LoadPreppedScreen() +void ScreenManager::DeletePreparedScreens() { - ASSERT( m_ScreenBuffered != NULL); - SetFromNewScreen( m_ScreenBuffered, false ); - - m_ScreenBuffered = NULL; -} - -void ScreenManager::DeletePreppedScreen() -{ - SAFE_DELETE( m_ScreenBuffered ); + FOREACH( Screen*, m_vPreparedScreens, s ) + SAFE_DELETE( *s ); + m_vPreparedScreens.clear(); TEXTUREMAN->DeleteCachedTextures(); } @@ -279,7 +281,7 @@ void ScreenManager::ClearScreenStack() m_ScreenStack.back()->HandleScreenMessage( SM_LoseFocus ); // move current screen(s) to ScreenToDelete - m_ScreensToDelete.insert(m_ScreensToDelete.end(), m_ScreenStack.begin(), m_ScreenStack.end()); + m_vScreensToDelete.insert(m_vScreensToDelete.end(), m_ScreenStack.begin(), m_ScreenStack.end()); m_ScreenStack.clear(); } @@ -299,7 +301,7 @@ void ScreenManager::SetFromNewScreen( Screen *pNewScreen, bool Stack ) void ScreenManager::SetNewScreen( const CString &sScreenName ) { - m_DelayedScreen = sScreenName; + m_sDelayedScreen = sScreenName; /* If we're not delaying screen loads, load it now. Otherwise, we'll load * it on the next iteration. Only delay if we already have a screen @@ -311,20 +313,37 @@ void ScreenManager::SetNewScreen( const CString &sScreenName ) void ScreenManager::LoadDelayedScreen() { retry: - CString sScreenName = m_DelayedScreen; - m_DelayedScreen = ""; - - /* If we prepped a screen but didn't use it, nuke it. */ - SAFE_DELETE( m_ScreenBuffered ); + CString sScreenName = m_sDelayedScreen; + m_sDelayedScreen = ""; Screen* pOldTopScreen = m_ScreenStack.empty() ? NULL : m_ScreenStack.back(); - // It makes sense that ScreenManager should allocate memory for a new screen since it - // deletes it later on. This also convention will reduce includes because screens won't - // have to include each other's headers of other screens. - Screen* pNewScreen = MakeNewScreen(sScreenName); + // + // Search prepped screens to see if we already have this screen available. + // If not prepped, then make it. + // + Screen* pNewScreen = NULL; + FOREACH( Screen*, m_vPreparedScreens, s ) + { + if( (*s)->m_sName == sScreenName ) + { + pNewScreen = *s; + m_vPreparedScreens.erase( s ); + break; + } + } + if( pNewScreen == NULL ) + pNewScreen = MakeNewScreen(sScreenName); + + // Load shared BGAnimation + CString sNewBGA = THEME->GetPathToB(sScreenName+" background"); + if( m_sLastLoadedBackground != sNewBGA ) + { + m_pSharedBGA->LoadFromAniDir( sNewBGA ); + m_sLastLoadedBackground = sNewBGA; + } if( pOldTopScreen!=NULL && m_ScreenStack.back()!=pOldTopScreen ) @@ -425,7 +444,7 @@ void ScreenManager::PopTopScreen( ScreenMessage SM ) Screen* pScreenToPop = m_ScreenStack.back(); // top menu pScreenToPop->HandleScreenMessage( SM_LoseFocus ); m_ScreenStack.erase(m_ScreenStack.end()-1, m_ScreenStack.end()); - m_ScreensToDelete.push_back( pScreenToPop ); + m_vScreensToDelete.push_back( pScreenToPop ); /* Post to the new top. This must be done now; otherwise, we'll have a single * frame between popping and these messages, which can result in a frame where eg. diff --git a/stepmania/src/ScreenManager.h b/stepmania/src/ScreenManager.h index 5a26c00ad1..9db581cfb6 100644 --- a/stepmania/src/ScreenManager.h +++ b/stepmania/src/ScreenManager.h @@ -35,9 +35,8 @@ public: void Draw(); void Input( const DeviceInput& DeviceI, const InputEventType type, const GameInput &GameI, const MenuInput &MenuI, const StyleInput &StyleI ); - void PrepNewScreen( const CString &sName ); - void LoadPreppedScreen(); - void DeletePreppedScreen(); + void PrepareScreen( const CString &sScreenName ); // creates and caches screen so that the next call to SetNewScreen for the prep'd screen will be very quick. + void DeletePreparedScreens(); void SetNewScreen( const CString &sName ); void AddNewScreenToTop( const CString &sName, ScreenMessage messageSendOnPop ); @@ -55,10 +54,6 @@ public: void RefreshCreditsMessages(); void ThemeChanged(); - void EmptyDeleteQueue(); - - void LoadDelayedScreen(); - Screen *GetTopScreen(); public: @@ -66,18 +61,23 @@ public: // in draw order first to last // BGAnimation *m_pSharedBGA; // BGA object that's persistent between screens - void PlaySharedBackgroundOffCommand(); + void PlaySharedBackgroundOffCommand(); private: vector m_ScreenStack; // bottommost to topmost - ScreenMessage m_MessageSendOnPop; - vector m_ScreensToDelete; - Screen *m_ScreenBuffered; ScreenSystemLayer *m_SystemLayer; + CString m_sLastLoadedBackground; + CString m_sDelayedScreen; + ScreenMessage m_MessageSendOnPop; + vector m_vPreparedScreens; + vector m_vScreensToDelete; + Screen* MakeNewScreen( const CString &sName ); void SetFromNewScreen( Screen *pNewScreen, bool Stack ); CString m_DelayedScreen; void ClearScreenStack(); + void EmptyDeleteQueue(); + void LoadDelayedScreen(); // Keep these sounds always loaded, because they could be // played at any time. We want to eliminate SOUND->PlayOnce diff --git a/stepmania/src/ScreenOptionsMaster.cpp b/stepmania/src/ScreenOptionsMaster.cpp index ece7b4d44a..0ac15db561 100644 --- a/stepmania/src/ScreenOptionsMaster.cpp +++ b/stepmania/src/ScreenOptionsMaster.cpp @@ -577,10 +577,15 @@ void ScreenOptionsMaster::GoToPrevScreen() { /* XXX: A better way to handle this would be to check if we're a pushed screen. */ if( GAMESTATE->m_bEditing ) + { SCREENMAN->PopTopScreen(); - // XXX: handle different destinations based on play mode? + // XXX: handle different destinations based on play mode? + } else + { + SCREENMAN->DeletePreparedScreens(); SCREENMAN->SetNewScreen( PREV_SCREEN ); // (GAMESTATE->m_PlayMode) ); + } } void ScreenOptionsMaster::RefreshIcons() diff --git a/stepmania/src/ScreenPlayerOptions.cpp b/stepmania/src/ScreenPlayerOptions.cpp index 8e5e78d653..51d0cf4aa9 100644 --- a/stepmania/src/ScreenPlayerOptions.cpp +++ b/stepmania/src/ScreenPlayerOptions.cpp @@ -60,9 +60,14 @@ ScreenPlayerOptions::ScreenPlayerOptions( CString sClassName ) : void ScreenPlayerOptions::GoToPrevScreen() { if( GAMESTATE->m_bEditing ) + { SCREENMAN->PopTopScreen(); + } else + { + SCREENMAN->DeletePreparedScreens(); SCREENMAN->SetNewScreen( PREV_SCREEN ); + } } void ScreenPlayerOptions::GoToNextScreen() diff --git a/stepmania/src/ScreenSelectMusic.cpp b/stepmania/src/ScreenSelectMusic.cpp index 98c2f4f2d5..588d4ca708 100644 --- a/stepmania/src/ScreenSelectMusic.cpp +++ b/stepmania/src/ScreenSelectMusic.cpp @@ -1045,7 +1045,9 @@ void ScreenSelectMusic::HandleScreenMessage( const ScreenMessage SM ) } return; case SM_GoToPrevScreen: + SCREENMAN->DeletePreparedScreens(); SCREENMAN->SetNewScreen( PREV_SCREEN ); + /* We may have stray SM_SongChanged messages from the music wheel. We can't * handle them anymore, since the title menu (and attract screens) reset * the game state, so just discard them. */ diff --git a/stepmania/src/ScreenSongOptions.cpp b/stepmania/src/ScreenSongOptions.cpp index 775fa287ce..d7a4e9103b 100644 --- a/stepmania/src/ScreenSongOptions.cpp +++ b/stepmania/src/ScreenSongOptions.cpp @@ -32,9 +32,14 @@ ScreenSongOptions::ScreenSongOptions( CString sClassName ) : void ScreenSongOptions::GoToPrevScreen() { if( GAMESTATE->m_bEditing ) + { SCREENMAN->PopTopScreen( SM_None ); + } else + { + SCREENMAN->DeletePreparedScreens(); SCREENMAN->SetNewScreen( PREV_SCREEN ); + } } void ScreenSongOptions::GoToNextScreen() diff --git a/stepmania/src/ScreenStage.cpp b/stepmania/src/ScreenStage.cpp index 289cf63cee..a86a05b330 100644 --- a/stepmania/src/ScreenStage.cpp +++ b/stepmania/src/ScreenStage.cpp @@ -105,7 +105,7 @@ void ScreenStage::HandleScreenMessage( const ScreenMessage SM ) * we can. */ this->PostScreenMessage( SM_BeginFadingOut, MINIMUM_DELAY ); - SCREENMAN->PrepNewScreen( NEXT_SCREEN ); + SCREENMAN->PrepareScreen( NEXT_SCREEN ); break; case SM_BeginFadingOut: @@ -116,16 +116,14 @@ void ScreenStage::HandleScreenMessage( const ScreenMessage SM ) OFF_COMMAND( m_Artist ); OFF_COMMAND( m_Banner ); SCREENMAN->PlaySharedBackgroundOffCommand(); - - this->PostScreenMessage( SM_GoToNextScreen, this->GetTweenTimeLeft() ); break; case SM_GoToNextScreen: - SCREENMAN->LoadPreppedScreen(); /* use prepped */ + SCREENMAN->SetNewScreen( NEXT_SCREEN ); break; case SM_GoToPrevScreen: - SCREENMAN->DeletePreppedScreen(); + SCREENMAN->DeletePreparedScreens(); SCREENMAN->SetNewScreen( PREV_SCREEN ); break; } diff --git a/stepmania/src/StepMania.cpp b/stepmania/src/StepMania.cpp index 932c871710..52ecf1aa42 100644 --- a/stepmania/src/StepMania.cpp +++ b/stepmania/src/StepMania.cpp @@ -1289,6 +1289,7 @@ bool HandleGlobalInputs( DeviceInput DeviceI, InputEventType type, GameInput Gam * (to prevent quitting without storing changes). */ if( !GAMESTATE->m_bIsOnSystemMenu ) { + SCREENMAN->DeletePreparedScreens(); SCREENMAN->SystemMessage( "OPERATOR" ); GAMESTATE->Reset(); SCREENMAN->SetNewScreen( "ScreenOptionsMenu" );