From 74d7bcd2bf9b5525840bb9f737328cac9e610c5c Mon Sep 17 00:00:00 2001 From: Chris Danford Date: Fri, 18 Apr 2003 23:55:20 +0000 Subject: [PATCH] Revamp texture caching system --- stepmania/README-FIRST.html | 124 +++++++++++++++++++++- stepmania/src/PrefsManager.cpp | 8 +- stepmania/src/PrefsManager.h | 2 +- stepmania/src/RageTexture.h | 2 +- stepmania/src/RageTextureManager.cpp | 103 ++++++++++-------- stepmania/src/RageTextureManager.h | 20 ++-- stepmania/src/ScreenAppearanceOptions.cpp | 1 + stepmania/src/ScreenGraphicOptions.cpp | 4 +- stepmania/src/ScreenManager.cpp | 4 +- stepmania/src/ScreenTitleMenu.cpp | 2 + stepmania/src/StepMania.cpp | 9 +- 11 files changed, 216 insertions(+), 63 deletions(-) diff --git a/stepmania/README-FIRST.html b/stepmania/README-FIRST.html index 75559535f1..dc91ff3e16 100644 --- a/stepmania/README-FIRST.html +++ b/stepmania/README-FIRST.html @@ -6,7 +6,7 @@ -

StepMania 3.0 final
+

StepMania X.X
©2001-2003, StepMania team, All rights reserved.
http://www.stepmania.com

@@ -35,11 +35,14 @@ and Help
Creating an Announcer
Creating a Note Skin
Creating a Theme
+Actor Commands
+ScreenSelect
How StepMania Loads Textures
Building StepMania from CVS Source
Thanks

See the file NEWS for version history.
+See the file COPYING.txt for license information.


@@ -923,6 +926,125 @@ Graphics folder "Themes\MySuperTheme\Graphics".


+

Actor Commands (top)

+
+

+ +
+In the old paradigm, you would define the position of an Actor with two +different metrics - one for the X position, and one for the Y. For example:
+ObjectX=100
+ObjectY=220
+
+This system is being replaced by more powerful "commands strings". A command +string can set positions, colors, effects, and also script animations over time. +Positioning an Actor with command string would look like this:
+ObjectOnCommand=x,100;y,220
+
+A command string contains one or more commands separated by semicolons. This +command string contains two commands: "x,100" and "y,220". A command is made up +of a command name and a list of parameters. The command name and any parameters +are separated by commas. In the example above, both the commands "x" and "y" +both take exactly one parameter. Other commands like "diffuse" take 4 parameters +(R, G, B, and A). For example, the command "diffuse,1,0,1,1" would turn an +Actor's color to opaque purple.
+
+Typically, the metrics file will have two commands per Actor - the "OnCommand" +(which is where you command an Actor to tween onto the screen), and the "OffCommand" +(for tweening the Actor off the screen).
+
+Below is a list of actor commands and their equivalent C++ equivalents. I'll +have an explanation of animations and more examples in the full documentation.
+
+
+sleep BeginTweening( fParam(0), TWEEN_LINEAR );
+linear BeginTweening( fParam(0), TWEEN_LINEAR );
+accelerate BeginTweening( fParam(0), TWEEN_ACCELERATE );
+decelerate BeginTweening( fParam(0), TWEEN_DECELERATE );
+bouncebegin BeginTweening( fParam(0), TWEEN_BOUNCE_BEGIN );
+bounceend BeginTweening( fParam(0), TWEEN_BOUNCE_END );
+spring BeginTweening( fParam(0), TWEEN_SPRING );
+stoptweening { StopTweening(); BeginTweening( 0.0001f, TWEEN_LINEAR ); }
+x SetX( fParam(0) );
+y SetY( fParam(0) );
+xoffset SetX( GetX()+fParam(0) );
+yoffset SetY( GetY()+fParam(0) );
+zoom SetZoom( fParam(0) );
+zoomx SetZoomY( fParam(0) );
+zoomy SetZoomY( fParam(0) );
+diffuse SetDiffuse( RageColor(fParam(0),fParam(1),fParam(2),fParam(3)) );
+glow SetGlow( RageColor(fParam(0),fParam(1),fParam(2),fParam(3)) );
+rotationx SetRotationX( fParam(0) );
+rotationy SetRotationY( fParam(0) );
+rotationz SetRotationZ( fParam(0) );
+shadowlength SetShadowLength( fParam(0) );
+horizalign SetHorizAlign( sParam(0) );
+vertalign SetVertAlign( sParam(0) );
+diffuseblink SetEffectDiffuseBlink();
+diffuseshift SetEffectDiffuseShift();
+glowblink SetEffectGlowBlink();
+glowshift SetEffectGlowShift();
+wag SetEffectWag();
+bounce SetEffectBounce();
+bob SetEffectBob();
+spin SetEffectSpin();
+vibrate SetEffectVibrate();
+stopeffect SetEffectNone();
+effectcolor1 SetEffectColor1( RageColor(fParam(0),fParam(1),fParam(2),fParam(3)) +);
+effectcolor2 SetEffectColor2( RageColor(fParam(0),fParam(1),fParam(2),fParam(3)) +);
+effectperiod SetEffectPeriod( fParam(0) );
+effectmagnitude SetEffectMagnitude( RageVector3(fParam(0),fParam(1),fParam(2)) +);
+additiveblend EnableAdditiveBlend( iParam(0)!=0 );
+
+

