fix "zero first update" logic
This commit is contained in:
Glenn Maynard
2004-01-30 05:07:26 +00:00
parent 62144e5794
commit 6e13a833d2
6 changed files with 39 additions and 65 deletions
+32 -55
View File
@@ -371,21 +371,6 @@ void ScreenManager::EmptyDeleteQueue()
TEXTUREMAN->DiagnosticOutput(); TEXTUREMAN->DiagnosticOutput();
} }
/* XXX: Big hack:
* All screens must receive at least one update before they draw.
* However, no screen should ever receive an update until it's ready
* to be drawn; otherwise Gameplay will queue music to start even though
* Stage might still be delaying for a while, throwing off timing.
*
* This is tricky with prepped screens. We can't do an Update(0) in
* LoadPreppedScreen, since that'll cause the delete queue to be cleared
* while the screen is on the stack, and possibly other odd things.
* So, update before we draw, which is also a hack (rendering shouldn't
* change state!). Only do this when we have to, so we don't double
* the number of updates. */
static bool g_TopNeedsNeedsNullUpdate = false;
static bool g_SkipRendering = false;
void ScreenManager::Update( float fDeltaTime ) void ScreenManager::Update( float fDeltaTime )
{ {
// Only update the topmost screen on the stack. // Only update the topmost screen on the stack.
@@ -402,9 +387,6 @@ void ScreenManager::Update( float fDeltaTime )
* to load the new screen will come after 4 seconds plus the load time. * to load the new screen will come after 4 seconds plus the load time.
* *
* So, let's just zero the first update for every screen. * So, let's just zero the first update for every screen.
*
* XXX: If a new Screen is set during this Update, that new screen is Drawn
* before its first Update.
*/ */
ASSERT( !m_ScreenStack.empty() || m_DelayedScreen != "" ); // Why play the game if there is nothing showing? ASSERT( !m_ScreenStack.empty() || m_DelayedScreen != "" ); // Why play the game if there is nothing showing?
@@ -434,31 +416,20 @@ void ScreenManager::Update( float fDeltaTime )
TEXTUREMAN->DiagnosticOutput(); TEXTUREMAN->DiagnosticOutput();
LoadDelayedScreen(); LoadDelayedScreen();
/* Ack. We can't Update(0), since we want to skip the *next* update
* (which is the one that will have all this load time in it). We
* can't draw it until we've updated it. Let's simply not render
* the next frame, so we'll come around quickly and handle it correctly. */
g_SkipRendering = true;
} }
} }
void ScreenManager::Draw() void ScreenManager::Draw()
{ {
DISPLAY->BeginFrame(); /* If it hasn't been updated yet, skip the render. We can't call Update(0), since
* that'll confuse the "zero out the next update after loading a screen logic.
if(g_SkipRendering) * If we don't render, don't call BeginFrame or EndFrame. That way, we won't
{ * clear the buffer, and we won't wait for vsync. */
/* Leave the frame there (if any). */ if( m_ScreenStack.back()->IsFirstUpdate() )
g_SkipRendering = false;
return; return;
}
if(g_TopNeedsNeedsNullUpdate) DISPLAY->BeginFrame();
{
g_TopNeedsNeedsNullUpdate = false;
m_ScreenStack.back()->Update( 0 );
}
if( !m_ScreenStack.empty() && !m_ScreenStack.back()->IsTransparent() ) // top screen isn't transparent if( !m_ScreenStack.empty() && !m_ScreenStack.back()->IsTransparent() ) // top screen isn't transparent
m_ScreenStack.back()->Draw(); m_ScreenStack.back()->Draw();
@@ -485,7 +456,7 @@ void ScreenManager::Input( const DeviceInput& DeviceI, const InputEventType type
Screen* ScreenManager::MakeNewScreen( CString sClassName ) Screen* ScreenManager::MakeNewScreen( CString sClassName )
{ {
/* By default, RageSounds handles the song timer. When we change screens, reset this; /* By default, RageSounds handles the song timer. When we change screens, reset this;
* screens turn this off in their ctor if they handle timers themselves (gameplay, edit). */ * screens turn this off in SM_GainFocus if they handle timers themselves (edit). */
SOUND->HandleSongTimer( true ); SOUND->HandleSongTimer( true );
/* Cleanup song data. This can free up a fair bit of memory, so do it before /* Cleanup song data. This can free up a fair bit of memory, so do it before
@@ -512,11 +483,7 @@ void ScreenManager::PrepNewScreen( CString sClassName )
void ScreenManager::LoadPreppedScreen() void ScreenManager::LoadPreppedScreen()
{ {
ASSERT( m_ScreenBuffered != NULL); ASSERT( m_ScreenBuffered != NULL);
SetNewScreen( m_ScreenBuffered ); SetFromNewScreen( m_ScreenBuffered, false );
// Need to update the new screen once, or else it will be
// drawn before ever being Update()d.
g_TopNeedsNeedsNullUpdate = true;
m_ScreenBuffered = NULL; m_ScreenBuffered = NULL;
} }
@@ -527,20 +494,22 @@ void ScreenManager::DeletePreppedScreen()
TEXTUREMAN->DeleteCachedTextures(); TEXTUREMAN->DeleteCachedTextures();
} }
void ScreenManager::SetNewScreen( Screen *pNewScreen ) /* Add a screen to m_ScreenStack. If Stack is true, it's added to the stack; otherwise any
* current screens are removed. This is the only function that adds to m_ScreenStack. */
void ScreenManager::SetFromNewScreen( Screen *pNewScreen, bool Stack )
{ {
RefreshCreditsMessages(); RefreshCreditsMessages();
THEME->ReloadMetricsIfNecessary(); THEME->ReloadMetricsIfNecessary();
// move current screen(s) to ScreenToDelete if( !Stack )
m_ScreensToDelete.insert(m_ScreensToDelete.end(), m_ScreenStack.begin(), m_ScreenStack.end()); {
m_ScreenStack.clear(); // move current screen(s) to ScreenToDelete
m_ScreensToDelete.insert(m_ScreensToDelete.end(), m_ScreenStack.begin(), m_ScreenStack.end());
m_ScreenStack.clear();
}
m_ScreenStack.push_back( pNewScreen ); m_ScreenStack.push_back( pNewScreen );
/* Make sure we always send at least one update before drawing. */
pNewScreen->Update( 0 );
PostMessageToTopScreen( SM_GainFocus, 0 ); PostMessageToTopScreen( SM_GainFocus, 0 );
} }
@@ -608,7 +577,8 @@ retry:
else else
GAMESTATE->m_bIsOnSystemMenu = false; GAMESTATE->m_bIsOnSystemMenu = false;
SetNewScreen( pNewScreen ); LOG->Trace("... SetFromNewScreen");
SetFromNewScreen( pNewScreen, false );
} }
void ScreenManager::AddNewScreenToTop( CString sClassName, ScreenMessage messageSendOnPop ) void ScreenManager::AddNewScreenToTop( CString sClassName, ScreenMessage messageSendOnPop )
@@ -619,7 +589,7 @@ void ScreenManager::AddNewScreenToTop( CString sClassName, ScreenMessage message
m_ScreenStack.back()->HandleScreenMessage( SM_LoseFocus ); m_ScreenStack.back()->HandleScreenMessage( SM_LoseFocus );
Screen* pNewScreen = MakeNewScreen(sClassName); Screen* pNewScreen = MakeNewScreen(sClassName);
m_ScreenStack.push_back( pNewScreen ); SetFromNewScreen( pNewScreen, true );
m_MessageSendOnPop = messageSendOnPop; m_MessageSendOnPop = messageSendOnPop;
} }
@@ -633,16 +603,22 @@ void ScreenManager::Prompt( ScreenMessage SM_SendWhenDone, CString sText, bool b
m_ScreenStack.back()->HandleScreenMessage( SM_LoseFocus ); m_ScreenStack.back()->HandleScreenMessage( SM_LoseFocus );
// add the new state onto the back of the array // add the new state onto the back of the array
m_ScreenStack.push_back( new ScreenPrompt(SM_SendWhenDone, sText, bYesNo, bDefaultAnswer, OnYes, OnNo, pCallbackData) ); Screen *pNewScreen = new ScreenPrompt( sText, bYesNo, bDefaultAnswer, OnYes, OnNo, pCallbackData);
SetFromNewScreen( pNewScreen, true );
m_MessageSendOnPop = SM_SendWhenDone;
} }
void ScreenManager::TextEntry( ScreenMessage SM_SendWhenDone, CString sQuestion, CString sInitialAnswer, void(*OnOK)(CString sAnswer), void(*OnCanel)() ) void ScreenManager::TextEntry( ScreenMessage SM_SendWhenDone, CString sQuestion, CString sInitialAnswer, void(*OnOK)(CString sAnswer), void(*OnCancel)() )
{ {
if( m_ScreenStack.size() ) if( m_ScreenStack.size() )
m_ScreenStack.back()->HandleScreenMessage( SM_LoseFocus ); m_ScreenStack.back()->HandleScreenMessage( SM_LoseFocus );
// add the new state onto the back of the array // add the new state onto the back of the array
m_ScreenStack.push_back( new ScreenTextEntry("ScreenTextEntry", SM_SendWhenDone, sQuestion, sInitialAnswer, OnOK, OnCanel) ); Screen *pNewScreen = new ScreenTextEntry( "ScreenTextEntry", sQuestion, sInitialAnswer, OnOK, OnCancel );
SetFromNewScreen( pNewScreen, true );
m_MessageSendOnPop = SM_SendWhenDone;
} }
void ScreenManager::MiniMenu( Menu* pDef, ScreenMessage SM_SendOnOK, ScreenMessage SM_SendOnCancel ) void ScreenManager::MiniMenu( Menu* pDef, ScreenMessage SM_SendOnOK, ScreenMessage SM_SendOnCancel )
@@ -651,7 +627,8 @@ void ScreenManager::MiniMenu( Menu* pDef, ScreenMessage SM_SendOnOK, ScreenMessa
m_ScreenStack.back()->HandleScreenMessage( SM_LoseFocus ); m_ScreenStack.back()->HandleScreenMessage( SM_LoseFocus );
// add the new state onto the back of the array // add the new state onto the back of the array
m_ScreenStack.push_back( new ScreenMiniMenu(pDef, SM_SendOnOK, SM_SendOnCancel) ); Screen *pNewScreen = new ScreenMiniMenu( pDef, SM_SendOnOK, SM_SendOnCancel );
SetFromNewScreen( pNewScreen, true );
} }
void ScreenManager::PopTopScreen( ScreenMessage SM ) void ScreenManager::PopTopScreen( ScreenMessage SM )
+1 -1
View File
@@ -67,7 +67,7 @@ private:
ScreenSystemLayer *m_SystemLayer; ScreenSystemLayer *m_SystemLayer;
Screen* MakeNewScreen( CString sClassName ); Screen* MakeNewScreen( CString sClassName );
void SetNewScreen( Screen *pNewScreen ); void SetFromNewScreen( Screen *pNewScreen, bool Stack );
CString m_DelayedScreen; CString m_DelayedScreen;
}; };
+2 -3
View File
@@ -27,12 +27,11 @@ const float PROMPT_Y = CENTER_Y + 120;
bool ScreenPrompt::s_bLastAnswer = false; bool ScreenPrompt::s_bLastAnswer = false;
ScreenPrompt::ScreenPrompt( ScreenMessage SM_SendWhenDone, CString sText, bool bYesNoPrompt, bool bDefaultAnswer, void(*OnYes)(void*), void(*OnNo)(void*), void* pCallbackData ) : ScreenPrompt::ScreenPrompt( CString sText, bool bYesNoPrompt, bool bDefaultAnswer, void(*OnYes)(void*), void(*OnNo)(void*), void* pCallbackData ) :
Screen("ScreenPrompt") Screen("ScreenPrompt")
{ {
m_bIsTransparent = true; // draw screens below us m_bIsTransparent = true; // draw screens below us
m_SMSendWhenDone = SM_SendWhenDone;
m_bYesNoPrompt = bYesNoPrompt; m_bYesNoPrompt = bYesNoPrompt;
m_bAnswer = bDefaultAnswer; m_bAnswer = bDefaultAnswer;
m_pOnYes = OnYes; m_pOnYes = OnYes;
@@ -128,7 +127,7 @@ void ScreenPrompt::HandleScreenMessage( const ScreenMessage SM )
case SM_DoneOpeningWipingLeft: case SM_DoneOpeningWipingLeft:
break; break;
case SM_DoneOpeningWipingRight: case SM_DoneOpeningWipingRight:
SCREENMAN->PopTopScreen( m_SMSendWhenDone ); SCREENMAN->PopTopScreen();
break; break;
} }
} }
+1 -1
View File
@@ -21,7 +21,7 @@ class ScreenPrompt : public Screen
{ {
public: public:
ScreenPrompt( CString sName ); ScreenPrompt( CString sName );
ScreenPrompt( ScreenMessage SM_SendWhenDone, CString sText, bool bYesNoPrompt=false, bool bDefaultAnswer = false, void(*OnYes)(void*) = NULL, void(*OnNo)(void*) = NULL, void* pCallbackData = NULL ); ScreenPrompt( CString sText, bool bYesNoPrompt=false, bool bDefaultAnswer = false, void(*OnYes)(void*) = NULL, void(*OnNo)(void*) = NULL, void* pCallbackData = NULL );
virtual void Update( float fDeltaTime ); virtual void Update( float fDeltaTime );
virtual void DrawPrimitives(); virtual void DrawPrimitives();
+2 -3
View File
@@ -40,12 +40,11 @@ bool ScreenTextEntry::s_bCancelledLast = false;
* Handle UTF-8. Right now, we need to at least be able to backspace * Handle UTF-8. Right now, we need to at least be able to backspace
* a whole UTF-8 character. Better would be to operate in longchars. * a whole UTF-8 character. Better would be to operate in longchars.
*/ */
ScreenTextEntry::ScreenTextEntry( CString sClassName, ScreenMessage SM_SendWhenDone, CString sQuestion, CString sInitialAnswer, void(*OnOK)(CString sAnswer), void(*OnCancel)() ) : ScreenTextEntry::ScreenTextEntry( CString sClassName, CString sQuestion, CString sInitialAnswer, void(*OnOK)(CString sAnswer), void(*OnCancel)() ) :
Screen( sClassName ) Screen( sClassName )
{ {
m_bIsTransparent = true; // draw screens below us m_bIsTransparent = true; // draw screens below us
m_SMSendWhenDone = SM_SendWhenDone;
m_pOnOK = OnOK; m_pOnOK = OnOK;
m_pOnCancel = OnCancel; m_pOnCancel = OnCancel;
@@ -179,7 +178,7 @@ void ScreenTextEntry::HandleScreenMessage( const ScreenMessage SM )
case SM_DoneOpeningWipingLeft: case SM_DoneOpeningWipingLeft:
break; break;
case SM_DoneOpeningWipingRight: case SM_DoneOpeningWipingRight:
SCREENMAN->PopTopScreen( m_SMSendWhenDone ); SCREENMAN->PopTopScreen();
break; break;
} }
} }
+1 -2
View File
@@ -22,7 +22,7 @@
class ScreenTextEntry : public Screen class ScreenTextEntry : public Screen
{ {
public: public:
ScreenTextEntry( CString sName, ScreenMessage SM_SendWhenDone, CString sQuestion, CString sInitialAnswer, void(*OnOK)(CString sAnswer) = NULL, void(*OnCanel)() = NULL ); ScreenTextEntry( CString sName, CString sQuestion, CString sInitialAnswer, void(*OnOK)(CString sAnswer) = NULL, void(*OnCanel)() = NULL );
virtual void Update( float fDeltaTime ); virtual void Update( float fDeltaTime );
virtual void DrawPrimitives(); virtual void DrawPrimitives();
@@ -45,7 +45,6 @@ protected:
Quad m_rectAnswerBox; Quad m_rectAnswerBox;
wstring m_sAnswer; wstring m_sAnswer;
BitmapText m_textAnswer; BitmapText m_textAnswer;
ScreenMessage m_SMSendWhenDone;
void(*m_pOnOK)( CString sAnswer ); void(*m_pOnOK)( CString sAnswer );
void(*m_pOnCancel)(); void(*m_pOnCancel)();
bool m_bCancelled; bool m_bCancelled;