From 68a82faa6ab06e7242867c7a7c09d094570e1328 Mon Sep 17 00:00:00 2001 From: Chris Danford Date: Thu, 26 May 2005 09:35:57 +0000 Subject: [PATCH] add multiple background layers --- stepmania/src/Background.cpp | 182 +++++++++++++++++++------------- stepmania/src/Background.h | 37 ++++--- stepmania/src/NoteField.cpp | 30 +++--- stepmania/src/NotesLoaderSM.cpp | 105 ++++++++++-------- stepmania/src/NotesWriterSM.cpp | 33 +++--- stepmania/src/ScreenEdit.cpp | 24 +++-- stepmania/src/ScreenEdit.h | 1 + stepmania/src/Song.cpp | 27 +++-- stepmania/src/SongManager.cpp | 7 +- stepmania/src/song.h | 11 +- 10 files changed, 275 insertions(+), 182 deletions(-) diff --git a/stepmania/src/Background.cpp b/stepmania/src/Background.cpp index ac0d491550..4d1c04fc90 100644 --- a/stepmania/src/Background.cpp +++ b/stepmania/src/Background.cpp @@ -53,13 +53,17 @@ static RageColor GetBrightnessColor( float fBrightnessPercent ) } Background::Background() +{ + m_pDancingCharacters = NULL; + m_bInitted = false; +} + +Background::Layer::Layer() { m_iCurBGChangeIndex = -1; m_pCurrentBGA = NULL; m_pFadingBGA = NULL; m_fSecsLeftInFade = 0; - m_pDancingCharacters = NULL; - m_bInitted = false; } void Background::Init() @@ -114,6 +118,14 @@ Background::~Background() } void Background::Unload() +{ + for( int i=0; i::iterator iter = m_BGAnimations.begin(); iter != m_BGAnimations.end(); @@ -125,10 +137,8 @@ void Background::Unload() m_pCurrentBGA = NULL; m_pFadingBGA = NULL; - m_pSong = NULL; m_fSecsLeftInFade = 0; m_iCurBGChangeIndex = -1; - m_fLastMusicSeconds = -9999; } Actor *MakeVisualization( const CString &sVisPath ) @@ -163,7 +173,7 @@ Actor *MakeMovie( const CString &sMoviePath ) return pSprite; } -Actor *Background::CreateSongBGA( CString sBGName ) const +Actor *Background::Layer::CreateSongBGA( const Song *pSong, CString sBGName ) const { BGAnimation *pTempBGA; @@ -173,7 +183,7 @@ Actor *Background::CreateSongBGA( CString sBGName ) const CStringArray asFiles; // Look for BGAnims in the song dir - GetDirListing( m_pSong->GetSongDir()+sBGName, asFiles, true, true ); + GetDirListing( pSong->GetSongDir()+sBGName, asFiles, true, true ); if( !asFiles.empty() ) { /* If default.xml exists, use the regular generic actor load. However, @@ -187,7 +197,7 @@ Actor *Background::CreateSongBGA( CString sBGName ) const return pTempBGA; } // Look for BG movies or static graphics in the song dir - GetDirListing( m_pSong->GetSongDir()+sBGName, asFiles, false, true ); + GetDirListing( pSong->GetSongDir()+sBGName, asFiles, false, true ); if( !asFiles.empty() ) { const CString sExt = GetExtension( asFiles[0]) ; @@ -214,9 +224,9 @@ Actor *Background::CreateSongBGA( CString sBGName ) const GetDirListing( BG_ANIMS_DIR+sBGName, asFiles, true, true ); if( !asFiles.empty() ) { - pTempBGA = new BGAnimation; - pTempBGA->LoadFromAniDir( asFiles[0] ); - return pTempBGA; + Actor *pActor = ActorUtil::MakeActor( asFiles[0] ); + ASSERT( pActor ); + return pActor; } // Look for BGAnims in the BGAnims dir @@ -228,7 +238,7 @@ Actor *Background::CreateSongBGA( CString sBGName ) const return NULL; } -CString Background::CreateRandomBGA( CString sPreferredSubDir ) +CString Background::Layer::CreateRandomBGA( const Song *pSong, CString sPreferredSubDir ) { if( sPreferredSubDir.Right(1) != "/" ) sPreferredSubDir += '/'; @@ -338,9 +348,9 @@ void Background::LoadFromRandom( float fFirstBeat, float fLastBeat, const Timing //bool bFade = PREFSMAN->m_BackgroundMode==PrefsManager::BGMODE_RANDOMMOVIES || // PREFSMAN->m_BackgroundMode==PrefsManager::BGMODE_MOVIEVIS; - CString sBGName = CreateRandomBGA( sPreferredSubDir ); + CString sBGName = m_Layer[0].CreateRandomBGA( m_pSong, sPreferredSubDir ); if( sBGName != "" ) - m_aBGChanges.push_back( BackgroundChange(f,sBGName,1.f,bFade) ); + m_Layer[0].m_aBGChanges.push_back( BackgroundChange(f,sBGName,1.f,bFade) ); } // change BG every BPM change that is at the beginning of a measure @@ -356,9 +366,9 @@ void Background::LoadFromRandom( float fFirstBeat, float fLastBeat, const Timing if( bpmseg.m_iStartIndex < iStartIndex || bpmseg.m_iStartIndex > iEndIndex ) continue; // skip - CString sBGName = CreateRandomBGA( sPreferredSubDir ); + CString sBGName = m_Layer[0].CreateRandomBGA( m_pSong, sPreferredSubDir ); if( sBGName != "" ) - m_aBGChanges.push_back( BackgroundChange(NoteRowToBeat(bpmseg.m_iStartIndex),sBGName) ); + m_Layer[0].m_aBGChanges.push_back( BackgroundChange(NoteRowToBeat(bpmseg.m_iStartIndex),sBGName) ); } } @@ -387,53 +397,68 @@ void Background::LoadFromSong( const Song* pSong ) if( pSong->HasBGChanges() ) { - // Load all song-specified backgrounds - for( unsigned i=0; im_BackgroundChanges.size(); i++ ) + for( int i=0; im_BackgroundChanges[i]; - CString &sBGName = change.m_sBGName; - - bool bIsAlreadyLoaded = m_BGAnimations.find(sBGName) != m_BGAnimations.end(); + Layer &layer = m_Layer[i]; - if( sBGName.CompareNoCase("-random-")!=0 && !bIsAlreadyLoaded ) + // Load all song-specified backgrounds + FOREACH_CONST( BackgroundChange, pSong->m_BackgroundChanges[i], bgc ) { - Actor *pTempBGA = CreateSongBGA( sBGName ); - if( pTempBGA ) + BackgroundChange change = *bgc; + CString &sBGName = change.m_sBGName; + + bool bIsAlreadyLoaded = layer.m_BGAnimations.find(sBGName) != layer.m_BGAnimations.end(); + + if( sBGName.CompareNoCase("-random-")!=0 && !bIsAlreadyLoaded ) { - m_BGAnimations[sBGName] = pTempBGA; - } - else // the background was not found. Use a random one instead - { - sBGName = CreateRandomBGA( pSong->m_sGroupName ); - if( sBGName == "" ) - sBGName = STATIC_BACKGROUND; + Actor *pTempBGA = layer.CreateSongBGA( m_pSong, sBGName ); + if( pTempBGA ) + { + layer.m_BGAnimations[sBGName] = pTempBGA; + } + else // the background was not found. Use a random one instead + { + sBGName = layer.CreateRandomBGA( pSong, pSong->m_sGroupName ); + if( sBGName == "" ) + sBGName = STATIC_BACKGROUND; + } } + + layer.m_aBGChanges.push_back( change ); } - - m_aBGChanges.push_back( change ); } } else // pSong doesn't have an animation plan { + Layer &layer = m_Layer[0]; + LoadFromRandom( pSong->m_fFirstBeat, pSong->m_fLastBeat, pSong->m_Timing, pSong->m_sGroupName ); // end showing the static song background - m_aBGChanges.push_back( BackgroundChange(pSong->m_fLastBeat,STATIC_BACKGROUND) ); + layer.m_aBGChanges.push_back( BackgroundChange(pSong->m_fLastBeat,STATIC_BACKGROUND) ); } // sort segments - SortBackgroundChangesArray( m_aBGChanges ); + for( int i=0; i= 0 ) - m_aBGChanges.insert( m_aBGChanges.begin(), BackgroundChange(-10000,STATIC_BACKGROUND) ); + if( mainlayer.m_aBGChanges.empty() || mainlayer.m_aBGChanges.front().m_fStartBeat >= 0 ) + mainlayer.m_aBGChanges.insert( mainlayer.m_aBGChanges.begin(), BackgroundChange(-10000,STATIC_BACKGROUND) ); // If any BGChanges use the background image, load it. bool bStaticBackgroundUsed = false; - for( unsigned i=0; iLoadBG( sSongBGPath ); pSprite->StretchTo( FullScreenRectF ); - m_BGAnimations[STATIC_BACKGROUND] = pSprite; + mainlayer.m_BGAnimations[STATIC_BACKGROUND] = pSprite; } // Look for the filename "Random", and replace the segment with LoadFromRandom. - for( unsigned i=0; im_Timing, pSong->m_sGroupName ); } // At this point, we shouldn't have any BGChanges to "". "" is an invalid name. - for( unsigned i=0; i::iterator it; - for( it = m_BGAnimations.begin(); it != m_BGAnimations.end(); ++it ) + for( it = mainlayer.m_BGAnimations.begin(); it != mainlayer.m_BGAnimations.end(); ++it ) { Actor *pBGA = it->second; @@ -514,7 +539,7 @@ void Background::LoadFromSong( const Song* pSong ) } } -int Background::FindBGSegmentForBeat( float fBeat ) const +int Background::Layer::FindBGSegmentForBeat( float fBeat ) const { if( m_aBGChanges.empty() ) return -1; @@ -533,7 +558,7 @@ int Background::FindBGSegmentForBeat( float fBeat ) const } /* If the BG segment has changed, move focus to it. Send Update() calls. */ -void Background::UpdateCurBGChange( float fCurrentTime ) +void Background::Layer::UpdateCurBGChange( const Song *pSong, float fLastMusicSeconds, float fCurrentTime ) { ASSERT( fCurrentTime != GameState::MUSIC_SECONDS_INVALID ); @@ -542,7 +567,7 @@ void Background::UpdateCurBGChange( float fCurrentTime ) float fBeat, fBPS; bool bFreeze; - m_pSong->m_Timing.GetBeatAndBPSFromElapsedTime( fCurrentTime, fBeat, fBPS, bFreeze ); + pSong->m_Timing.GetBeatAndBPSFromElapsedTime( fCurrentTime, fBeat, fBPS, bFreeze ); /* Calls to Update() should *not* be scaled by music rate; fCurrentTime is. Undo it. */ const float fRate = GAMESTATE->m_SongOptions.m_fMusicRate; @@ -582,7 +607,7 @@ void Background::UpdateCurBGChange( float fCurrentTime ) m_fSecsLeftInFade = m_pFadingBGA!=NULL ? FADE_SECONDS : 0; /* How much time of this BGA have we skipped? (This happens with SetSeconds.) */ - const float fStartSecond = m_pSong->m_Timing.GetElapsedTimeFromBeat( change.m_fStartBeat ); + const float fStartSecond = pSong->m_Timing.GetElapsedTimeFromBeat( change.m_fStartBeat ); /* This is affected by the music rate. */ float fDeltaTime = fCurrentTime - fStartSecond; @@ -593,17 +618,16 @@ void Background::UpdateCurBGChange( float fCurrentTime ) else // we're not changing backgrounds { /* This is affected by the music rate. */ - float fDeltaTime = fCurrentTime - m_fLastMusicSeconds; + float fDeltaTime = fCurrentTime - fLastMusicSeconds; fDeltaTime /= fRate; if( m_pCurrentBGA ) m_pCurrentBGA->Update( max( fDeltaTime, 0 ) ); } - float fDeltaTime = fCurrentTime - m_fLastMusicSeconds; + float fDeltaTime = fCurrentTime - fLastMusicSeconds; fDeltaTime /= fRate; if( m_pFadingBGA ) - m_pFadingBGA->Update( max( fCurrentTime - m_fLastMusicSeconds, 0 ) ); - m_fLastMusicSeconds = fCurrentTime; + m_pFadingBGA->Update( max( fCurrentTime - fLastMusicSeconds, 0 ) ); } void Background::Update( float fDeltaTime ) @@ -624,28 +648,33 @@ void Background::Update( float fDeltaTime ) m_DeadPlayer[p].Update( fDeltaTime ); } + if( m_pDancingCharacters ) + m_pDancingCharacters->Update( fDeltaTime ); + /* Always update the current background, even when m_DangerAll is being displayed. * Otherwise, we'll stop updating movies during danger (which may stop them from * playing), and we won't start clips at the right time, which will throw backgrounds * off sync. */ - UpdateCurBGChange( GAMESTATE->m_fMusicSeconds ); - - if( m_pFadingBGA ) + for( int i=0; iUpdate( fDeltaTime ); - m_fSecsLeftInFade -= fDeltaTime; - float fPercentOpaque = m_fSecsLeftInFade / FADE_SECONDS; - m_pFadingBGA->SetDiffuse( RageColor(1,1,1,fPercentOpaque) ); - if( fPercentOpaque <= 0 ) + Layer &layer = m_Layer[i]; + layer.UpdateCurBGChange( m_pSong, m_fLastMusicSeconds, GAMESTATE->m_fMusicSeconds ); + + if( layer.m_pFadingBGA ) { - /* Reset its diffuse color, in case we reuse it. */ - m_pFadingBGA->SetDiffuse( RageColor(1,1,1,1) ); - m_pFadingBGA = NULL; + layer.m_pFadingBGA->Update( fDeltaTime ); + layer.m_fSecsLeftInFade -= fDeltaTime; + float fPercentOpaque = layer.m_fSecsLeftInFade / FADE_SECONDS; + layer.m_pFadingBGA->SetDiffuse( RageColor(1,1,1,fPercentOpaque) ); + if( fPercentOpaque <= 0 ) + { + /* Reset its diffuse color, in case we reuse it. */ + layer.m_pFadingBGA->SetDiffuse( RageColor(1,1,1,1) ); + layer.m_pFadingBGA = NULL; + } } } - - if( m_pDancingCharacters ) - m_pDancingCharacters->Update( fDeltaTime ); + m_fLastMusicSeconds = GAMESTATE->m_fMusicSeconds; } void Background::DrawPrimitives() @@ -665,10 +694,15 @@ void Background::DrawPrimitives() { if( m_pDancingCharacters ) m_pDancingCharacters->m_bDrawDangerLight = false; - if( m_pCurrentBGA ) - m_pCurrentBGA->Draw(); - if( m_pFadingBGA ) - m_pFadingBGA->Draw(); + + for( int i=0; iDraw(); + if( layer.m_pFadingBGA ) + layer.m_pFadingBGA->Draw(); + } FOREACH_PlayerNumber( p ) { diff --git a/stepmania/src/Background.h b/stepmania/src/Background.h index 0d0aedef58..a1018a7bd0 100644 --- a/stepmania/src/Background.h +++ b/stepmania/src/Background.h @@ -49,30 +49,39 @@ public: protected: const Song *m_pSong; void LoadFromRandom( float fFirstBeat, float fLastBeat, const TimingData &timing, CString sPreferredSubDir ); - int FindBGSegmentForBeat( float fBeat ) const; bool IsDangerAllVisible(); - void UpdateCurBGChange( float fCurrentTime ); bool m_bInitted; DancingCharacters* m_pDancingCharacters; + class Layer + { + public: + Layer(); + void Unload(); + + Actor *CreateSongBGA( const Song *pSong, CString sBGName ) const; + CString CreateRandomBGA( const Song *pSong, CString sPreferredSubDir ); + int FindBGSegmentForBeat( float fBeat ) const; + void UpdateCurBGChange( const Song *pSong, float fLastMusicSeconds, float fCurrentTime ); + + map m_BGAnimations; + deque m_RandomBGAnimations; + vector m_aBGChanges; + int m_iCurBGChangeIndex; + Actor *m_pCurrentBGA; + Actor *m_pFadingBGA; + float m_fSecsLeftInFade; + }; + Layer m_Layer[NUM_BACKGROUND_LAYERS]; + + float m_fLastMusicSeconds; + BGAnimation m_DangerPlayer[NUM_PLAYERS]; BGAnimation m_DangerAll; BGAnimation m_DeadPlayer[NUM_PLAYERS]; - - Actor *CreateSongBGA( CString sBGName ) const; - CString CreateRandomBGA( CString sPreferredSubDir ); - - map m_BGAnimations; - deque m_RandomBGAnimations; - vector m_aBGChanges; - int m_iCurBGChangeIndex; - Actor *m_pCurrentBGA; - Actor *m_pFadingBGA; - float m_fSecsLeftInFade; - float m_fLastMusicSeconds; // cover up the edge of animations that might hang outside of the background rectangle Quad m_quadBorderLeft, m_quadBorderTop, m_quadBorderRight, m_quadBorderBottom; diff --git a/stepmania/src/NoteField.cpp b/stepmania/src/NoteField.cpp index 8e4a1ae99d..529ef7aabe 100644 --- a/stepmania/src/NoteField.cpp +++ b/stepmania/src/NoteField.cpp @@ -531,22 +531,26 @@ void NoteField::DrawPrimitives() break; case EDIT_MODE_FULL: { - vector &aBackgroundChanges = GAMESTATE->m_pCurSong->m_BackgroundChanges; - for( unsigned i=0; i= fFirstBeatToDraw && - aBackgroundChanges[i].m_fStartBeat <= fLastBeatToDraw) + vector &aBackgroundChanges = GAMESTATE->m_pCurSong->m_BackgroundChanges[b]; + for( unsigned i=0; i= fFirstBeatToDraw && + aBackgroundChanges[i].m_fStartBeat <= fLastBeatToDraw ) + { + const BackgroundChange& change = aBackgroundChanges[i]; + CString sChangeText = ssprintf("%s%s\n%.0f%%%s%s%s", + ((b!=0) ? ssprintf("%d:",b) : CString()).c_str(), + change.m_sBGName.c_str(), + change.m_fRate*100, + change.m_bFadeLast ? " Fade" : "", + change.m_bRewindMovie ? " Rewind" : "", + change.m_bLoop ? " Loop" : "" ); - if( IS_ON_SCREEN(change.m_fStartBeat) ) - DrawBGChangeText( change.m_fStartBeat, sChangeText ); + if( IS_ON_SCREEN(change.m_fStartBeat) ) + DrawBGChangeText( change.m_fStartBeat, sChangeText ); + } } } } diff --git a/stepmania/src/NotesLoaderSM.cpp b/stepmania/src/NotesLoaderSM.cpp index b5b120050a..35de229810 100644 --- a/stepmania/src/NotesLoaderSM.cpp +++ b/stepmania/src/NotesLoaderSM.cpp @@ -87,11 +87,14 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out ) for( unsigned i=0; iTrace("Ignored #LASTBEAT (cache only)"); out.m_fLastBeat = strtof( sParams[1], NULL ); } - else if( 0==stricmp(sValueName,"SONGFILENAME") ) + else if( sValueName=="SONGFILENAME" ) { if( FromCache ) out.m_sSongFileName = sParams[1]; } - else if( 0==stricmp(sValueName,"HASMUSIC") ) + else if( sValueName=="HASMUSIC" ) { if( FromCache ) out.m_bHasMusic = atoi( sParams[1] ) != 0; } - else if( 0==stricmp(sValueName,"HASBANNER") ) + else if( sValueName=="HASBANNER" ) { if( FromCache ) out.m_bHasBanner = atoi( sParams[1] ) != 0; } - else if( 0==stricmp(sValueName,"SAMPLESTART") ) + else if( sValueName=="SAMPLESTART" ) out.m_fMusicSampleStartSeconds = HHMMSSToSeconds( sParams[1] ); - else if( 0==stricmp(sValueName,"SAMPLELENGTH") ) + else if( sValueName=="SAMPLELENGTH" ) out.m_fMusicSampleLengthSeconds = HHMMSSToSeconds( sParams[1] ); - else if( 0==stricmp(sValueName,"DISPLAYBPM") ) + else if( sValueName=="DISPLAYBPM" ) { // #DISPLAYBPM:[xxx][xxx:xxx]|[*]; if( sParams[1] == "*" ) @@ -302,7 +306,7 @@ bool SMLoader::LoadFromSMFile( CString sPath, Song &out ) } } - else if( 0==stricmp(sValueName,"SELECTABLE") ) + else if( sValueName=="SELECTABLE" ) { if(!stricmp(sParams[1],"YES")) out.m_SelectionDisplay = out.SHOW_ALWAYS; @@ -314,20 +318,30 @@ bool SMLoader::LoadFromSMFile( CString sPath, Song &out ) LOG->Warn( "The song file '%s' has an unknown #SELECTABLE value, '%s'; ignored.", sPath.c_str(), sParams[1].c_str()); } - else if( 0==stricmp(sValueName,"BGCHANGES") || 0==stricmp(sValueName,"ANIMATIONS") ) + else if( sValueName=="BGCHANGES" || sValueName=="ANIMATIONS" ) { - CStringArray aBGChangeExpressions; - split( sParams[1], ",", aBGChangeExpressions ); + int iLayer = 0; + sscanf( sValueName, "BGCHANGES%d", &iLayer ); - for( unsigned b=0; b= NUM_BACKGROUND_LAYERS ) { - BackgroundChange change; - if( LoadFromBGChangesString( change, aBGChangeExpressions[b] ) ) - out.AddBackgroundChange( change ); + LOG->Warn( "The song file '%s' has a BGCHANGES tag '%s' that is out of range.", sPath.c_str(), sValueName.c_str() ); + } + else + { + CStringArray aBGChangeExpressions; + split( sParams[1], ",", aBGChangeExpressions ); + + for( unsigned b=0; bTrace( "Unexpected value named '%s'", sValueName.c_str() ); @@ -436,10 +450,11 @@ bool SMLoader::LoadEditFromMsd( const MsdFile &msd, CString sEditFilePath, Profi { int iNumParams = msd.GetNumParams(i); const MsdFile::value_t &sParams = msd.GetValue(i); - const CString sValueName = sParams[0]; + CString sValueName = sParams[0]; + sValueName.MakeUpper(); // handle the data - if( 0==stricmp(sValueName,"SONG") ) + if( sValueName=="SONG" ) { if( pSong ) { @@ -464,7 +479,7 @@ bool SMLoader::LoadEditFromMsd( const MsdFile &msd, CString sEditFilePath, Profi } } - else if( 0==stricmp(sValueName,"NOTES") ) + else if( sValueName=="NOTES" ) { if( pSong == NULL ) { @@ -519,7 +534,7 @@ void SMLoader::TidyUpData( Song &song, bool cache ) * have to add an explicit song BG tag if they want it. This is really a * formatting hack only; nothing outside of SMLoader ever sees "-nosongbg-". */ - vector &bg = song.m_BackgroundChanges; + vector &bg = song.m_BackgroundChanges[0]; if( !bg.empty() ) { /* BGChanges have been sorted. On the odd chance that a BGChange exists diff --git a/stepmania/src/NotesWriterSM.cpp b/stepmania/src/NotesWriterSM.cpp index 030abec19a..bb83d195d9 100644 --- a/stepmania/src/NotesWriterSM.cpp +++ b/stepmania/src/NotesWriterSM.cpp @@ -10,6 +10,7 @@ #include "NoteTypes.h" #include #include +#include "Foreach.h" void NotesWriterSM::WriteGlobalTags( RageFile &f, const Song &out ) { @@ -80,21 +81,27 @@ void NotesWriterSM::WriteGlobalTags( RageFile &f, const Song &out ) f.Write( "," ); } f.PutLine( ";" ); - - f.Write( "#BGCHANGES:" ); - for( unsigned i=0; im_fStartBeat, bgc->m_sBGName.c_str(), bgc->m_fRate, bgc->m_bFadeLast, bgc->m_bRewindMovie, bgc->m_bLoop ) ); + + /* If there's an animation plan at all, add a dummy "-nosongbg-" tag to indicate that + * this file doesn't want a song BG entry added at the end. See SMLoader::TidyUpData. + * This tag will be removed on load. Add it at a very high beat, so it won't cause + * problems if loaded in older versions. */ + if( b==0 && !out.m_BackgroundChanges[b].empty() ) + f.PutLine( "99999=-nosongbg-=1.000=0=0=0 // don't automatically add -songbackground-" ); + f.PutLine( ";" ); } - /* If there's an animation plan at all, add a dummy "-nosongbg-" tag to indicate that - * this file doesn't want a song BG entry added at the end. See SMLoader::TidyUpData. - * This tag will be removed on load. Add it at a very high beat, so it won't cause - * problems if loaded in older versions. */ - if( !out.m_BackgroundChanges.empty() ) - f.PutLine( "99999=-nosongbg-=1.000=0=0=0 // don't automatically add -songbackground-" ); - f.PutLine( ";" ); if( out.m_ForegroundChanges.size() ) { diff --git a/stepmania/src/ScreenEdit.cpp b/stepmania/src/ScreenEdit.cpp index d90f2d3d1a..2f17c015a8 100644 --- a/stepmania/src/ScreenEdit.cpp +++ b/stepmania/src/ScreenEdit.cpp @@ -441,6 +441,7 @@ static Menu g_SongInformation( static Menu g_BackgroundChange( "ScreenMiniMenuBackgroundChange", + MenuRow( ScreenEdit::layer, "Layer (applies to new adds)", true, EDIT_MODE_PRACTICE, 0, "0","1" ), MenuRow( ScreenEdit::rate, "Rate (applies to new adds)", true, EDIT_MODE_PRACTICE, 10, "0%","10%","20%","30%","40%","50%","60%","70%","80%","90%","100%","120%","140%","160%","180%","200%" ), MenuRow( ScreenEdit::fade_last, "Fade Last (applies to new adds)", true, EDIT_MODE_PRACTICE, 0, "NO","YES" ), MenuRow( ScreenEdit::rewind_movie, "Rewind Movie (applies to new adds)", true, EDIT_MODE_PRACTICE, 0, "NO","YES" ), @@ -2073,16 +2074,21 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector &iAns // - // Fill in line enabled/disabled + // Fill in line's enabled/disabled // bool bAlreadyBGChangeHere = false; + int iLayer = 0; BackgroundChange bgChange; - FOREACH( BackgroundChange, m_pSong->m_BackgroundChanges, bgc ) + for( int l=0; lm_fStartBeat == GAMESTATE->m_fSongBeat ) + FOREACH( BackgroundChange, m_pSong->m_BackgroundChanges[l], bgc ) { - bAlreadyBGChangeHere = true; - bgChange = *bgc; + if( bgc->m_fStartBeat == GAMESTATE->m_fSongBeat ) + { + bAlreadyBGChangeHere = true; + iLayer = l; + bgChange = *bgc; + } } } @@ -2097,6 +2103,7 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector &iAns // set default choices + g_BackgroundChange.rows[layer]. SetDefaultChoiceIfPresent( ssprintf("%d",iLayer) ); g_BackgroundChange.rows[rate]. SetDefaultChoiceIfPresent( ssprintf("%2.0f%%",bgChange.m_fRate*100) ); g_BackgroundChange.rows[fade_last].iDefaultChoice = bgChange.m_bFadeLast ? 1 : 0; g_BackgroundChange.rows[rewind_movie].iDefaultChoice = bgChange.m_bRewindMovie ? 1 : 0; @@ -2618,15 +2625,16 @@ void ScreenEdit::HandleSongInformationChoice( SongInformationChoice c, const vec void ScreenEdit::HandleBGChangeChoice( BGChangeChoice c, const vector &iAnswers ) { + int iLayer = atoi( g_BackgroundChange.rows[layer].choices[iAnswers[layer]] ); BackgroundChange newChange; - FOREACH( BackgroundChange, m_pSong->m_BackgroundChanges, iter ) + FOREACH( BackgroundChange, m_pSong->m_BackgroundChanges[iLayer], iter ) { if( iter->m_fStartBeat == GAMESTATE->m_fSongBeat ) { newChange = *iter; // delete the old change. We'll add a new one below. - m_pSong->m_BackgroundChanges.erase( iter ); + m_pSong->m_BackgroundChanges[iLayer].erase( iter ); break; } } @@ -2659,7 +2667,7 @@ void ScreenEdit::HandleBGChangeChoice( BGChangeChoice c, const vector &iAns newChange.m_bLoop = !!iAnswers[loop]; if( newChange.m_sBGName != "" ) - m_pSong->AddBackgroundChange( newChange ); + m_pSong->AddBackgroundChange( iLayer, newChange ); } void ScreenEdit::SetupCourseAttacks() diff --git a/stepmania/src/ScreenEdit.h b/stepmania/src/ScreenEdit.h index 74a495e90d..92b4f8226d 100644 --- a/stepmania/src/ScreenEdit.h +++ b/stepmania/src/ScreenEdit.h @@ -364,6 +364,7 @@ public: void HandleSongInformationChoice( SongInformationChoice c, const vector &iAnswers ); enum BGChangeChoice { + layer, rate, fade_last, rewind_movie, diff --git a/stepmania/src/Song.cpp b/stepmania/src/Song.cpp index c3439694e0..cb0417b4f6 100644 --- a/stepmania/src/Song.cpp +++ b/stepmania/src/Song.cpp @@ -110,10 +110,11 @@ void Song::Reset() } -void Song::AddBackgroundChange( BackgroundChange seg ) +void Song::AddBackgroundChange( int iLayer, BackgroundChange seg ) { - m_BackgroundChanges.push_back( seg ); - SortBackgroundChangesArray( m_BackgroundChanges ); + ASSERT( iLayer >= 0 && iLayer < NUM_BACKGROUND_LAYERS ); + m_BackgroundChanges[iLayer].push_back( seg ); + SortBackgroundChangesArray( m_BackgroundChanges[iLayer] ); } void Song::AddForegroundChange( BackgroundChange seg ) @@ -143,13 +144,13 @@ void Song::GetDisplayBpms( DisplayBpms &AddTo ) const } } -CString Song::GetBackgroundAtBeat( float fBeat ) const +CString Song::GetBackgroundAtBeat( int iLayer, float fBeat ) const { unsigned i; - for( i=0; i fBeat ) + for( i=0; i fBeat ) break; - return m_BackgroundChanges[i].m_sBGName; + return m_BackgroundChanges[iLayer][i].m_sBGName; } @@ -720,7 +721,7 @@ void Song::TidyUpData() /* Use this->GetBeatFromElapsedTime(0) instead of 0 to start when the * music starts. */ if( arrayPossibleMovies.size() == 1 ) - this->AddBackgroundChange( BackgroundChange(0,arrayPossibleMovies[0],1.f,true,true,false) ); + this->AddBackgroundChange( 0, BackgroundChange(0,arrayPossibleMovies[0],1.f,true,true,false) ); } @@ -1209,7 +1210,15 @@ bool Song::HasBanner() const {return m_sBannerFile != "" && IsAFile(GetBann bool Song::HasLyrics() const {return m_sLyricsFile != "" && IsAFile(GetLyricsPath()); } bool Song::HasBackground() const {return m_sBackgroundFile != "" && IsAFile(GetBackgroundPath()); } bool Song::HasCDTitle() const {return m_sCDTitleFile != "" && IsAFile(GetCDTitlePath()); } -bool Song::HasBGChanges() const {return !m_BackgroundChanges.empty(); } +bool Song::HasBGChanges() const +{ + for( unsigned i=0; iLoadFromSongDir( sSymDestination ) ) + { delete pNewSong; // The song failed to load. + } else { const vector& vpSteps = pNewSong->GetAllSteps(); while( vpSteps.size() ) pNewSong->RemoveSteps( vpSteps[0] ); - pNewSong->m_BackgroundChanges.clear(); + for( int i=0; im_BackgroundChanges[i].clear(); pNewSong->m_bIsSymLink = true; // Very important so we don't double-parse later pNewSong->m_sGroupName = sGroupFolder; diff --git a/stepmania/src/song.h b/stepmania/src/song.h index 2e24966365..c5e9bdc436 100644 --- a/stepmania/src/song.h +++ b/stepmania/src/song.h @@ -17,11 +17,12 @@ class Profile; class StepsID; struct lua_State; -#define MAX_EDITS_PER_SONG_PER_PROFILE 5 -#define MAX_EDITS_PER_SONG 5*NUM_PROFILE_SLOTS +const int MAX_EDITS_PER_SONG_PER_PROFILE = 5; +const int MAX_EDITS_PER_SONG = 5*NUM_PROFILE_SLOTS; extern const int FILE_CACHE_VERSION; +const int NUM_BACKGROUND_LAYERS = 2; struct BackgroundChange { @@ -153,18 +154,18 @@ public: bool Matches(CString sGroup, CString sSong) const; TimingData m_Timing; - vector m_BackgroundChanges; // this must be sorted before gameplay + vector m_BackgroundChanges[NUM_BACKGROUND_LAYERS]; // these must be sorted before gameplay vector m_ForegroundChanges; // this must be sorted before gameplay vector m_LyricSegments; // this must be sorted before gameplay void AddBPMSegment( const BPMSegment &seg ) { m_Timing.AddBPMSegment( seg ); } void AddStopSegment( const StopSegment &seg ) { m_Timing.AddStopSegment( seg ); } - void AddBackgroundChange( BackgroundChange seg ); + void AddBackgroundChange( int iLayer, BackgroundChange seg ); void AddForegroundChange( BackgroundChange seg ); void AddLyricSegment( LyricSegment seg ); void GetDisplayBpms( DisplayBpms &AddTo ) const; - CString GetBackgroundAtBeat( float fBeat ) const; + CString GetBackgroundAtBeat( int iLayer, float fBeat ) const; float GetBPMAtBeat( float fBeat ) const { return m_Timing.GetBPMAtBeat( fBeat ); } void SetBPMAtBeat( float fBeat, float fBPM ) { m_Timing.SetBPMAtBeat( fBeat, fBPM ); }