+
+

ScreenSelect (top)

+
+

+ +
+ScreenSelect is a type of screen that presents the user with a list of choices. +The choices shown on these screens can be Styles, Difficulties, PlayModes, or +any combination thereof. Each ScreenSelect screen has two metrics that define +what choices are shown (examples below). Currently, there are only two different +screens that support the ScreenSelect framework.
+- ScreenSelectMaxType1
+- ScreenSelectMaxType2
+- (more will be converted over in the next couple days)
+
+
+// Example 1: Show all Styles for the current game type the DDR MAX Select Style +template
+
+[ScreenSelectMaxType1]
+ChoicesType=0 // 0=styles, 1=difficulties, 2=modes, 3=games
+Choices=
+
+
+// Example 2: Show specific Difficulty and PlayMode choices using a DDR MAX +Select Difficulty template
+
+[ScreenSelectMaxType2]
+ChoicesType=1 // 0=styles, 1=difficulties, 2=modes, 3=games
+Choices=Beginner,Easy,Medium,Hard,Nonstop,Oni,Endless
+
+
+// Example 3: Show specific Style-PlayMode-Difficulty combinations using a DDR +MAX Select Style template
+
+ChoicesType=2 // 0=styles, 1=difficulties, 2=modes, 3=games
+Choices=versus-arcade-medium,couple-arcade-medium,double-arcade-medium,single-arcade-medium,single-battle-medium,double-battle-medium,couple-battle-medium,versus-battle-medium
+
+
+
+
+

