fix MiniMenu crashes for rows with 0 choices

more complete BackgroundChange controls in editor
added "play current beat until end" in editor
cleaned up Background
This commit is contained in:
Chris Danford
2003-03-16 00:05:23 +00:00
parent 4383b2ef3a
commit 5382f1f3fa
12 changed files with 262 additions and 285 deletions
@@ -0,0 +1 @@
MusicList titles
+162 -201
View File
@@ -19,7 +19,8 @@
#include "GameState.h" #include "GameState.h"
#include "ThemeManager.h" #include "ThemeManager.h"
#include "PrefsManager.h" #include "PrefsManager.h"
#include "NoteTypes.h"
#include <math.h> // for fmodf
const float FADE_SECONDS = 1.0f; const float FADE_SECONDS = 1.0f;
@@ -31,20 +32,22 @@ const float FADE_SECONDS = 1.0f;
#define RECT_BACKGROUND RectI(LEFT_EDGE,TOP_EDGE,RIGHT_EDGE,BOTTOM_EDGE) #define RECT_BACKGROUND RectI(LEFT_EDGE,TOP_EDGE,RIGHT_EDGE,BOTTOM_EDGE)
int CompareBGSegments(const BGSegment &seg1, const BGSegment &seg2)
{
return seg1.m_fStartBeat < seg2.m_fStartBeat;
}
void SortBGSegmentArray( vector<BGSegment> &arrayBGSegments ) const CString STATIC_BACKGROUND = "static background";
const int MAX_RANDOM_BACKGROUNDS = 5;
const CString RANDOM_BACKGROUND[MAX_RANDOM_BACKGROUNDS] =
{ {
sort( arrayBGSegments.begin(), arrayBGSegments.end(), CompareBGSegments ); "__random1",
} "__random2",
"__random3",
"__random4",
"__random5"
};
Background::Background() Background::Background()
{ {
m_iCurBGSegment = 0; m_iCurBGChange = 0;
m_bInDanger = false; m_bInDanger = false;
m_pFadingBGA = NULL; m_pFadingBGA = NULL;
@@ -72,12 +75,14 @@ Background::~Background()
void Background::Unload() void Background::Unload()
{ {
for( unsigned i=0; i<m_BGAnimations.size(); i++ ) for( map<CString,BGAnimation*>::iterator iter = m_BGAnimations.begin();
delete m_BGAnimations[i]; iter != m_BGAnimations.end();
iter++ )
delete iter->second;
m_BGAnimations.clear(); m_BGAnimations.clear();
m_aBGSegments.clear(); m_aBGChanges.clear();
m_iCurBGSegment = 0; m_iCurBGChange = 0;
} }
void Background::LoadFromAniDir( CString sAniDir ) void Background::LoadFromAniDir( CString sAniDir )
@@ -87,10 +92,10 @@ void Background::LoadFromAniDir( CString sAniDir )
BGAnimation* pTempBGA; BGAnimation* pTempBGA;
pTempBGA = new BGAnimation; pTempBGA = new BGAnimation;
pTempBGA->LoadFromAniDir( sAniDir ); pTempBGA->LoadFromAniDir( sAniDir );
m_BGAnimations.push_back( pTempBGA ); m_BGAnimations[STATIC_BACKGROUND] = pTempBGA;
} }
BGAnimation *Background::GetBGA(const Song *pSong, const BackgroundChange &aniseg) const BGAnimation *Background::CreateSongBGA(const Song *pSong, CString sBGName) const
{ {
BGAnimation *pTempBGA; BGAnimation *pTempBGA;
@@ -100,7 +105,7 @@ BGAnimation *Background::GetBGA(const Song *pSong, const BackgroundChange &anise
CStringArray asFiles; CStringArray asFiles;
// Look for BGAnims in the song dir // Look for BGAnims in the song dir
GetDirListing( pSong->GetSongDir()+aniseg.m_sBGName, asFiles, true, true ); GetDirListing( pSong->GetSongDir()+sBGName, asFiles, true, true );
if( !asFiles.empty() ) if( !asFiles.empty() )
{ {
pTempBGA = new BGAnimation; pTempBGA = new BGAnimation;
@@ -108,7 +113,7 @@ BGAnimation *Background::GetBGA(const Song *pSong, const BackgroundChange &anise
return pTempBGA; return pTempBGA;
} }
// Look for BG movies in the song dir // Look for BG movies in the song dir
GetDirListing( pSong->GetSongDir()+aniseg.m_sBGName, asFiles, false, true ); GetDirListing( pSong->GetSongDir()+sBGName, asFiles, false, true );
if( !asFiles.empty() ) if( !asFiles.empty() )
{ {
pTempBGA = new BGAnimation; pTempBGA = new BGAnimation;
@@ -116,7 +121,7 @@ BGAnimation *Background::GetBGA(const Song *pSong, const BackgroundChange &anise
return pTempBGA; return pTempBGA;
} }
// Look for movies in the RandomMovies dir // Look for movies in the RandomMovies dir
GetDirListing( RANDOMMOVIES_DIR+aniseg.m_sBGName, asFiles, false, true ); GetDirListing( RANDOMMOVIES_DIR+sBGName, asFiles, false, true );
if( !asFiles.empty() ) if( !asFiles.empty() )
{ {
pTempBGA = new BGAnimation; pTempBGA = new BGAnimation;
@@ -125,7 +130,7 @@ BGAnimation *Background::GetBGA(const Song *pSong, const BackgroundChange &anise
} }
// Look for BGAnims in the BGAnims dir // Look for BGAnims in the BGAnims dir
GetDirListing( BG_ANIMS_DIR+aniseg.m_sBGName, asFiles, true, true ); GetDirListing( BG_ANIMS_DIR+sBGName, asFiles, true, true );
if( !asFiles.empty() ) if( !asFiles.empty() )
{ {
pTempBGA = new BGAnimation; pTempBGA = new BGAnimation;
@@ -134,16 +139,78 @@ BGAnimation *Background::GetBGA(const Song *pSong, const BackgroundChange &anise
} }
// Look for BGAnims in the BGAnims dir // Look for BGAnims in the BGAnims dir
GetDirListing( VISUALIZATIONS_DIR+aniseg.m_sBGName, asFiles, false, true ); GetDirListing( VISUALIZATIONS_DIR+sBGName, asFiles, false, true );
if( !asFiles.empty() ) if( !asFiles.empty() )
{ {
pTempBGA = new BGAnimation; pTempBGA = new BGAnimation;
pTempBGA->LoadFromVisualization( asFiles[0] ); pTempBGA->LoadFromVisualization( asFiles[0] );
return pTempBGA; return pTempBGA;
} }
// There is no background by this name.
return NULL; return NULL;
} }
BGAnimation* Background::CreateRandomBGA() const
{
switch( PREFSMAN->m_BackgroundMode )
{
default:
ASSERT(0);
// fall through
case PrefsManager::BGMODE_OFF:
return NULL;
case PrefsManager::BGMODE_ANIMATIONS:
{
CStringArray arrayPossibleAnims;
GetDirListing( BG_ANIMS_DIR+"*", arrayPossibleAnims, true, true );
// strip out "cvs" and "danger
int i;
for( i=arrayPossibleAnims.size()-1; i>=0; i-- )
if( 0==stricmp(arrayPossibleAnims[i].Right(3),"cvs") || 0==stricmp(arrayPossibleAnims[i].Right(3),"danger") )
arrayPossibleAnims.erase(arrayPossibleAnims.begin()+i,
arrayPossibleAnims.begin()+i+1);
if( arrayPossibleAnims.empty() )
return NULL;
unsigned index = rand() % arrayPossibleAnims.size();
BGAnimation *pTempBGA = new BGAnimation;
pTempBGA->LoadFromAniDir( arrayPossibleAnims[index] );
return pTempBGA;
}
case PrefsManager::BGMODE_MOVIEVIS:
{
CStringArray arrayPossibleMovies;
GetDirListing( VISUALIZATIONS_DIR + "*.avi", arrayPossibleMovies, false, true );
GetDirListing( VISUALIZATIONS_DIR + "*.mpg", arrayPossibleMovies, false, true );
GetDirListing( VISUALIZATIONS_DIR + "*.mpeg", arrayPossibleMovies, false, true );
if( arrayPossibleMovies.empty() )
return NULL;
unsigned index = rand() % arrayPossibleMovies.size();
BGAnimation* pTempBGA = new BGAnimation;
pTempBGA->LoadFromVisualization( arrayPossibleMovies[index] );
return pTempBGA;
}
break;
case PrefsManager::BGMODE_RANDOMMOVIES:
{
CStringArray arrayPossibleMovies;
GetDirListing( RANDOMMOVIES_DIR + "*.avi", arrayPossibleMovies, false, true );
GetDirListing( RANDOMMOVIES_DIR + "*.mpg", arrayPossibleMovies, false, true );
GetDirListing( RANDOMMOVIES_DIR + "*.mpeg", arrayPossibleMovies, false, true );
if( arrayPossibleMovies.empty() )
return NULL;
unsigned index = rand() % arrayPossibleMovies.size();
BGAnimation *pTempBGA = new BGAnimation;
pTempBGA->LoadFromMovie( arrayPossibleMovies[index], true, false );
return pTempBGA;
}
break;
}
}
void Background::LoadFromSong( Song* pSong ) void Background::LoadFromSong( Song* pSong )
{ {
Unload(); Unload();
@@ -153,201 +220,94 @@ void Background::LoadFromSong( Song* pSong )
CString sSongBGPath = pSong && pSong->HasBackground() ? pSong->GetBackgroundPath() : THEME->GetPathTo("Graphics","Common fallback background"); CString sSongBGPath = pSong && pSong->HasBackground() ? pSong->GetBackgroundPath() : THEME->GetPathTo("Graphics","Common fallback background");
//
// Load the static background that will before notes start and after notes end // Load the static background that will before notes start and after notes end
//
{ {
BGAnimation *pTempBGA = new BGAnimation; BGAnimation *pTempBGA = new BGAnimation;
pTempBGA->LoadFromStaticGraphic( sSongBGPath ); pTempBGA->LoadFromStaticGraphic( sSongBGPath );
m_BGAnimations.push_back( pTempBGA ); m_BGAnimations[STATIC_BACKGROUND] = pTempBGA;
} }
// Load random backgrounds
{
for( int i=0; i<MAX_RANDOM_BACKGROUNDS; i++ )
{
CString sBGName = RANDOM_BACKGROUND[ i ];
m_BGAnimations[sBGName] = CreateRandomBGA();
}
}
// start off showing the static song background
m_aBGChanges.push_back( BackgroundChange(-10000,STATIC_BACKGROUND) );
if( pSong->HasBGChanges() ) if( pSong->HasBGChanges() )
{ {
// start off showing the static song background // Load all song-specified backgrounds
m_aBGSegments.push_back( BGSegment(-10000,0,false) );
// Load the animations used by the song's pre-defined animation plan.
// the song has a plan. Use it.
for( unsigned i=0; i<pSong->m_BackgroundChanges.size(); i++ ) for( unsigned i=0; i<pSong->m_BackgroundChanges.size(); i++ )
{ {
const BackgroundChange& aniseg = pSong->m_BackgroundChanges[i]; float fStartBeat = pSong->m_BackgroundChanges[i].m_fStartBeat;
bool bFade = i==0; CString sBGName = pSong->m_BackgroundChanges[i].m_sBGName;
BGAnimation *pTempBGA = GetBGA(pSong, aniseg); bool bIsAlreadyLoaded = m_BGAnimations.find(sBGName) != m_BGAnimations.end();
if(pTempBGA != NULL) if( !bIsAlreadyLoaded )
{ {
m_BGAnimations.push_back( pTempBGA ); BGAnimation *pTempBGA = CreateSongBGA(pSong, sBGName);
// add to the plan if( pTempBGA )
m_aBGSegments.push_back( BGSegment(aniseg.m_fStartBeat, m_BGAnimations.size()-1, bFade) ); m_BGAnimations[sBGName] = pTempBGA;
else // the background was not found. Use a random one instead
sBGName = RANDOM_BACKGROUND[ rand()%MAX_RANDOM_BACKGROUNDS ];
} }
m_aBGChanges.push_back( BackgroundChange(fStartBeat, sBGName) );
} }
// end showing the static song background
m_aBGSegments.push_back( BGSegment(pSong->m_fLastBeat,0,false) );
SortBGSegmentArray( m_aBGSegments ); // Need to sort in case there is a background change after the last beat (not likely)
} }
else // pSong doesn't have an animation plan else // pSong doesn't have an animation plan
{ {
enum BackgroundMode { MODE_STATIC_BG, MODE_ANIMATIONS, MODE_MOVIE_VIS, MODE_RANDOMMOVIES } backgroundMode;
//
// figure out what BackgroundMode to use
//
if( PREFSMAN->m_BackgroundMode == PrefsManager::BGMODE_OFF )
backgroundMode = MODE_STATIC_BG;
else if( PREFSMAN->m_BackgroundMode == PrefsManager::BGMODE_MOVIEVIS )
backgroundMode = MODE_MOVIE_VIS;
else if( PREFSMAN->m_BackgroundMode == PrefsManager::BGMODE_RANDOMMOVIES )
backgroundMode = MODE_RANDOMMOVIES;
else
backgroundMode = MODE_ANIMATIONS;
bool bFade = backgroundMode==MODE_RANDOMMOVIES;
//
// Load animations that will play while notes are active
//
switch( backgroundMode )
{
case MODE_STATIC_BG:
break;
case MODE_MOVIE_VIS:
{
CStringArray arrayPossibleMovies;
GetDirListing( VISUALIZATIONS_DIR + "*.avi", arrayPossibleMovies, false, true );
GetDirListing( VISUALIZATIONS_DIR + "*.mpg", arrayPossibleMovies, false, true );
GetDirListing( VISUALIZATIONS_DIR + "*.mpeg", arrayPossibleMovies, false, true );
BGAnimation *pTempBGA = NULL;
if( !arrayPossibleMovies.empty() )
{
unsigned index = rand() % arrayPossibleMovies.size();
pTempBGA = new BGAnimation;
pTempBGA->LoadFromVisualization( arrayPossibleMovies[index] );
}
else
{
pTempBGA = new BGAnimation;
pTempBGA->LoadFromStaticGraphic( sSongBGPath );
}
m_BGAnimations.push_back( pTempBGA );
}
break;
case MODE_ANIMATIONS:
{
CStringArray arrayPossibleAnims;
GetDirListing( BG_ANIMS_DIR+"*", arrayPossibleAnims, true, true );
// strip out "cvs" and "danger
int i;
for( i=arrayPossibleAnims.size()-1; i>=0; i-- )
if( 0==stricmp(arrayPossibleAnims[i].Right(3),"cvs") || 0==stricmp(arrayPossibleAnims[i].Right(3),"danger") )
arrayPossibleAnims.erase(arrayPossibleAnims.begin()+i,
arrayPossibleAnims.begin()+i+1);
for( i=0; i<4 && !arrayPossibleAnims.empty(); i++ )
{
unsigned index = rand() % arrayPossibleAnims.size();
BGAnimation *pTempBGA = new BGAnimation;
pTempBGA->LoadFromAniDir( arrayPossibleAnims[index] );
m_BGAnimations.push_back( pTempBGA );
arrayPossibleAnims.erase( arrayPossibleAnims.begin()+index,
arrayPossibleAnims.begin()+index+1 );
}
}
break;
case MODE_RANDOMMOVIES:
{
CStringArray arrayPossibleMovies;
GetDirListing( RANDOMMOVIES_DIR + "*.avi", arrayPossibleMovies, false, true );
GetDirListing( RANDOMMOVIES_DIR + "*.mpg", arrayPossibleMovies, false, true );
GetDirListing( RANDOMMOVIES_DIR + "*.mpeg", arrayPossibleMovies, false, true );
for( int i=0; i<4 && !arrayPossibleMovies.empty(); i++ )
{
unsigned index = rand() % arrayPossibleMovies.size();
BGAnimation *pTempBGA = new BGAnimation;
pTempBGA->LoadFromMovie( arrayPossibleMovies[index], true, false );
m_BGAnimations.push_back( pTempBGA );
arrayPossibleMovies.erase( arrayPossibleMovies.begin()+index,
arrayPossibleMovies.begin()+index+1 );
}
}
break;
default:
ASSERT(0);
}
// At this point, m_BGAnimations[0] is the song background, and everything else
// in m_BGAnimations should be cycled through randomly while notes are playing.
//
// Generate an animation plan
//
if( backgroundMode == MODE_MOVIE_VIS )
{
m_aBGSegments.push_back( BGSegment(-10000,1,false) );
return;
}
else
{
// start off showing the static song background
m_aBGSegments.push_back( BGSegment(-10000,0,false) );
}
const float fFirstBeat = pSong->m_fFirstBeat; const float fFirstBeat = pSong->m_fFirstBeat;
const float fLastBeat = pSong->m_fLastBeat; const float fLastBeat = pSong->m_fLastBeat;
/* If we have only 2, only generate a single animation segment for for the // change BG every 4 bars
* whole song. Otherwise, if it's a movie, it'll loop every four measures; we for( float f=fFirstBeat; f<fLastBeat; f+=BEATS_PER_MEASURE*4 )
* want it to play continuously. */ {
if( m_BGAnimations.size() == 2) { CString sBGName = RANDOM_BACKGROUND[ rand()%MAX_RANDOM_BACKGROUNDS ];
m_aBGSegments.push_back( BGSegment(fFirstBeat,1,bFade) ); m_aBGChanges.push_back( BackgroundChange(f,sBGName) );
} else {
// change BG every 4 bars
for( float f=fFirstBeat; f<fLastBeat; f+=16 )
{
int index;
if( m_BGAnimations.size()==1 )
index = 0;
else if( f == fFirstBeat )
index = 1; // force the first random background to play first
else
index = 1 + rand()%(m_BGAnimations.size()-1);
m_aBGSegments.push_back( BGSegment(f,index,bFade) );
}
// change BG every BPM change
for( unsigned i=0; i<pSong->m_BPMSegments.size(); i++ )
{
const BPMSegment& bpmseg = pSong->m_BPMSegments[i];
if( bpmseg.m_fStartBeat < fFirstBeat || bpmseg.m_fStartBeat > fLastBeat )
continue; // skip]
int index;
if( m_BGAnimations.size()==1 )
index = 0;
else
index = 1 + int(bpmseg.m_fBPM)%(m_BGAnimations.size()-1);
m_aBGSegments.push_back( BGSegment(bpmseg.m_fStartBeat,index,bFade) );
}
} }
// end showing the static song background // change BG every BPM change that is at the beginning of a measure
m_aBGSegments.push_back( BGSegment(pSong->m_fLastBeat,0,bFade) ); for( unsigned i=0; i<pSong->m_BPMSegments.size(); i++ )
{
const BPMSegment& bpmseg = pSong->m_BPMSegments[i];
// sort segments if( fmodf(bpmseg.m_fStartBeat, BEATS_PER_MEASURE) != 0 )
SortBGSegmentArray( m_aBGSegments ); continue; // skip
if( bpmseg.m_fStartBeat < fFirstBeat || bpmseg.m_fStartBeat > fLastBeat )
continue; // skip
CString sBGName = RANDOM_BACKGROUND[ rand()%MAX_RANDOM_BACKGROUNDS ];
m_aBGChanges.push_back( BackgroundChange(bpmseg.m_fStartBeat,sBGName) );
}
} }
for( unsigned i=0; i<m_BGAnimations.size(); i++ )
// end showing the static song background
m_aBGChanges.push_back( BackgroundChange(pSong->m_fLastBeat,STATIC_BACKGROUND) );
// sort segments
SortBackgroundChangesArray( m_aBGChanges );
for( map<CString,BGAnimation*>::iterator iter = m_BGAnimations.begin();
iter != m_BGAnimations.end();
iter++ )
{ {
m_BGAnimations[i]->SetXY( (float)LEFT_EDGE, (float)TOP_EDGE ); iter->second->SetXY( (float)LEFT_EDGE, (float)TOP_EDGE );
m_BGAnimations[i]->SetZoomX( fXZoom ); iter->second->SetZoomX( fXZoom );
m_BGAnimations[i]->SetZoomY( fYZoom ); iter->second->SetZoomY( fYZoom );
} }
m_BGADanger.SetXY( (float)LEFT_EDGE, (float)TOP_EDGE ); m_BGADanger.SetXY( (float)LEFT_EDGE, (float)TOP_EDGE );
@@ -360,7 +320,7 @@ void Background::Update( float fDeltaTime )
{ {
ActorFrame::Update( fDeltaTime ); ActorFrame::Update( fDeltaTime );
if( DangerVisible() ) if( IsDangerVisible() )
{ {
m_BGADanger.Update( fDeltaTime ); m_BGADanger.Update( fDeltaTime );
} }
@@ -375,17 +335,17 @@ void Background::Update( float fDeltaTime )
// Find the BGSegment we're in // Find the BGSegment we're in
unsigned i; unsigned i;
for( i=0; i<m_aBGSegments.size()-1; i++ ) for( i=0; i<m_aBGChanges.size()-1; i++ )
if( GAMESTATE->m_fSongBeat < m_aBGSegments[i+1].m_fStartBeat ) if( GAMESTATE->m_fSongBeat < m_aBGChanges[i+1].m_fStartBeat )
break; break;
ASSERT( i >= 0 && i<m_aBGSegments.size() ); ASSERT( i >= 0 && i<m_aBGChanges.size() );
if( int(i) > m_iCurBGSegment ) if( int(i) > m_iCurBGChange )
{ {
// LOG->Trace( "%d, %d, %f, %f\n", m_iCurBGSegment, i, m_aBGSegments[i].m_fStartBeat, GAMESTATE->m_fSongBeat ); // LOG->Trace( "%d, %d, %f, %f\n", m_iCurBGSegment, i, m_aBGSegments[i].m_fStartBeat, GAMESTATE->m_fSongBeat );
BGAnimation* pOld = GetCurBGA(); BGAnimation* pOld = GetCurrentBGA();
m_iCurBGSegment = i; m_iCurBGChange = i;
BGAnimation* pNew = GetCurBGA(); BGAnimation* pNew = GetCurrentBGA();
if( pOld != pNew ) if( pOld != pNew )
{ {
@@ -393,11 +353,12 @@ void Background::Update( float fDeltaTime )
pNew->GainingFocus(); pNew->GainingFocus();
m_pFadingBGA = pOld; m_pFadingBGA = pOld;
m_fSecsLeftInFade = m_aBGSegments[m_iCurBGSegment].m_bFade ? FADE_SECONDS : 0; bool bBGAnimsMode = PREFSMAN->m_BackgroundMode == PrefsManager::BGMODE_ANIMATIONS;
m_fSecsLeftInFade = bBGAnimsMode ? 0 : FADE_SECONDS;
} }
} }
GetCurBGA()->Update( fDeltaTime ); GetCurrentBGA()->Update( fDeltaTime );
if( m_pFadingBGA ) if( m_pFadingBGA )
{ {
m_pFadingBGA->Update( fDeltaTime ); m_pFadingBGA->Update( fDeltaTime );
@@ -416,13 +377,13 @@ void Background::DrawPrimitives()
{ {
ActorFrame::DrawPrimitives(); ActorFrame::DrawPrimitives();
if( DangerVisible() ) if( IsDangerVisible() )
{ {
m_BGADanger.Draw(); m_BGADanger.Draw();
} }
else else
{ {
GetCurBGA()->Draw(); GetCurrentBGA()->Draw();
if( m_pFadingBGA ) if( m_pFadingBGA )
m_pFadingBGA->Draw(); m_pFadingBGA->Draw();
} }
@@ -432,7 +393,7 @@ void Background::DrawPrimitives()
m_quadBorder[i].Draw(); m_quadBorder[i].Draw();
} }
bool Background::DangerVisible() bool Background::IsDangerVisible()
{ {
return m_bInDanger && PREFSMAN->m_bShowDanger && (RageTimer::GetTimeSinceStart() - (int)RageTimer::GetTimeSinceStart()) < 0.5f; return m_bInDanger && PREFSMAN->m_bShowDanger && (RageTimer::GetTimeSinceStart() - (int)RageTimer::GetTimeSinceStart()) < 0.5f;
} }
+13 -20
View File
@@ -12,22 +12,11 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
*/ */
#include "Sprite.h" #include "Sprite.h"
#include "Quad.h" #include "Quad.h"
#include "ActorFrame.h" #include "ActorFrame.h"
#include "song.h"
#include "BGAnimation.h" #include "BGAnimation.h"
#include "Song.h"
struct BGSegment // like a BGChange, but holds index of a background instead of name
{
BGSegment() {};
BGSegment( float b, int i, bool f ) { m_fStartBeat = b; m_iBGIndex = i; m_bFade = f; };
float m_fStartBeat;
int m_iBGIndex;
bool m_bFade;
};
class Background : public ActorFrame class Background : public ActorFrame
@@ -53,17 +42,21 @@ public:
virtual bool IsInDanger() { return m_bInDanger; }; virtual bool IsInDanger() { return m_bInDanger; };
protected: protected:
bool DangerVisible(); bool IsDangerVisible();
BGAnimation *GetBGA(const Song *pSong, const BackgroundChange &aniseg) const;
BGAnimation m_BGADanger; BGAnimation m_BGADanger;
// used in all BackgroundModes except OFF
vector<BGAnimation*> m_BGAnimations; BGAnimation* CreateSongBGA(const Song *pSong, CString sBGName) const;
vector<BGSegment> m_aBGSegments; BGAnimation* CreateRandomBGA() const;
int m_iCurBGSegment; // this increases as we move into new segments
BGAnimation* GetCurBGA() { int index = m_aBGSegments[m_iCurBGSegment].m_iBGIndex; return m_BGAnimations[index]; }; map<CString,BGAnimation*> m_BGAnimations;
BGAnimation* m_pCurrentBGA; vector<BackgroundChange> m_aBGChanges;
int m_iCurBGChange; // starts at 0 and increases to m_aBGSegments.size()-1
BGAnimation* GetCurrentBGA()
{
return m_BGAnimations[ m_aBGChanges[m_iCurBGChange].m_sBGName ];
}
BGAnimation* m_pFadingBGA; BGAnimation* m_pFadingBGA;
float m_fSecsLeftInFade; float m_fSecsLeftInFade;
+4 -1
View File
@@ -174,6 +174,7 @@ void NoteField::DrawBPMText( const float fBeat, const float fBPM )
const float fYOffset = ArrowGetYOffset( m_PlayerNumber, fBeat ); const float fYOffset = ArrowGetYOffset( m_PlayerNumber, fBeat );
const float fYPos = ArrowGetYPos( m_PlayerNumber, fYOffset ); const float fYPos = ArrowGetYPos( m_PlayerNumber, fYOffset );
m_textMeasureNumber.SetHorizAlign( Actor::align_right );
m_textMeasureNumber.SetDiffuse( RageColor(1,0,0,1) ); m_textMeasureNumber.SetDiffuse( RageColor(1,0,0,1) );
m_textMeasureNumber.SetGlow( RageColor(1,1,1,cosf(RageTimer::GetTimeSinceStart()*2)/2+0.5f) ); m_textMeasureNumber.SetGlow( RageColor(1,1,1,cosf(RageTimer::GetTimeSinceStart()*2)/2+0.5f) );
m_textMeasureNumber.SetText( ssprintf("%.2f", fBPM) ); m_textMeasureNumber.SetText( ssprintf("%.2f", fBPM) );
@@ -186,6 +187,7 @@ void NoteField::DrawFreezeText( const float fBeat, const float fSecs )
const float fYOffset = ArrowGetYOffset( m_PlayerNumber, fBeat ); const float fYOffset = ArrowGetYOffset( m_PlayerNumber, fBeat );
const float fYPos = ArrowGetYPos( m_PlayerNumber, fYOffset ); const float fYPos = ArrowGetYPos( m_PlayerNumber, fYOffset );
m_textMeasureNumber.SetHorizAlign( Actor::align_right );
m_textMeasureNumber.SetDiffuse( RageColor(0.8f,0.8f,0,1) ); m_textMeasureNumber.SetDiffuse( RageColor(0.8f,0.8f,0,1) );
m_textMeasureNumber.SetGlow( RageColor(1,1,1,cosf(RageTimer::GetTimeSinceStart()*2)/2+0.5f) ); m_textMeasureNumber.SetGlow( RageColor(1,1,1,cosf(RageTimer::GetTimeSinceStart()*2)/2+0.5f) );
m_textMeasureNumber.SetText( ssprintf("%.2f", fSecs) ); m_textMeasureNumber.SetText( ssprintf("%.2f", fSecs) );
@@ -198,10 +200,11 @@ void NoteField::DrawBGChangeText( const float fBeat, const CString sNewBGName )
const float fYOffset = ArrowGetYOffset( m_PlayerNumber, fBeat ); const float fYOffset = ArrowGetYOffset( m_PlayerNumber, fBeat );
const float fYPos = ArrowGetYPos( m_PlayerNumber, fYOffset ); const float fYPos = ArrowGetYPos( m_PlayerNumber, fYOffset );
m_textMeasureNumber.SetHorizAlign( Actor::align_left );
m_textMeasureNumber.SetDiffuse( RageColor(0,1,0,1) ); m_textMeasureNumber.SetDiffuse( RageColor(0,1,0,1) );
m_textMeasureNumber.SetGlow( RageColor(1,1,1,cosf(RageTimer::GetTimeSinceStart()*2)/2+0.5f) ); m_textMeasureNumber.SetGlow( RageColor(1,1,1,cosf(RageTimer::GetTimeSinceStart()*2)/2+0.5f) );
m_textMeasureNumber.SetText( sNewBGName ); m_textMeasureNumber.SetText( sNewBGName );
m_textMeasureNumber.SetXY( +GetWidth()/2.f + 10, fYPos ); m_textMeasureNumber.SetXY( +GetWidth()/2.f, fYPos );
m_textMeasureNumber.Draw(); m_textMeasureNumber.Draw();
} }
+61 -54
View File
@@ -111,6 +111,7 @@ Menu g_KeyboardShortcuts
MenuRow( "Shift + Up/Down: Drag area marker", false ), MenuRow( "Shift + Up/Down: Drag area marker", false ),
MenuRow( "P: Play selection", false ), MenuRow( "P: Play selection", false ),
MenuRow( "Ctrl + P: Play whole song", false ), MenuRow( "Ctrl + P: Play whole song", false ),
MenuRow( "Shift + P: Play current beat to end", false ),
MenuRow( "F7/F8: Decrease/increase BPM at cur beat", false ), MenuRow( "F7/F8: Decrease/increase BPM at cur beat", false ),
MenuRow( "F9/F10: Decrease/increase stop at cur beat", false ), MenuRow( "F9/F10: Decrease/increase stop at cur beat", false ),
MenuRow( "F11/F12: Decrease/increase music offset", false ), MenuRow( "F11/F12: Decrease/increase music offset", false ),
@@ -119,23 +120,25 @@ Menu g_KeyboardShortcuts
* menu each time), so it doesn't use a whole bunch of hotkeys. */ * menu each time), so it doesn't use a whole bunch of hotkeys. */
MenuRow( "[ and ]: Decrease/increase sample music start", false ), MenuRow( "[ and ]: Decrease/increase sample music start", false ),
MenuRow( "{ and }: Decrease/increase sample music length", false ), MenuRow( "{ and }: Decrease/increase sample music length", false ),
MenuRow( "M: Play sample music", false ) MenuRow( "M: Play sample music", false ),
MenuRow( "B: Add/Edit Background Change", false )
); );
Menu g_MainMenu Menu g_MainMenu
( (
"Main Menu", "Main Menu",
MenuRow( "Edit Notes Statistics", true ), MenuRow( "Edit Notes Statistics", true ),
MenuRow( "Play Whole Song", true ), MenuRow( "Play Whole Song", true ),
MenuRow( "Save", true ), MenuRow( "Play Current Beat To End", true ),
MenuRow( "Player Options", true ), MenuRow( "Save", true ),
MenuRow( "Song Options", true ), MenuRow( "Player Options", true ),
MenuRow( "Edit Song Info", true ), MenuRow( "Song Options", true ),
MenuRow( "Add/Edit BPM Change", true ), MenuRow( "Edit Song Info", true ),
MenuRow( "Add/Edit Stop", true ), MenuRow( "Add/Edit BPM Change", true ),
MenuRow( "Add/Edit BG Change", true ), MenuRow( "Add/Edit Stop", true ),
MenuRow( "Play preview music", true ), MenuRow( "Add/Edit BG Change", true ),
MenuRow( "Exit", true ) MenuRow( "Play preview music", true ),
MenuRow( "Exit", true )
); );
Menu g_AreaMenu Menu g_AreaMenu
@@ -913,11 +916,17 @@ void ScreenEdit::InputEdit( const DeviceInput& DeviceI, const InputEventType typ
case SDLK_m: case SDLK_m:
PlayPreviewMusic(); PlayPreviewMusic();
break; break;
case SDLK_b:
HandleMainMenuChoice( edit_bg_change, NULL );
break;
case SDLK_p: case SDLK_p:
{ {
if( INPUTFILTER->IsBeingPressed(DeviceInput(DEVICE_KEYBOARD,SDLK_LCTRL)) || if( INPUTFILTER->IsBeingPressed(DeviceInput(DEVICE_KEYBOARD,SDLK_LCTRL)) ||
INPUTFILTER->IsBeingPressed(DeviceInput(DEVICE_KEYBOARD,SDLK_RCTRL)) ) INPUTFILTER->IsBeingPressed(DeviceInput(DEVICE_KEYBOARD,SDLK_RCTRL)) )
HandleMainMenuChoice( play_whole_song, NULL ); HandleMainMenuChoice( play_whole_song, NULL );
else if( INPUTFILTER->IsBeingPressed(DeviceInput(DEVICE_KEYBOARD,SDLK_LSHIFT)) ||
INPUTFILTER->IsBeingPressed(DeviceInput(DEVICE_KEYBOARD,SDLK_RSHIFT)) )
HandleMainMenuChoice( play_current_beat_to_end, NULL );
else else
if( m_NoteFieldEdit.m_fBeginMarker!=-1 && m_NoteFieldEdit.m_fEndMarker!=-1 ) if( m_NoteFieldEdit.m_fBeginMarker!=-1 && m_NoteFieldEdit.m_fEndMarker!=-1 )
HandleAreaMenuChoice( play, NULL ); HandleAreaMenuChoice( play, NULL );
@@ -1088,24 +1097,6 @@ void ScreenEdit::OnSnapModeChange()
// Begin helper functions for InputEdit // Begin helper functions for InputEdit
void AddBGChange( CString sBGName )
{
Song* pSong = GAMESTATE->m_pCurSong;
unsigned i;
for( i=0; i<pSong->m_BackgroundChanges.size(); i++ )
{
if( pSong->m_BackgroundChanges[i].m_fStartBeat == GAMESTATE->m_fSongBeat )
break;
}
if( i != pSong->m_BackgroundChanges.size() ) // there is already a BGChange here
pSong->m_BackgroundChanges.erase( pSong->m_BackgroundChanges.begin()+i,
pSong->m_BackgroundChanges.begin()+i+1);
// create a new BGChange
if( sBGName != "" )
pSong->AddBackgroundChange( BackgroundChange(GAMESTATE->m_fSongBeat, sBGName) );
}
void ChangeDescription( CString sNew ) void ChangeDescription( CString sNew )
{ {
@@ -1183,6 +1174,13 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, int* iAnswers )
HandleAreaMenuChoice( play, NULL ); HandleAreaMenuChoice( play, NULL );
} }
break; break;
case play_current_beat_to_end:
{
m_NoteFieldEdit.m_fBeginMarker = GAMESTATE->m_fSongBeat;
m_NoteFieldEdit.m_fEndMarker = m_NoteFieldEdit.GetLastBeat();
HandleAreaMenuChoice( play, NULL );
}
break;
case save: case save:
{ {
// copy edit into current Notes // copy edit into current Notes
@@ -1193,7 +1191,7 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, int* iAnswers )
GAMESTATE->m_pCurSong->Save(); GAMESTATE->m_pCurSong->Save();
SCREENMAN->SystemMessage( "Saved as SM and DWI." ); SCREENMAN->SystemMessage( "Saved as SM and DWI." );
SOUNDMAN->PlayOnce( THEME->GetPathTo("Sounds","edit save") ); SOUNDMAN->PlayOnce( THEME->GetPathTo("Sounds","ScreenEdit save") );
} }
break; break;
case player_options: case player_options:
@@ -1224,26 +1222,28 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, int* iAnswers )
// //
// Fill in option names // Fill in option names
// //
// m_pSong->GetSongDir() has trailing slash
g_BGChange.rows[add_song_bganimation].choices.clear(); g_BGChange.rows[add_song_bganimation].choices.clear();
GetDirListing( m_pSong->GetSongDir()+"/*.*", g_BGChange.rows[add_song_bganimation].choices, true ); GetDirListing( m_pSong->GetSongDir()+"*.*", g_BGChange.rows[add_song_bganimation].choices, true );
g_BGChange.rows[add_song_movie].choices.clear(); g_BGChange.rows[add_song_movie].choices.clear();
GetDirListing( m_pSong->GetSongDir()+"/*.avi", g_BGChange.rows[add_song_movie].choices, false ); GetDirListing( m_pSong->GetSongDir()+"*.avi", g_BGChange.rows[add_song_movie].choices, false );
GetDirListing( m_pSong->GetSongDir()+"/*.mpg", g_BGChange.rows[add_song_movie].choices, false ); GetDirListing( m_pSong->GetSongDir()+"*.mpg", g_BGChange.rows[add_song_movie].choices, false );
GetDirListing( m_pSong->GetSongDir()+"/*.mpeg", g_BGChange.rows[add_song_movie].choices, false ); GetDirListing( m_pSong->GetSongDir()+"*.mpeg", g_BGChange.rows[add_song_movie].choices, false );
g_BGChange.rows[add_global_random_movie].choices.clear(); g_BGChange.rows[add_global_random_movie].choices.clear();
GetDirListing( m_pSong->GetSongDir()+"/*.avi", g_BGChange.rows[add_global_random_movie].choices, false ); GetDirListing( RANDOMMOVIES_DIR+"*.avi", g_BGChange.rows[add_global_random_movie].choices, false );
GetDirListing( m_pSong->GetSongDir()+"/*.mpg", g_BGChange.rows[add_global_random_movie].choices, false ); GetDirListing( RANDOMMOVIES_DIR+"*.mpg", g_BGChange.rows[add_global_random_movie].choices, false );
GetDirListing( m_pSong->GetSongDir()+"/*.mpeg", g_BGChange.rows[add_global_random_movie].choices, false ); GetDirListing( RANDOMMOVIES_DIR+"*.mpeg", g_BGChange.rows[add_global_random_movie].choices, false );
g_BGChange.rows[add_global_bganimation].choices.clear(); g_BGChange.rows[add_global_bganimation].choices.clear();
GetDirListing( m_pSong->GetSongDir()+"/*.*", g_BGChange.rows[add_global_bganimation].choices, true ); GetDirListing( BG_ANIMS_DIR+"*.*", g_BGChange.rows[add_global_bganimation].choices, true );
g_BGChange.rows[add_global_visualization].choices.clear(); g_BGChange.rows[add_global_visualization].choices.clear();
GetDirListing( m_pSong->GetSongDir()+"/*.avi", g_BGChange.rows[add_global_visualization].choices, false ); GetDirListing( VISUALIZATIONS_DIR+"*.avi", g_BGChange.rows[add_global_visualization].choices, false );
GetDirListing( m_pSong->GetSongDir()+"/*.mpg", g_BGChange.rows[add_global_visualization].choices, false ); GetDirListing( VISUALIZATIONS_DIR+"*.mpg", g_BGChange.rows[add_global_visualization].choices, false );
GetDirListing( m_pSong->GetSongDir()+"/*.mpeg", g_BGChange.rows[add_global_visualization].choices, false ); GetDirListing( VISUALIZATIONS_DIR+"*.mpeg", g_BGChange.rows[add_global_visualization].choices, false );
// //
@@ -1256,7 +1256,7 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, int* iAnswers )
g_BGChange.rows[add_random].enabled = true; g_BGChange.rows[add_random].enabled = true;
g_BGChange.rows[add_song_bganimation].enabled = g_BGChange.rows[add_song_bganimation].choices.size() > 0; g_BGChange.rows[add_song_bganimation].enabled = g_BGChange.rows[add_song_bganimation].choices.size() > 0;
g_BGChange.rows[add_song_movie].enabled = g_BGChange.rows[add_global_random_movie].choices.size() > 0; g_BGChange.rows[add_song_movie].enabled = g_BGChange.rows[add_song_movie].choices.size() > 0;
g_BGChange.rows[add_global_random_movie].enabled = g_BGChange.rows[add_global_random_movie].choices.size() > 0; g_BGChange.rows[add_global_random_movie].enabled = g_BGChange.rows[add_global_random_movie].choices.size() > 0;
g_BGChange.rows[add_global_bganimation].enabled = g_BGChange.rows[add_global_bganimation].choices.size() > 0; g_BGChange.rows[add_global_bganimation].enabled = g_BGChange.rows[add_global_bganimation].choices.size() > 0;
g_BGChange.rows[add_global_visualization].enabled = g_BGChange.rows[add_global_visualization].choices.size() > 0; g_BGChange.rows[add_global_visualization].enabled = g_BGChange.rows[add_global_visualization].choices.size() > 0;
@@ -1515,30 +1515,37 @@ void ScreenEdit::HandleBGChangeChoice( BGChangeChoice c, int* iAnswers )
{ {
Song* pSong = GAMESTATE->m_pCurSong; Song* pSong = GAMESTATE->m_pCurSong;
CString sBGName;
switch( c ) switch( c )
{ {
case add_random: case add_random:
SCREENMAN->TextEntry( SM_None, "Edit main title.\nPress Enter to confirm,\nEscape to cancel.", pSong->m_sMainTitle, ChangeMainTitle, NULL ); sBGName = "-random-";
break; break;
case add_song_bganimation: case add_song_bganimation:
SCREENMAN->TextEntry( SM_None, "Edit sub title.\nPress Enter to confirm,\nEscape to cancel.", pSong->m_sSubTitle, ChangeSubTitle, NULL );
break;
case add_song_movie: case add_song_movie:
SCREENMAN->TextEntry( SM_None, "Edit artist.\nPress Enter to confirm,\nEscape to cancel.", pSong->m_sArtist, ChangeArtist, NULL );
break;
case add_global_random_movie: case add_global_random_movie:
SCREENMAN->TextEntry( SM_None, "Edit main title transliteration.\nPress Enter to confirm,\nEscape to cancel.", pSong->m_sMainTitleTranslit, ChangeMainTitleTranslit, NULL );
break;
case add_global_bganimation: case add_global_bganimation:
SCREENMAN->TextEntry( SM_None, "Edit sub title transliteration.\nPress Enter to confirm,\nEscape to cancel.", pSong->m_sSubTitleTranslit, ChangeSubTitleTranslit, NULL );
break;
case add_global_visualization: case add_global_visualization:
SCREENMAN->TextEntry( SM_None, "Edit artist transliteration.\nPress Enter to confirm,\nEscape to cancel.", pSong->m_sArtistTranslit, ChangeArtistTranslit, NULL ); sBGName = g_BGChange.rows[c].choices[iAnswers[c]];
break; break;
case delete_change: case delete_change:
SCREENMAN->TextEntry( SM_None, "Edit artist transliteration.\nPress Enter to confirm,\nEscape to cancel.", pSong->m_sArtistTranslit, ChangeArtistTranslit, NULL ); sBGName = "";
break; break;
default: default:
ASSERT(0); ASSERT(0);
}; };
unsigned i;
for( i=0; i<m_pSong->m_BackgroundChanges.size(); i++ )
if( m_pSong->m_BackgroundChanges[i].m_fStartBeat == GAMESTATE->m_fSongBeat )
break;
if( i != m_pSong->m_BackgroundChanges.size() ) // there is already a BGChange here
m_pSong->m_BackgroundChanges.erase( m_pSong->m_BackgroundChanges.begin()+i,
m_pSong->m_BackgroundChanges.begin()+i+1);
// create a new BGChange
if( sBGName != "" )
m_pSong->AddBackgroundChange( BackgroundChange(GAMESTATE->m_fSongBeat, sBGName) );
} }
+1
View File
@@ -104,6 +104,7 @@ public:
enum MainMenuChoice { enum MainMenuChoice {
edit_notes_statistics, edit_notes_statistics,
play_whole_song, play_whole_song,
play_current_beat_to_end,
save, save,
player_options, player_options,
song_options, song_options,
+10 -3
View File
@@ -124,7 +124,7 @@ ScreenMiniMenu::ScreenMiniMenu( Menu* pDef, ScreenMessage SM_SendOnOK, ScreenMes
m_textAnswer[k].SetX( fAnswerX ); m_textAnswer[k].SetX( fAnswerX );
} }
SOUNDMAN->PlayOnce( THEME->GetPathTo("Sounds","ScreenMiniMenu music") ); SOUNDMAN->PlayOnce( THEME->GetPathTo("Sounds","Common prompt") );
} }
void ScreenMiniMenu::Update( float fDeltaTime ) void ScreenMiniMenu::Update( float fDeltaTime )
@@ -277,11 +277,18 @@ int ScreenMiniMenu::GetGoDownSpot()
bool ScreenMiniMenu::CanGoLeft() bool ScreenMiniMenu::CanGoLeft()
{ {
return m_iCurAnswers[m_iCurLine] != 0; int iNumInCurRow = m_Def.rows[m_iCurLine].choices.size();
if( iNumInCurRow==0 )
return false;
else
return m_iCurAnswers[m_iCurLine] != 0;
} }
bool ScreenMiniMenu::CanGoRight() bool ScreenMiniMenu::CanGoRight()
{ {
int iNumInCurRow = m_Def.rows[m_iCurLine].choices.size(); int iNumInCurRow = m_Def.rows[m_iCurLine].choices.size();
return m_iCurAnswers[m_iCurLine] != iNumInCurRow-1; if( iNumInCurRow==0 )
return false;
else
return m_iCurAnswers[m_iCurLine] != iNumInCurRow-1;
} }
+1 -1
View File
@@ -160,7 +160,7 @@ ScreenMusicScroll::ScreenMusicScroll()
for( i=0; i<min(arraySongs.size(), MAX_MUSIC_LINES); i++ ) for( i=0; i<min(arraySongs.size(), MAX_MUSIC_LINES); i++ )
{ {
Song* pSong = arraySongs[i]; Song* pSong = arraySongs[i];
m_textLines[m_iNumLines].LoadFromFont( THEME->GetPathTo("Fonts","music scroll") ); m_textLines[m_iNumLines].LoadFromFont( THEME->GetPathTo("Fonts","Screen MusicScroll titles") );
m_textLines[m_iNumLines].SetText( pSong->GetFullDisplayTitle(), pSong->GetFullTranslitTitle() ); m_textLines[m_iNumLines].SetText( pSong->GetFullDisplayTitle(), pSong->GetFullTranslitTitle() );
m_textLines[m_iNumLines].SetDiffuse( SONGMAN->GetSongColor(pSong) ); m_textLines[m_iNumLines].SetDiffuse( SONGMAN->GetSongColor(pSong) );
m_textLines[m_iNumLines].SetZoom( TEXT_ZOOM ); m_textLines[m_iNumLines].SetZoom( TEXT_ZOOM );
+1 -1
View File
@@ -79,7 +79,7 @@ ScreenPrompt::ScreenPrompt( ScreenMessage SM_SendWhenDone, CString sText, bool b
m_textAnswer[m_bAnswer].SetEffectGlowShift(); m_textAnswer[m_bAnswer].SetEffectGlowShift();
SOUNDMAN->PlayOnce( THEME->GetPathTo("Sounds","ScreenMenuPrompt music.mp3") ); SOUNDMAN->PlayOnce( THEME->GetPathTo("Sounds","Common prompt") );
} }
void ScreenPrompt::Update( float fDeltaTime ) void ScreenPrompt::Update( float fDeltaTime )
+1 -1
View File
@@ -70,7 +70,7 @@ ScreenTextEntry::ScreenTextEntry( ScreenMessage SM_SendWhenDone, CString sQuesti
UpdateText(); UpdateText();
this->AddChild( &m_textAnswer ); this->AddChild( &m_textAnswer );
SOUNDMAN->PlayOnce( THEME->GetPathTo("Sounds","menu prompt") ); SOUNDMAN->PlayOnce( THEME->GetPathTo("Sounds","Common prompt") );
} }
void ScreenTextEntry::UpdateText() void ScreenTextEntry::UpdateText()
+3 -1
View File
@@ -213,7 +213,9 @@ try_element_again:
* the default theme point to "_shared background", and themes override * the default theme point to "_shared background", and themes override
* just "_shared background"; the redirs in the default theme should end * just "_shared background"; the redirs in the default theme should end
* up resolving to the overridden background. */ * up resolving to the overridden background. */
CString sPath = GetPathTo(sAssetCategory, sNewFileName); /* Use GetPathToOptional because we don't want report that there's an element
* missing. Instead we want to report that the redirect is invalid. */
CString sPath = GetPathToOptional(sAssetCategory, sNewFileName);
if( !sPath.empty() ) if( !sPath.empty() )
return sPath; return sPath;
+2
View File
@@ -47,6 +47,8 @@ struct BackgroundChange
CString m_sBGName; CString m_sBGName;
}; };
void SortBackgroundChangesArray( vector<BackgroundChange> &arrayBackgroundChanges );
struct LyricSegment struct LyricSegment
{ {
LyricSegment() { m_fStartTime = -1; }; LyricSegment() { m_fStartTime = -1; };