+
How StepMania Loads Textures (top)
diff --git a/stepmania/src/PrefsManager.cpp b/stepmania/src/PrefsManager.cpp index d6957837c1..f77c2ddb18 100644 --- a/stepmania/src/PrefsManager.cpp +++ b/stepmania/src/PrefsManager.cpp @@ -71,8 +71,8 @@ PrefsManager::PrefsManager() m_bShowSelectGroup = true; m_bShowTranslations = true; m_bArcadeOptionsNavigation = false; - m_bSoloSingle = false; // OFF!!!! - m_iUnloadTextureDelaySeconds = 0; // disabled 60*30; // 30 mins + m_bSoloSingle = false; + m_bDelayedTextureDelete = true; m_MusicWheelUsesSections = ALWAYS; m_iMusicWheelSwitchSpeed = 10; m_bChangeBannersWhenFast = false; @@ -163,7 +163,7 @@ void PrefsManager::ReadGlobalPrefsFromDisk( bool bSwitchToLastPlayedGame ) ini.GetValueB( "Options", "ShowTranslations", m_bShowTranslations ); ini.GetValueB( "Options", "ArcadeOptionsNavigation", m_bArcadeOptionsNavigation ); ini.GetValue ( "Options", "DWIPath", m_DWIPath ); - ini.GetValueI( "Options", "UnloadTextureDelaySeconds", m_iUnloadTextureDelaySeconds ); + ini.GetValueB( "Options", "DelayedTextureDelete", m_bDelayedTextureDelete ); ini.GetValueI( "Options", "MusicWheelUsesSections", (int&)m_MusicWheelUsesSections ); ini.GetValueI( "Options", "MusicWheelSwitchSpeed", m_iMusicWheelSwitchSpeed ); ini.GetValueB( "Options", "ChangeBannersWhenFast", m_bChangeBannersWhenFast ); @@ -245,7 +245,7 @@ void PrefsManager::SaveGlobalPrefsToDisk() ini.SetValueB( "Options", "ShowTranslations", m_bShowTranslations ); ini.SetValueB( "Options", "ArcadeOptionsNavigation", m_bArcadeOptionsNavigation ); ini.SetValue ( "Options", "DWIPath", m_DWIPath ); - ini.SetValueI( "Options", "UnloadTextureDelaySeconds", m_iUnloadTextureDelaySeconds ); + ini.SetValueB( "Options", "DelayedTextureDelete", m_bDelayedTextureDelete ); ini.SetValueI( "Options", "MusicWheelUsesSections", m_MusicWheelUsesSections ); ini.SetValueI( "Options", "MusicWheelSwitchSpeed", m_iMusicWheelSwitchSpeed ); ini.SetValueB( "Options", "ChangeBannersWhenFast", m_bChangeBannersWhenFast ); diff --git a/stepmania/src/PrefsManager.h b/stepmania/src/PrefsManager.h index 1a849567ec..0a5e35d075 100644 --- a/stepmania/src/PrefsManager.h +++ b/stepmania/src/PrefsManager.h @@ -33,7 +33,7 @@ public: bool m_bUseBGIfNoBanner; bool m_bHiddenSongs; bool m_bVsync; - int m_iUnloadTextureDelaySeconds; + bool m_bDelayedTextureDelete; bool m_bIgnoreJoyAxes; bool m_bOnlyDedicatedMenuButtons; diff --git a/stepmania/src/RageTexture.h b/stepmania/src/RageTexture.h index 3bf8d8d7b2..09e9d9fb81 100644 --- a/stepmania/src/RageTexture.h +++ b/stepmania/src/RageTexture.h @@ -86,7 +86,7 @@ public: const CString &GetFilePath() const { return GetID().filename; } int m_iRefCount; - int m_iTimeOfLastUnload; + bool m_bCacheThis; /* The ID that we were asked to load: */ const RageTextureID &GetID() const { return m_ID; } diff --git a/stepmania/src/RageTextureManager.cpp b/stepmania/src/RageTextureManager.cpp index 136564d77f..1ba925086e 100644 --- a/stepmania/src/RageTextureManager.cpp +++ b/stepmania/src/RageTextureManager.cpp @@ -27,9 +27,8 @@ RageTextureManager* TEXTUREMAN = NULL; //----------------------------------------------------------------------------- // constructor/destructor //----------------------------------------------------------------------------- -RageTextureManager::RageTextureManager( int iTextureColorDepth, int iSecondsBeforeUnload, int iMaxTextureResolution ) +RageTextureManager::RageTextureManager() { - SetPrefs( iTextureColorDepth, iSecondsBeforeUnload, iMaxTextureResolution ); } RageTextureManager::~RageTextureManager() @@ -103,21 +102,49 @@ RageTexture* RageTextureManager::LoadTexture( RageTextureID ID ) return pTexture; } - -void RageTextureManager::GCTextures() +void RageTextureManager::CacheTexture( RageTextureID ID ) { - /* If m_iSecondsBeforeUnload is 0, then we'll unload textures immediately when - * they're no longer needed, to use as little extra memory as possible, so don't - * bother checking for expired textures here. */ - if(!m_iSecondsBeforeUnload) return; + RageTexture* pTexture = LoadTexture( ID ); + pTexture->m_bCacheThis |= true; + UnloadTexture( pTexture ); +} - static int timeLastGarbageCollect = time(NULL); - if( timeLastGarbageCollect+m_iSecondsBeforeUnload/2 > time(NULL) ) - return; +void RageTextureManager::UnloadTexture( RageTexture *t ) +{ + t->m_iRefCount--; + ASSERT( t->m_iRefCount >= 0 ); + /* Always unload movies, so we don't waste time decoding. + * + * Actually, multiple refs to a movie won't work; they should play independently, + * but they'll actually share settings. Not worth fixing, since we don't currently + * using movies for anything except BGAs (though we could). + */ + if( t->m_iRefCount==0 ) + { + bool bDeleteThis = false; + if( t->IsAMovie() ) + bDeleteThis = true; + if( !m_bDelayedDelete || !t->m_bCacheThis ) + bDeleteThis = true; + + if( bDeleteThis ) + DeleteTexture( t ); + } +} + +void RageTextureManager::DeleteTexture( RageTexture *t ) +{ + ASSERT( t->m_iRefCount==0 ); + LOG->Trace( "RageTextureManager: deleting '%s'.", t->GetID().filename.GetString() ); + m_mapPathToTexture.erase( t->GetID() ); // remove map entry + SAFE_DELETE( t ); // free the texture +} + +void RageTextureManager::GarbageCollect( GCType type ) +{ // Search for old textures with refcount==0 to unload - LOG->Trace("Performing texture garbage collection"); - timeLastGarbageCollect = time(NULL); + LOG->Trace("Performing texture garbage collection."); for( std::map::iterator i = m_mapPathToTexture.begin(); i != m_mapPathToTexture.end(); ) @@ -126,16 +153,25 @@ void RageTextureManager::GCTextures() i++; CString sPath = j->first.filename; - RageTexture* pTexture = j->second; - if( pTexture->m_iRefCount==0 && - pTexture->m_iTimeOfLastUnload+m_iSecondsBeforeUnload < time(NULL) ) + RageTexture* t = j->second; + + if( t->m_iRefCount==0 ) { - SAFE_DELETE( pTexture ); // free the texture - m_mapPathToTexture.erase(j); // and remove the key in the map + bool bDeleteThis = false; + if( type==cached_textures && !m_bDelayedDelete ) + bDeleteThis = true; + if( type==delayed_delete ) + bDeleteThis = true; + + if( bDeleteThis ) + DeleteTexture( t ); } } } +/* + + Redundant. -Chris void RageTextureManager::UnloadTexture( RageTextureID ID ) { @@ -155,31 +191,8 @@ void RageTextureManager::UnloadTexture( RageTextureID ID ) UnloadTexture(p->second); //LOG->Trace( "RageTextureManager: '%s' will not be deleted. It still has %d references.", sTexturePath.GetString(), pTexture->m_iRefCount ); } +*/ -void RageTextureManager::UnloadTexture( RageTexture *t ) -{ - t->m_iRefCount--; - t->m_iTimeOfLastUnload = time(NULL); - ASSERT( t->m_iRefCount >= 0 ); - - /* Always unload movies, so we don't waste time decoding. - * - * Actually, multiple refs to a movie won't work; they should play independently, - * but they'll actually share settings. Not worth fixing, since we don't currently - * using movies for anything except BGAs (though we could). - * - * Also, if texture caching is off, just remove it now instead of doing - * garbage collection. */ - if( t->m_iRefCount == 0 && - (t->IsAMovie() || !m_iSecondsBeforeUnload )) - { - // LOG->Trace( "RageTextureManager: '%s' will be deleted. It has %d references.", sTexturePath.GetString(), pTexture->m_iRefCount ); - m_mapPathToTexture.erase(t->GetID()); // and remove the key in the map - SAFE_DELETE( t ); // free the texture - } - - GCTextures(); -} void RageTextureManager::ReloadAll() { @@ -228,15 +241,15 @@ void RageTextureManager::InvalidateTextures() } } -bool RageTextureManager::SetPrefs( int iTextureColorDepth, int iSecondsBeforeUnload, int iMaxTextureResolution ) +bool RageTextureManager::SetPrefs( int iTextureColorDepth, bool bDelayedDelete, int iMaxTextureResolution ) { bool need_reload = false; - if(m_iSecondsBeforeUnload != iSecondsBeforeUnload || + if( m_bDelayedDelete != bDelayedDelete || m_iTextureColorDepth != iTextureColorDepth || m_iMaxTextureResolution != iMaxTextureResolution ) need_reload = true; - m_iSecondsBeforeUnload = iSecondsBeforeUnload; + m_bDelayedDelete = bDelayedDelete; m_iTextureColorDepth = iTextureColorDepth; m_iMaxTextureResolution = iMaxTextureResolution; diff --git a/stepmania/src/RageTextureManager.h b/stepmania/src/RageTextureManager.h index 4f5a6050fc..28a924246e 100644 --- a/stepmania/src/RageTextureManager.h +++ b/stepmania/src/RageTextureManager.h @@ -21,27 +21,35 @@ class RageTextureManager { public: - RageTextureManager( int iTextureColorDepth, int iSecsBeforeUnload, int iMaxTextureResolution ); + RageTextureManager(); void Update( float fDeltaTime ); ~RageTextureManager(); RageTexture* LoadTexture( RageTextureID ID ); - void UnloadTexture( RageTextureID ID ); + void CacheTexture( RageTextureID ID ); void UnloadTexture( RageTexture *t ); void ReloadAll(); - bool SetPrefs( int iTextureColorDepth, int iSecsBeforeUnload, int iMaxTextureResolution ); + bool SetPrefs( int iTextureColorDepth, bool bDelayedDelete, int iMaxTextureResolution ); int GetTextureColorDepth() { return m_iTextureColorDepth; }; + bool GetDelayedDelete() { return m_bDelayedDelete; }; int GetMaxTextureResolution() { return m_iMaxTextureResolution; }; - int GetSecsBeforeUnload() { return m_iSecondsBeforeUnload; }; + // call this between Screens + void DeleteCachedTextures() { GarbageCollect(cached_textures); } + + // call this on switch theme + void DoDelayedDelete() { GarbageCollect(delayed_delete); } + void InvalidateTextures(); protected: - void GCTextures(); + void DeleteTexture( RageTexture *t ); + enum GCType { cached_textures, delayed_delete }; + void GarbageCollect( GCType type ); int m_iTextureColorDepth; - int m_iSecondsBeforeUnload; + bool m_bDelayedDelete; int m_iMaxTextureResolution; std::map m_mapPathToTexture; diff --git a/stepmania/src/ScreenAppearanceOptions.cpp b/stepmania/src/ScreenAppearanceOptions.cpp index 19f9357160..3334641276 100644 --- a/stepmania/src/ScreenAppearanceOptions.cpp +++ b/stepmania/src/ScreenAppearanceOptions.cpp @@ -157,6 +157,7 @@ void ScreenAppearanceOptions::ExportOptions() int iSelectedTheme = m_iSelectedOption[0][AO_THEME]; CString sNewTheme = m_OptionRow[AO_THEME].choices[iSelectedTheme]; THEME->SwitchTheme( sNewTheme ); + TEXTUREMAN->DoDelayedDelete(); // delete all textures that don't have references int iSelectedSkin = m_iSelectedOption[0][AO_SKIN]; CString sNewSkin = m_OptionRow[AO_SKIN].choices[iSelectedSkin]; diff --git a/stepmania/src/ScreenGraphicOptions.cpp b/stepmania/src/ScreenGraphicOptions.cpp index 67da6be4fa..209f0d9e0b 100644 --- a/stepmania/src/ScreenGraphicOptions.cpp +++ b/stepmania/src/ScreenGraphicOptions.cpp @@ -109,7 +109,7 @@ void ScreenGraphicOptions::ImportOptions() case 32: m_iSelectedOption[0][GO_TEXTURE_COLOR_DEPTH] = 1; break; } - m_iSelectedOption[0][GO_KEEP_TEXTURES_IN_MEM] = PREFSMAN->m_iUnloadTextureDelaySeconds>0 ? 1:0; + m_iSelectedOption[0][GO_KEEP_TEXTURES_IN_MEM] = PREFSMAN->m_bDelayedTextureDelete ? 1:0; switch(PREFSMAN->m_iRefreshRate) { @@ -153,7 +153,7 @@ void ScreenGraphicOptions::ExportOptions() default: ASSERT(0); PREFSMAN->m_iTextureColorDepth = 16; break; } - PREFSMAN->m_iUnloadTextureDelaySeconds = (m_iSelectedOption[0][GO_KEEP_TEXTURES_IN_MEM] == 1) ? 1200 : 0; // 20 mins + PREFSMAN->m_bDelayedTextureDelete = (m_iSelectedOption[0][GO_KEEP_TEXTURES_IN_MEM] == 1); if(m_iSelectedOption[0][GO_REFRESH_RATE] == 0) PREFSMAN->m_iRefreshRate = REFRESH_DEFAULT; diff --git a/stepmania/src/ScreenManager.cpp b/stepmania/src/ScreenManager.cpp index 1656902502..d941beb76c 100644 --- a/stepmania/src/ScreenManager.cpp +++ b/stepmania/src/ScreenManager.cpp @@ -24,9 +24,9 @@ #include "RageDisplay.h" #include "Screen.h" #include "SongManager.h" - #include "BitmapText.h" #include "Quad.h" +#include "RageTextureManager.h" ScreenManager* SCREENMAN = NULL; // global and accessable from anywhere in our program @@ -370,6 +370,8 @@ void ScreenManager::Input( const DeviceInput& DeviceI, const InputEventType type Screen* ScreenManager::MakeNewScreen( CString sClassName ) { + TEXTUREMAN->DeleteCachedTextures(); + Screen *ret = Screen::Create( sClassName ); /* Loading probably took a little while. Let's reset stats. This prevents us diff --git a/stepmania/src/ScreenTitleMenu.cpp b/stepmania/src/ScreenTitleMenu.cpp index 5b30a2b4ba..25c956ff4b 100644 --- a/stepmania/src/ScreenTitleMenu.cpp +++ b/stepmania/src/ScreenTitleMenu.cpp @@ -27,6 +27,7 @@ #include "SDL_utils.h" #include "RageSoundManager.h" #include "CodeDetector.h" +#include "RageTextureManager.h" #define LOGO_ON_COMMAND THEME->GetMetric("ScreenTitleMenu","LogoOnCommand") @@ -240,6 +241,7 @@ void ScreenTitleMenu::Input( const DeviceInput& DeviceI, const InputEventType ty THEME->NextTheme(); SCREENMAN->SystemMessage( "Theme: "+THEME->GetCurThemeName() ); SCREENMAN->SetNewScreen( "ScreenTitleMenu" ); + TEXTUREMAN->DoDelayedDelete(); } if( CodeDetector::EnteredCode(GameI.controller,CodeDetector::CODE_NEXT_ANNOUNCER) ) { diff --git a/stepmania/src/StepMania.cpp b/stepmania/src/StepMania.cpp index 7f94401f76..a52b5056b1 100644 --- a/stepmania/src/StepMania.cpp +++ b/stepmania/src/StepMania.cpp @@ -98,7 +98,7 @@ void ApplyGraphicOptions() bNeedReload |= TEXTUREMAN->SetPrefs( PREFSMAN->m_iTextureColorDepth, - PREFSMAN->m_iUnloadTextureDelaySeconds, + PREFSMAN->m_bDelayedTextureDelete, PREFSMAN->m_iMaxTextureResolution ); if( bNeedReload ) @@ -133,6 +133,7 @@ void ResetGame() THEME->SwitchTheme( sGameName ); else THEME->SwitchTheme( "default" ); + TEXTUREMAN->DoDelayedDelete(); } PREFSMAN->SaveGamePrefsToDisk(); @@ -297,7 +298,11 @@ int main(int argc, char* argv[]) PREFSMAN->m_iDisplayColorDepth, PREFSMAN->m_iRefreshRate, PREFSMAN->m_bVsync ); - TEXTUREMAN = new RageTextureManager( PREFSMAN->m_iTextureColorDepth, PREFSMAN->m_iUnloadTextureDelaySeconds, PREFSMAN->m_iMaxTextureResolution ); + TEXTUREMAN = new RageTextureManager(); + TEXTUREMAN->SetPrefs( + PREFSMAN->m_iTextureColorDepth, + PREFSMAN->m_bDelayedTextureDelete, + PREFSMAN->m_iMaxTextureResolution ); /* Now that we've started DISPLAY, we can set up event masks. */ SDL_EventState(SDL_QUIT, SDL_ENABLE);