reduce header file dependencies

This commit is contained in:
Chris Danford
2005-06-04 21:22:50 +00:00
parent 7386647ece
commit 3b61a74477
16 changed files with 293 additions and 201 deletions
+135 -29
View File
@@ -22,6 +22,7 @@
#include <float.h>
#include "XmlFile.h"
#include "BackgroundUtil.h"
#include "song.h"
ThemeMetric<float> LEFT_EDGE ("Background","LeftEdge");
ThemeMetric<float> TOP_EDGE ("Background","TopEdge");
@@ -35,6 +36,99 @@ ThemeMetric<float> CLAMP_OUTPUT_PERCENT ("Background","ClampOutputPercent");
static float g_fBackgroundCenterWidth = 40; // What is this for? -Chris
class BrightnessOverlay: public ActorFrame
{
public:
BrightnessOverlay();
void Update( float fDeltaTime );
void FadeToActualBrightness();
void SetActualBrightness();
void Set( float fBrightness );
private:
Quad m_quadBGBrightness[NUM_PLAYERS];
Quad m_quadBGBrightnessFade;
};
struct BackgroundTransition
{
apActorCommands cmdLeaves;
apActorCommands cmdRoot;
};
class BackgroundImpl : public ActorFrame
{
public:
BackgroundImpl();
~BackgroundImpl();
void Init();
virtual void LoadFromSong( const Song *pSong );
virtual void Unload();
virtual void Update( float fDeltaTime );
virtual void DrawPrimitives();
void FadeToActualBrightness() { m_Brightness.FadeToActualBrightness(); }
void SetBrightness( float fBrightness ) { m_Brightness.Set(fBrightness); } /* overrides pref and Cover */
DancingCharacters* GetDancingCharacters() { return m_pDancingCharacters; };
protected:
bool m_bInitted;
DancingCharacters* m_pDancingCharacters;
const Song *m_pSong;
map<CString,BackgroundTransition> m_mapNameToTransition;
deque<BackgroundDef> m_RandomBGAnimations; // random background to choose from. These may or may not be loaded into m_BGAnimations.
void LoadFromRandom( float fFirstBeat, float fLastBeat, const BackgroundChange &change );
bool IsDangerAllVisible();
class Layer
{
public:
Layer();
void Unload();
// return true if created and added to m_BGAnimations
bool CreateBackground( const Song *pSong, const BackgroundDef &bd );
// return def of the background that was created and added to m_BGAnimations. calls CreateBackground
BackgroundDef CreateRandomBGA( const Song *pSong, deque<BackgroundDef> &RandomBGAnimations );
int FindBGSegmentForBeat( float fBeat ) const;
void UpdateCurBGChange( const Song *pSong, float fLastMusicSeconds, float fCurrentTime, const map<CString,BackgroundTransition> &mapNameToTransition );
map<BackgroundDef,Actor*> m_BGAnimations;
vector<BackgroundChange> m_aBGChanges;
int m_iCurBGChangeIndex;
Actor *m_pCurrentBGA;
Actor *m_pFadingBGA;
float m_fSecsLeftInFade;
};
Layer m_Layer[NUM_BackgroundLayer];
float m_fLastMusicSeconds;
BGAnimation m_DangerPlayer[NUM_PLAYERS];
BGAnimation m_DangerAll;
BGAnimation m_DeadPlayer[NUM_PLAYERS];
// cover up the edge of animations that might hang outside of the background rectangle
Quad m_quadBorderLeft, m_quadBorderTop, m_quadBorderRight, m_quadBorderBottom;
BrightnessOverlay m_Brightness;
BackgroundDef STATIC_BACKGROUND_DEF;
};
static RageColor GetBrightnessColor( float fBrightnessPercent )
{
RageColor cBrightness = RageColor( 0,0,0,1-fBrightnessPercent );
@@ -51,14 +145,14 @@ static RageColor GetBrightnessColor( float fBrightnessPercent )
return ret;
}
Background::Background()
BackgroundImpl::BackgroundImpl()
{
m_bInitted = false;
m_pDancingCharacters = NULL;
m_pSong = NULL;
}
Background::Layer::Layer()
BackgroundImpl::Layer::Layer()
{
m_iCurBGChangeIndex = -1;
m_pCurrentBGA = NULL;
@@ -66,7 +160,7 @@ Background::Layer::Layer()
m_fSecsLeftInFade = 0;
}
void Background::Init()
void BackgroundImpl::Init()
{
if( m_bInitted )
return;
@@ -139,22 +233,22 @@ void Background::Init()
this->AddChild( &m_Brightness );
}
Background::~Background()
BackgroundImpl::~BackgroundImpl()
{
Unload();
delete m_pDancingCharacters;
}
void Background::Unload()
void BackgroundImpl::Unload()
{
for( int i=0; i<NUM_BACKGROUND_LAYERS; i++ )
FOREACH_BackgroundLayer( i )
m_Layer[i].Unload();
m_pSong = NULL;
m_fLastMusicSeconds = -9999;
m_RandomBGAnimations.clear();
}
void Background::Layer::Unload()
void BackgroundImpl::Layer::Unload()
{
for( map<BackgroundDef,Actor*>::iterator iter = m_BGAnimations.begin();
iter != m_BGAnimations.end();
@@ -201,7 +295,7 @@ Actor *MakeMovie( const CString &sMoviePath )
return pSprite;
}
bool Background::Layer::CreateBackground( const Song *pSong, const BackgroundDef &bd )
bool BackgroundImpl::Layer::CreateBackground( const Song *pSong, const BackgroundDef &bd )
{
ASSERT( m_BGAnimations.find(bd) == m_BGAnimations.end() );
@@ -300,7 +394,7 @@ bool Background::Layer::CreateBackground( const Song *pSong, const BackgroundDef
return true;
}
BackgroundDef Background::Layer::CreateRandomBGA( const Song *pSong, deque<BackgroundDef> &RandomBGAnimations )
BackgroundDef BackgroundImpl::Layer::CreateRandomBGA( const Song *pSong, deque<BackgroundDef> &RandomBGAnimations )
{
if( PREFSMAN->m_BackgroundMode == PrefsManager::BGMODE_OFF )
return BackgroundDef();
@@ -325,7 +419,7 @@ BackgroundDef Background::Layer::CreateRandomBGA( const Song *pSong, deque<Backg
return bd;
}
void Background::LoadFromRandom( float fFirstBeat, float fLastBeat, const BackgroundChange &change )
void BackgroundImpl::LoadFromRandom( float fFirstBeat, float fLastBeat, const BackgroundChange &change )
{
const TimingData &timing = m_pSong->m_Timing;
@@ -337,7 +431,7 @@ void Background::LoadFromRandom( float fFirstBeat, float fLastBeat, const Backgr
if( !bd.IsEmpty() )
{
BackgroundChange c = change;
(BackgroundDef&)c = bd;
c.m_def = bd;
c.m_fStartBeat = f;
m_Layer[0].m_aBGChanges.push_back( c );
}
@@ -360,14 +454,14 @@ void Background::LoadFromRandom( float fFirstBeat, float fLastBeat, const Backgr
if( !bd.IsEmpty() )
{
BackgroundChange c = change;
(BackgroundDef&)c = bd;
c.m_def = bd;
c.m_fStartBeat = NoteRowToBeat(bpmseg.m_iStartIndex);
m_Layer[0].m_aBGChanges.push_back( c );
}
}
}
void Background::LoadFromSong( const Song* pSong )
void BackgroundImpl::LoadFromSong( const Song* pSong )
{
Init();
Unload();
@@ -425,15 +519,15 @@ void Background::LoadFromSong( const Song* pSong )
if( pSong->HasBGChanges() )
{
for( int i=0; i<NUM_BACKGROUND_LAYERS; i++ )
FOREACH_BackgroundLayer( i )
{
Layer &layer = m_Layer[i];
// Load all song-specified backgrounds
FOREACH_CONST( BackgroundChange, pSong->m_BackgroundChanges[i], bgc )
FOREACH_CONST( BackgroundChange, pSong->GetBackgroundChanges(i), bgc )
{
BackgroundChange change = *bgc;
BackgroundDef &bd = change;
BackgroundDef &bd = change.m_def;
bool bIsAlreadyLoaded = layer.m_BGAnimations.find(bd) != layer.m_BGAnimations.end();
@@ -475,7 +569,7 @@ void Background::LoadFromSong( const Song* pSong )
// sort segments
for( int i=0; i<NUM_BACKGROUND_LAYERS; i++ )
FOREACH_BackgroundLayer( i )
{
Layer &layer = m_Layer[i];
BackgroundUtil::SortBackgroundChangesArray( layer.m_aBGChanges );
@@ -497,12 +591,12 @@ void Background::LoadFromSong( const Song* pSong )
// If any BGChanges use the background image, load it.
bool bStaticBackgroundUsed = false;
for( int i=0; i<NUM_BACKGROUND_LAYERS; i++ )
FOREACH_BackgroundLayer( i )
{
Layer &layer = m_Layer[i];
FOREACH_CONST( BackgroundChange, layer.m_aBGChanges, bgc )
{
const BackgroundDef &bd = *bgc;
const BackgroundDef &bd = bgc->m_def;
if( bd == STATIC_BACKGROUND_DEF )
{
bStaticBackgroundUsed = true;
@@ -524,7 +618,7 @@ void Background::LoadFromSong( const Song* pSong )
for( unsigned i=0; i<mainlayer.m_aBGChanges.size(); i++ )
{
const BackgroundChange change = mainlayer.m_aBGChanges[i];
if( change.m_sFile1 != RANDOM_BACKGROUND_FILE )
if( change.m_def.m_sFile1 != RANDOM_BACKGROUND_FILE )
continue;
const float fStartBeat = change.m_fStartBeat;
@@ -538,7 +632,7 @@ void Background::LoadFromSong( const Song* pSong )
// At this point, we shouldn't have any BGChanges to "". "" is an invalid name.
for( unsigned i=0; i<mainlayer.m_aBGChanges.size(); i++ )
ASSERT( !mainlayer.m_aBGChanges[i].m_sFile1.empty() );
ASSERT( !mainlayer.m_aBGChanges[i].m_def.m_sFile1.empty() );
// Re-sort.
@@ -587,7 +681,7 @@ void Background::LoadFromSong( const Song* pSong )
}
}
int Background::Layer::FindBGSegmentForBeat( float fBeat ) const
int BackgroundImpl::Layer::FindBGSegmentForBeat( float fBeat ) const
{
if( m_aBGChanges.empty() )
return -1;
@@ -606,7 +700,7 @@ int Background::Layer::FindBGSegmentForBeat( float fBeat ) const
}
/* If the BG segment has changed, move focus to it. Send Update() calls. */
void Background::Layer::UpdateCurBGChange( const Song *pSong, float fLastMusicSeconds, float fCurrentTime, const map<CString,BackgroundTransition> &mapNameToTransition )
void BackgroundImpl::Layer::UpdateCurBGChange( const Song *pSong, float fLastMusicSeconds, float fCurrentTime, const map<CString,BackgroundTransition> &mapNameToTransition )
{
ASSERT( fCurrentTime != GameState::MUSIC_SECONDS_INVALID );
@@ -634,7 +728,7 @@ void Background::Layer::UpdateCurBGChange( const Song *pSong, float fLastMusicSe
m_pFadingBGA = m_pCurrentBGA;
map<BackgroundDef,Actor*>::const_iterator iter = m_BGAnimations.find( (BackgroundDef)change );
map<BackgroundDef,Actor*>::const_iterator iter = m_BGAnimations.find( change.m_def );
ASSERT( iter != m_BGAnimations.end() );
m_pCurrentBGA = iter->second;
@@ -694,7 +788,7 @@ void Background::Layer::UpdateCurBGChange( const Song *pSong, float fLastMusicSe
m_pFadingBGA->Update( fDeltaTimeMusicRate );
}
void Background::Update( float fDeltaTime )
void BackgroundImpl::Update( float fDeltaTime )
{
ActorFrame::Update( fDeltaTime );
@@ -719,7 +813,7 @@ void Background::Update( float fDeltaTime )
* 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. */
for( int i=0; i<NUM_BACKGROUND_LAYERS; i++ )
FOREACH_BackgroundLayer( i )
{
Layer &layer = m_Layer[i];
layer.UpdateCurBGChange( m_pSong, m_fLastMusicSeconds, GAMESTATE->m_fMusicSeconds, m_mapNameToTransition );
@@ -727,7 +821,7 @@ void Background::Update( float fDeltaTime )
m_fLastMusicSeconds = GAMESTATE->m_fMusicSeconds;
}
void Background::DrawPrimitives()
void BackgroundImpl::DrawPrimitives()
{
if( PREFSMAN->m_fBGBrightness == 0.0f )
return;
@@ -745,7 +839,7 @@ void Background::DrawPrimitives()
if( m_pDancingCharacters )
m_pDancingCharacters->m_bDrawDangerLight = false;
for( int i=0; i<NUM_BACKGROUND_LAYERS; i++ )
FOREACH_BackgroundLayer( i )
{
Layer &layer = m_Layer[i];
if( layer.m_pCurrentBGA )
@@ -769,7 +863,7 @@ void Background::DrawPrimitives()
ActorFrame::DrawPrimitives();
}
bool Background::IsDangerAllVisible()
bool BackgroundImpl::IsDangerAllVisible()
{
FOREACH_PlayerNumber( p )
if( GAMESTATE->GetPlayerFailType(p) == SongOptions::FAIL_OFF )
@@ -859,6 +953,18 @@ void BrightnessOverlay::FadeToActualBrightness()
SetActualBrightness();
}
Background::Background() { m_pImpl = new BackgroundImpl; this->AddChild(m_pImpl); }
Background::~Background() { SAFE_DELETE( m_pImpl ); }
void Background::Init() { m_pImpl->Init(); }
void Background::LoadFromSong( const Song *pSong ) { m_pImpl->LoadFromSong(pSong); }
void Background::Unload() { m_pImpl->Unload(); }
void Background::FadeToActualBrightness() { m_pImpl->FadeToActualBrightness(); }
void Background::SetBrightness( float fBrightness ) { m_pImpl->SetBrightness(fBrightness); }
DancingCharacters* Background::GetDancingCharacters() { return m_pImpl->GetDancingCharacters(); }
/*
* (c) 2001-2004 Chris Danford, Ben Nordstrom
* All rights reserved.
+9 -76
View File
@@ -3,36 +3,17 @@
#ifndef BACKGROUND_H
#define BACKGROUND_H
#include "Sprite.h"
#include "Quad.h"
#include "ActorFrame.h"
#include "Quad.h"
#include "BGAnimation.h"
#include "song.h"
#include "PlayerNumber.h"
#include "BackgroundUtil.h"
#include <deque>
#include <map>
class DancingCharacters;
class BrightnessOverlay: public ActorFrame
{
public:
BrightnessOverlay();
void Update( float fDeltaTime );
void FadeToActualBrightness();
void SetActualBrightness();
void Set( float fBrightness );
private:
Quad m_quadBGBrightness[NUM_PLAYERS];
Quad m_quadBGBrightnessFade;
};
struct BackgroundTransition
{
apActorCommands cmdLeaves;
apActorCommands cmdRoot;
};
class Song;
class BackgroundImpl;
class Background : public ActorFrame
{
@@ -44,61 +25,13 @@ public:
virtual void LoadFromSong( const Song *pSong );
virtual void Unload();
virtual void Update( float fDeltaTime );
virtual void DrawPrimitives();
void FadeToActualBrightness() { m_Brightness.FadeToActualBrightness(); }
void SetBrightness( float fBrightness ) { m_Brightness.Set(fBrightness); } /* overrides pref and Cover */
DancingCharacters* GetDancingCharacters() { return m_pDancingCharacters; };
void FadeToActualBrightness();
void SetBrightness( float fBrightness ); /* overrides pref and Cover */
DancingCharacters* GetDancingCharacters();
protected:
bool m_bInitted;
DancingCharacters* m_pDancingCharacters;
const Song *m_pSong;
map<CString,BackgroundTransition> m_mapNameToTransition;
deque<BackgroundDef> m_RandomBGAnimations; // random background to choose from. These may or may not be loaded into m_BGAnimations.
void LoadFromRandom( float fFirstBeat, float fLastBeat, const BackgroundChange &change );
bool IsDangerAllVisible();
class Layer
{
public:
Layer();
void Unload();
// return true if created and added to m_BGAnimations
bool CreateBackground( const Song *pSong, const BackgroundDef &bd );
// return def of the background that was created and added to m_BGAnimations. calls CreateBackground
BackgroundDef CreateRandomBGA( const Song *pSong, deque<BackgroundDef> &RandomBGAnimations );
int FindBGSegmentForBeat( float fBeat ) const;
void UpdateCurBGChange( const Song *pSong, float fLastMusicSeconds, float fCurrentTime, const map<CString,BackgroundTransition> &mapNameToTransition );
map<BackgroundDef,Actor*> m_BGAnimations;
vector<BackgroundChange> 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];
// cover up the edge of animations that might hang outside of the background rectangle
Quad m_quadBorderLeft, m_quadBorderTop, m_quadBorderRight, m_quadBorderBottom;
BrightnessOverlay m_Brightness;
BackgroundDef STATIC_BACKGROUND_DEF;
BackgroundImpl *m_pImpl;
};
+1 -1
View File
@@ -185,7 +185,7 @@ void BackgroundUtil::GetGlobalRandomMovies( const Song *pSong, const CString &sM
if( !vsPathsOut.empty() )
goto found_files;
if( sMatch != "-nosongbg-" )
if( sMatch != NO_SONG_BG_FILE )
LOG->Warn( "Background missing: %s", sMatch.c_str() );
}
+7 -5
View File
@@ -12,7 +12,8 @@ const CString SBE_StretchRewind = "StretchRewind";
const CString SBT_CrossFade = "CrossFade";
const CString RANDOM_BACKGROUND_FILE = "-random-";
const CString SONG_BACKGROUND_FILE = "songbackground";
const CString NO_SONG_BG_FILE = "-nosongbg-";
const CString SONG_BACKGROUND_FILE = "songbackground";
struct BackgroundDef
{
@@ -41,7 +42,7 @@ struct BackgroundDef
CString m_sFile2; // may be ""
};
struct BackgroundChange : public BackgroundDef
struct BackgroundChange
{
BackgroundChange()
{
@@ -58,12 +59,13 @@ struct BackgroundChange : public BackgroundDef
)
{
m_fStartBeat=s;
m_sFile1=f1;
m_sFile2=f2;
m_def.m_sFile1=f1;
m_def.m_sFile2=f2;
m_fRate=r;
m_sEffect=e;
m_def.m_sEffect=e;
m_sTransition=t;
}
BackgroundDef m_def;
float m_fStartBeat;
float m_fRate;
CString m_sTransition;
+1
View File
@@ -3,6 +3,7 @@
#include "song.h"
#include "ThemeMetric.h"
#include "Command.h"
#include "RageUtil.h"
ThemeMetric<apActorCommands> ICONONCOMMAND ("DifficultyDisplay","IconOnCommand");
ThemeMetric<apActorCommands> ICONOFFCOMMAND ("DifficultyDisplay","IconOffCommand");
+5 -3
View File
@@ -6,6 +6,8 @@
#include "RageTextureManager.h"
#include "ActorUtil.h"
#include "song.h"
#include "BackgroundUtil.h"
#include "Foreach.h"
Foreground::~Foreground()
{
@@ -29,10 +31,10 @@ void Foreground::LoadFromSong( const Song *pSong )
TEXTUREMAN->SetDefaultTexturePolicy( RageTextureID::TEX_VOLATILE );
m_pSong = pSong;
for( unsigned i=0; i<pSong->m_ForegroundChanges.size(); i++ )
FOREACH_CONST( BackgroundChange, pSong->GetForegroundChanges(), bgc )
{
const BackgroundChange &change = pSong->m_ForegroundChanges[i];
CString sBGName = change.m_sFile1;
const BackgroundChange &change = *bgc;
CString sBGName = change.m_def.m_sFile1;
LoadedBGA bga;
bga.m_bga = ActorUtil::MakeActor( pSong->GetSongDir() + sBGName );
+1
View File
@@ -4,6 +4,7 @@
#include "ActorFrame.h"
class Song;
class Foreground: public ActorFrame
{
public:
+1
View File
@@ -2,6 +2,7 @@
#include "MusicList.h"
#include "ThemeManager.h"
#include "ThemeMetric.h"
#include "RageUtil.h"
/* If this actor is used anywhere other than SelectGroup, we
* can add a setting that changes which metric group we pull
+13 -12
View File
@@ -19,6 +19,7 @@
#include "Style.h"
#include "CommonMetrics.h"
#include <float.h>
#include "BackgroundUtil.h"
NoteField::NoteField()
{
@@ -533,18 +534,18 @@ void NoteField::DrawPrimitives()
break;
case EDIT_MODE_FULL:
{
vector<BackgroundChange>::iterator iter[NUM_BACKGROUND_LAYERS];
for( int i=0; i<NUM_BACKGROUND_LAYERS; i++ )
iter[i] = GAMESTATE->m_pCurSong->m_BackgroundChanges[i].begin();
vector<BackgroundChange>::iterator iter[NUM_BackgroundLayer];
FOREACH_BackgroundLayer( i )
iter[i] = GAMESTATE->m_pCurSong->GetBackgroundChanges(i).begin();
while( 1 )
{
float fLowestBeat = FLT_MAX;
vector<int> viLowestIndex;
vector<BackgroundLayer> viLowestIndex;
for( int i=0; i<NUM_BACKGROUND_LAYERS; i++ )
FOREACH_BackgroundLayer( i )
{
if( iter[i] == GAMESTATE->m_pCurSong->m_BackgroundChanges[i].end() )
if( iter[i] == GAMESTATE->m_pCurSong->GetBackgroundChanges(i).end() )
continue;
float fBeat = iter[i]->m_fStartBeat;
@@ -566,23 +567,23 @@ void NoteField::DrawPrimitives()
if( IS_ON_SCREEN(fLowestBeat) )
{
vector<CString> vs;
FOREACH_CONST( int, viLowestIndex, i )
FOREACH_CONST( BackgroundLayer, viLowestIndex, i )
{
ASSERT( iter[*i] != GAMESTATE->m_pCurSong->m_BackgroundChanges[*i].end() );
ASSERT( iter[*i] != GAMESTATE->m_pCurSong->GetBackgroundChanges(*i).end() );
const BackgroundChange& change = *iter[*i];
vs.push_back( ssprintf("%s%s%s%s%s%s",
((*i!=0) ? ssprintf("%d: ",*i) : CString()).c_str(),
(!change.m_sFile1.empty() ? " "+change.m_sFile1 : CString()).c_str(),
(!change.m_sFile2.empty() ? " "+change.m_sFile2 : CString()).c_str(),
(!change.m_def.m_sFile1.empty() ? " "+change.m_def.m_sFile1 : CString()).c_str(),
(!change.m_def.m_sFile2.empty() ? " "+change.m_def.m_sFile2 : CString()).c_str(),
((change.m_fRate!=1.0f) ? ssprintf("%.2f%%",change.m_fRate*100) : CString()).c_str(),
(!change.m_sTransition.empty() ? " "+change.m_sTransition : CString()).c_str(),
(!change.m_sEffect.empty() ? " "+change.m_sEffect : CString()).c_str()
(!change.m_def.m_sEffect.empty() ? " "+change.m_def.m_sEffect : CString()).c_str()
) );
}
DrawBGChangeText( fLowestBeat, join("\n",vs) );
}
FOREACH_CONST( int, viLowestIndex, i )
FOREACH_CONST( BackgroundLayer, viLowestIndex, i )
iter[*i]++;
}
}
+11 -10
View File
@@ -8,6 +8,7 @@
#include "SongManager.h"
#include "RageFileManager.h"
#include "NoteTypes.h"
#include "BackgroundUtil.h"
#define MAX_EDIT_SIZE_BYTES 20*1024 // 20 KB
@@ -170,20 +171,20 @@ bool LoadFromBGChangesString( BackgroundChange &change, const CString &sBGChange
// m_sEffect may be overwritten by param 7 below.
if( bRewindMovie )
change.m_sEffect = SBE_StretchRewind;
change.m_def.m_sEffect = SBE_StretchRewind;
if( !bLoop )
change.m_sEffect = SBE_StretchNoLoop;
change.m_def.m_sEffect = SBE_StretchNoLoop;
}
if( aBGChangeValues.size() >= 9 )
{
change.m_sEffect = aBGChangeValues[6];
change.m_sFile2 = aBGChangeValues[7];
change.m_def.m_sEffect = aBGChangeValues[6];
change.m_def.m_sFile2 = aBGChangeValues[7];
change.m_sTransition = aBGChangeValues[8];
}
if( aBGChangeValues.size() >= 2 )
{
change.m_fStartBeat = strtof( aBGChangeValues[0], NULL );
change.m_sFile1 = aBGChangeValues[1];
change.m_def.m_sFile1 = aBGChangeValues[1];
return true;
}
else
@@ -334,10 +335,10 @@ bool SMLoader::LoadFromSMFile( CString sPath, Song &out )
else if( sValueName=="BGCHANGES" || sValueName=="ANIMATIONS" )
{
int iLayer = 0;
BackgroundLayer iLayer = BACKGROUND_LAYER_1;
sscanf( sValueName, "BGCHANGES%d", &iLayer );
if( iLayer < 0 && iLayer >= NUM_BACKGROUND_LAYERS )
if( iLayer < 0 && iLayer >= NUM_BackgroundLayer )
{
LOG->Warn( "The song file '%s' has a BGCHANGES tag '%s' that is out of range.", sPath.c_str(), sValueName.c_str() );
}
@@ -548,7 +549,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<BackgroundChange> &bg = song.m_BackgroundChanges[0];
vector<BackgroundChange> &bg = song.GetBackgroundChanges(BACKGROUND_LAYER_1);
if( !bg.empty() )
{
/* BGChanges have been sorted. On the odd chance that a BGChange exists
@@ -557,7 +558,7 @@ void SMLoader::TidyUpData( Song &song, bool cache )
for( unsigned i = 0; !bHasNoSongBgTag && i < bg.size(); ++i )
{
if( !bg[i].m_sFile1.CompareNoCase("-nosongbg-") )
if( !bg[i].m_def.m_sFile1.CompareNoCase(NO_SONG_BG_FILE) )
{
bg.erase( bg.begin()+i );
bHasNoSongBgTag = true;
@@ -578,7 +579,7 @@ void SMLoader::TidyUpData( Song &song, bool cache )
break;
/* If the last BGA is already the song BGA, don't add a duplicate. */
if( !bg.empty() && !bg.back().m_sFile1.CompareNoCase(song.m_sBackgroundFile) )
if( !bg.empty() && !bg.back().m_def.m_sFile1.CompareNoCase(song.m_sBackgroundFile) )
break;
if( !IsAFile( song.GetBackgroundPath() ) )
+12 -11
View File
@@ -11,19 +11,20 @@
#include <cstring>
#include <cerrno>
#include "Foreach.h"
#include "BackgroundUtil.h"
static CString BackgroundChangeToString( const BackgroundChange &bgc )
{
return ssprintf(
"%.3f=%s=%.3f=%d=%d=%d=%s=%s=%s,",
bgc.m_fStartBeat,
bgc.m_sFile1.c_str(),
bgc.m_def.m_sFile1.c_str(),
bgc.m_fRate,
bgc.m_sTransition == SBT_CrossFade, // backward compat
bgc.m_sEffect == SBE_StretchRewind, // backward compat
bgc.m_sEffect != SBE_StretchNoLoop, // backward compat
bgc.m_sEffect.c_str(),
bgc.m_sFile2.c_str(),
bgc.m_def.m_sEffect == SBE_StretchRewind, // backward compat
bgc.m_def.m_sEffect != SBE_StretchNoLoop, // backward compat
bgc.m_def.m_sEffect.c_str(),
bgc.m_def.m_sFile2.c_str(),
bgc.m_sTransition.c_str()
);
}
@@ -95,31 +96,31 @@ void NotesWriterSM::WriteGlobalTags( RageFile &f, const Song &out )
}
f.PutLine( ";" );
for( int b=0; b<NUM_BACKGROUND_LAYERS; b++ )
FOREACH_BackgroundLayer( b )
{
if( b==0 )
f.Write( "#BGCHANGES:" );
else if( out.m_BackgroundChanges[b].empty() )
else if( out.GetBackgroundChanges(b).empty() )
continue; // skip
else
f.Write( ssprintf("#BGCHANGES%d:", b) );
FOREACH_CONST( BackgroundChange, out.m_BackgroundChanges[b], bgc )
FOREACH_CONST( BackgroundChange, out.GetBackgroundChanges(b), bgc )
f.PutLine( BackgroundChangeToString(*bgc) );
/* 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() )
if( b==0 && !out.GetBackgroundChanges(b).empty() )
f.PutLine( "99999=-nosongbg-=1.000=0=0=0 // don't automatically add -songbackground-" );
f.PutLine( ";" );
}
if( out.m_ForegroundChanges.size() )
if( out.GetForegroundChanges().size() )
{
f.Write( "#FGCHANGES:" );
FOREACH_CONST( BackgroundChange, out.m_ForegroundChanges, bgc )
FOREACH_CONST( BackgroundChange, out.GetForegroundChanges(), bgc )
{
f.PutLine( BackgroundChangeToString(*bgc) );
}
+1
View File
@@ -10,6 +10,7 @@
#include "BitmapText.h"
#include "ActorUtil.h"
#include "SongUtil.h"
#include "RageUtil.h"
#define BACKGROUNDS_SPACING_X THEME->GetMetricF("ScreenCredits","BackgroundsSpacingX")
+28 -28
View File
@@ -2083,9 +2083,9 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector<int> &iAns
bool bAlreadyBGChangeHere = false;
int iLayer = 0;
BackgroundChange bgChange;
for( int l=0; l<NUM_BACKGROUND_LAYERS; l++ )
FOREACH_BackgroundLayer( l )
{
FOREACH( BackgroundChange, m_pSong->m_BackgroundChanges[l], bgc )
FOREACH( BackgroundChange, m_pSong->GetBackgroundChanges(l), bgc )
{
if( bgc->m_fStartBeat == GAMESTATE->m_fSongBeat )
{
@@ -2114,24 +2114,24 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector<int> &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[transition]. SetDefaultChoiceIfPresent( bgChange.m_sTransition );
g_BackgroundChange.rows[effect]. SetDefaultChoiceIfPresent( bgChange.m_sEffect );
g_BackgroundChange.rows[layer]. SetDefaultChoiceIfPresent( ssprintf("%d",iLayer) );
g_BackgroundChange.rows[rate]. SetDefaultChoiceIfPresent( ssprintf("%2.0f%%",bgChange.m_fRate*100) );
g_BackgroundChange.rows[transition]. SetDefaultChoiceIfPresent( bgChange.m_sTransition );
g_BackgroundChange.rows[effect]. SetDefaultChoiceIfPresent( bgChange.m_def.m_sEffect );
g_BackgroundChange.rows[file1_type].iDefaultChoice = none;
if( bgChange.m_sFile1 == RANDOM_BACKGROUND_FILE ) g_BackgroundChange.rows[file1_type].iDefaultChoice = pick_random;
if( g_BackgroundChange.rows[file1_song_bganimation]. SetDefaultChoiceIfPresent( bgChange.m_sFile1 ) ) g_BackgroundChange.rows[file1_type].iDefaultChoice = song_bganimation;
if( g_BackgroundChange.rows[file1_song_movie]. SetDefaultChoiceIfPresent( bgChange.m_sFile1 ) ) g_BackgroundChange.rows[file1_type].iDefaultChoice = song_movie;
if( g_BackgroundChange.rows[file1_song_still]. SetDefaultChoiceIfPresent( bgChange.m_sFile1 ) ) g_BackgroundChange.rows[file1_type].iDefaultChoice = song_bitmap;
if( g_BackgroundChange.rows[file1_global_bganimation]. SetDefaultChoiceIfPresent( bgChange.m_sFile1 ) ) g_BackgroundChange.rows[file1_type].iDefaultChoice = global_bganimation;
if( g_BackgroundChange.rows[file1_global_random_movie]. SetDefaultChoiceIfPresent( bgChange.m_sFile1 ) ) g_BackgroundChange.rows[file1_type].iDefaultChoice = global_movie;
if( bgChange.m_def.m_sFile1 == RANDOM_BACKGROUND_FILE ) g_BackgroundChange.rows[file1_type].iDefaultChoice = pick_random;
if( g_BackgroundChange.rows[file1_song_bganimation]. SetDefaultChoiceIfPresent( bgChange.m_def.m_sFile1 ) ) g_BackgroundChange.rows[file1_type].iDefaultChoice = song_bganimation;
if( g_BackgroundChange.rows[file1_song_movie]. SetDefaultChoiceIfPresent( bgChange.m_def.m_sFile1 ) ) g_BackgroundChange.rows[file1_type].iDefaultChoice = song_movie;
if( g_BackgroundChange.rows[file1_song_still]. SetDefaultChoiceIfPresent( bgChange.m_def.m_sFile1 ) ) g_BackgroundChange.rows[file1_type].iDefaultChoice = song_bitmap;
if( g_BackgroundChange.rows[file1_global_bganimation]. SetDefaultChoiceIfPresent( bgChange.m_def.m_sFile1 ) ) g_BackgroundChange.rows[file1_type].iDefaultChoice = global_bganimation;
if( g_BackgroundChange.rows[file1_global_random_movie]. SetDefaultChoiceIfPresent( bgChange.m_def.m_sFile1 ) ) g_BackgroundChange.rows[file1_type].iDefaultChoice = global_movie;
g_BackgroundChange.rows[file2_type].iDefaultChoice = none;
if( bgChange.m_sFile2 == RANDOM_BACKGROUND_FILE ) g_BackgroundChange.rows[file2_type].iDefaultChoice = pick_random;
if( g_BackgroundChange.rows[file2_song_bganimation]. SetDefaultChoiceIfPresent( bgChange.m_sFile2 ) ) g_BackgroundChange.rows[file2_type].iDefaultChoice = song_bganimation;
if( g_BackgroundChange.rows[file2_song_movie]. SetDefaultChoiceIfPresent( bgChange.m_sFile2 ) ) g_BackgroundChange.rows[file2_type].iDefaultChoice = song_movie;
if( g_BackgroundChange.rows[file2_song_still]. SetDefaultChoiceIfPresent( bgChange.m_sFile2 ) ) g_BackgroundChange.rows[file2_type].iDefaultChoice = song_bitmap;
if( g_BackgroundChange.rows[file2_global_bganimation]. SetDefaultChoiceIfPresent( bgChange.m_sFile2 ) ) g_BackgroundChange.rows[file2_type].iDefaultChoice = global_bganimation;
if( g_BackgroundChange.rows[file2_global_random_movie]. SetDefaultChoiceIfPresent( bgChange.m_sFile2 ) ) g_BackgroundChange.rows[file2_type].iDefaultChoice = global_movie;
if( bgChange.m_def.m_sFile2 == RANDOM_BACKGROUND_FILE ) g_BackgroundChange.rows[file2_type].iDefaultChoice = pick_random;
if( g_BackgroundChange.rows[file2_song_bganimation]. SetDefaultChoiceIfPresent( bgChange.m_def.m_sFile2 ) ) g_BackgroundChange.rows[file2_type].iDefaultChoice = song_bganimation;
if( g_BackgroundChange.rows[file2_song_movie]. SetDefaultChoiceIfPresent( bgChange.m_def.m_sFile2 ) ) g_BackgroundChange.rows[file2_type].iDefaultChoice = song_movie;
if( g_BackgroundChange.rows[file2_song_still]. SetDefaultChoiceIfPresent( bgChange.m_def.m_sFile2 ) ) g_BackgroundChange.rows[file2_type].iDefaultChoice = song_bitmap;
if( g_BackgroundChange.rows[file2_global_bganimation]. SetDefaultChoiceIfPresent( bgChange.m_def.m_sFile2 ) ) g_BackgroundChange.rows[file2_type].iDefaultChoice = global_bganimation;
if( g_BackgroundChange.rows[file2_global_random_movie]. SetDefaultChoiceIfPresent( bgChange.m_def.m_sFile2 ) ) g_BackgroundChange.rows[file2_type].iDefaultChoice = global_movie;
SCREENMAN->MiniMenu( &g_BackgroundChange, SM_BackFromBGChange );
@@ -2643,16 +2643,16 @@ void ScreenEdit::HandleSongInformationChoice( SongInformationChoice c, const vec
void ScreenEdit::HandleBGChangeChoice( BGChangeChoice c, const vector<int> &iAnswers )
{
int iLayer = atoi( g_BackgroundChange.rows[layer].choices[iAnswers[layer]] );
BackgroundLayer iLayer = (BackgroundLayer)atoi( g_BackgroundChange.rows[layer].choices[iAnswers[layer]] );
BackgroundChange newChange;
FOREACH( BackgroundChange, m_pSong->m_BackgroundChanges[iLayer], iter )
FOREACH( BackgroundChange, m_pSong->GetBackgroundChanges(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[iLayer].erase( iter );
m_pSong->GetBackgroundChanges(iLayer).erase( iter );
break;
}
}
@@ -2663,12 +2663,12 @@ void ScreenEdit::HandleBGChangeChoice( BGChangeChoice c, const vector<int> &iAns
newChange.m_fStartBeat = GAMESTATE->m_fSongBeat;
newChange.m_fRate = strtof( g_BackgroundChange.rows[rate].choices[iAnswers[rate]], NULL )/100.f;
newChange.m_sTransition = g_BackgroundChange.rows[transition].choices[iAnswers[transition]];
newChange.m_sEffect = g_BackgroundChange.rows[effect].choices[iAnswers[effect]];
newChange.m_def.m_sEffect = g_BackgroundChange.rows[effect].choices[iAnswers[effect]];
switch( iAnswers[file1_type] )
{
default: ASSERT(0);
case none: newChange.m_sFile1 = ""; break;
case pick_random: newChange.m_sFile1 = RANDOM_BACKGROUND_FILE; break;
case none: newChange.m_def.m_sFile1 = ""; break;
case pick_random: newChange.m_def.m_sFile1 = RANDOM_BACKGROUND_FILE; break;
case song_bganimation:
case song_movie:
case song_bitmap:
@@ -2676,15 +2676,15 @@ void ScreenEdit::HandleBGChangeChoice( BGChangeChoice c, const vector<int> &iAns
case global_movie:
{
BGChangeChoice row1 = (BGChangeChoice)(file1_song_bganimation + iAnswers[file1_type]-2);
newChange.m_sFile1 = g_BackgroundChange.rows[row1].choices[iAnswers[row1]];
newChange.m_def.m_sFile1 = g_BackgroundChange.rows[row1].choices[iAnswers[row1]];
}
break;
}
switch( iAnswers[file2_type] )
{
default: ASSERT(0);
case none: newChange.m_sFile2 = ""; break;
case pick_random: newChange.m_sFile2 = RANDOM_BACKGROUND_FILE; break;
case none: newChange.m_def.m_sFile2 = ""; break;
case pick_random: newChange.m_def.m_sFile2 = RANDOM_BACKGROUND_FILE; break;
case song_bganimation:
case song_movie:
case song_bitmap:
@@ -2692,7 +2692,7 @@ void ScreenEdit::HandleBGChangeChoice( BGChangeChoice c, const vector<int> &iAns
case global_movie:
{
BGChangeChoice row2 = (BGChangeChoice)(file2_song_bganimation + iAnswers[file2_type]-2);
newChange.m_sFile2 = g_BackgroundChange.rows[row2].choices[iAnswers[row2]];
newChange.m_def.m_sFile2 = g_BackgroundChange.rows[row2].choices[iAnswers[row2]];
}
break;
}
+43 -15
View File
@@ -24,6 +24,7 @@
#include "ProfileManager.h"
#include "Foreach.h"
#include "UnlockManager.h"
#include "BackgroundUtil.h"
#include "NotesLoaderSM.h"
#include "NotesLoaderDWI.h"
@@ -49,6 +50,11 @@ const float DEFAULT_MUSIC_SAMPLE_LENGTH = 12.f;
//////////////////////////////
Song::Song()
{
FOREACH_BackgroundLayer( i )
m_BackgroundChanges[i] = new vector<BackgroundChange>;
m_ForegroundChanges = new vector<BackgroundChange>;
m_LoadedFromProfile = PROFILE_SLOT_INVALID;
m_fMusicSampleStartSeconds = -1;
m_fMusicSampleLengthSeconds = DEFAULT_MUSIC_SAMPLE_LENGTH;
@@ -66,6 +72,10 @@ Song::Song()
Song::~Song()
{
FOREACH_BackgroundLayer( i )
SAFE_DELETE( m_BackgroundChanges[i] );
SAFE_DELETE( m_ForegroundChanges );
FOREACH( Steps*, m_vpSteps, s )
SAFE_DELETE( *s );
m_vpSteps.clear();
@@ -98,17 +108,17 @@ void Song::Reset()
}
void Song::AddBackgroundChange( int iLayer, BackgroundChange seg )
void Song::AddBackgroundChange( BackgroundLayer iLayer, BackgroundChange seg )
{
ASSERT( iLayer >= 0 && iLayer < NUM_BACKGROUND_LAYERS );
m_BackgroundChanges[iLayer].push_back( seg );
BackgroundUtil::SortBackgroundChangesArray( m_BackgroundChanges[iLayer] );
ASSERT( iLayer >= 0 && iLayer < NUM_BackgroundLayer );
GetBackgroundChanges(iLayer).push_back( seg );
BackgroundUtil::SortBackgroundChangesArray( GetBackgroundChanges(iLayer) );
}
void Song::AddForegroundChange( BackgroundChange seg )
{
m_ForegroundChanges.push_back( seg );
BackgroundUtil::SortBackgroundChangesArray( m_ForegroundChanges );
GetForegroundChanges().push_back( seg );
BackgroundUtil::SortBackgroundChangesArray( GetForegroundChanges() );
}
void Song::AddLyricSegment( LyricSegment seg )
@@ -132,13 +142,12 @@ void Song::GetDisplayBpms( DisplayBpms &AddTo ) const
}
}
const BackgroundChange &Song::GetBackgroundAtBeat( int iLayer, float fBeat ) const
const BackgroundChange &Song::GetBackgroundAtBeat( BackgroundLayer iLayer, float fBeat ) const
{
unsigned i;
for( i=0; i<m_BackgroundChanges[iLayer].size()-1; i++ )
if( m_BackgroundChanges[iLayer][i+1].m_fStartBeat > fBeat )
break;
return m_BackgroundChanges[iLayer][i];
for( unsigned i=0; i<GetBackgroundChanges(iLayer).size()-1; i++ )
if( GetBackgroundChanges(iLayer)[i+1].m_fStartBeat > fBeat )
return GetBackgroundChanges(iLayer)[i];
return GetBackgroundChanges(iLayer)[0];
}
@@ -709,7 +718,7 @@ void Song::TidyUpData()
/* Use this->GetBeatFromElapsedTime(0) instead of 0 to start when the
* music starts. */
if( arrayPossibleMovies.size() == 1 )
this->AddBackgroundChange( 0, BackgroundChange(0,arrayPossibleMovies[0],"",1.f,SBE_StretchNoLoop) );
this->AddBackgroundChange( BACKGROUND_LAYER_1, BackgroundChange(0,arrayPossibleMovies[0],"",1.f,SBE_StretchNoLoop) );
}
@@ -1200,14 +1209,33 @@ bool Song::HasBackground() const {return m_sBackgroundFile != "" && IsAFile(G
bool Song::HasCDTitle() const {return m_sCDTitleFile != "" && IsAFile(GetCDTitlePath()); }
bool Song::HasBGChanges() const
{
for( int i=0; i<NUM_BACKGROUND_LAYERS; i++ )
FOREACH_BackgroundLayer( i )
{
if( !m_BackgroundChanges[i].empty() )
if( !GetBackgroundChanges(i).empty() )
return true;
}
return false;
}
const vector<BackgroundChange> &Song::GetBackgroundChanges( BackgroundLayer bl ) const
{
return *(m_BackgroundChanges[bl]);
}
vector<BackgroundChange> &Song::GetBackgroundChanges( BackgroundLayer bl )
{
return *(m_BackgroundChanges[bl]);
}
const vector<BackgroundChange> &Song::GetForegroundChanges() const
{
return *m_ForegroundChanges;
}
vector<BackgroundChange> &Song::GetForegroundChanges()
{
return *m_ForegroundChanges;
}
CString GetSongAssetPath( CString sPath, const CString &sSongPath )
{
if( sPath == "" )
+4 -3
View File
@@ -29,6 +29,7 @@
#include "Foreach.h"
#include "StatsManager.h"
#include "Style.h"
#include "BackgroundUtil.h"
SongManager* SONGMAN = NULL; // global and accessable from anywhere in our program
@@ -232,7 +233,7 @@ void SongManager::LoadStepManiaSongDir( CString sDir, LoadingWindow *ld )
}
}
// Why Symlink instead of allowing membership in multiple groups via song tags?
// Instead of "symlinks", songs should have membership in multiple groups.
// -Chris
void SongManager::LoadGroupSymLinks(CString sDir, CString sGroupFolder)
{
@@ -257,8 +258,8 @@ void SongManager::LoadGroupSymLinks(CString sDir, CString sGroupFolder)
while( vpSteps.size() )
pNewSong->RemoveSteps( vpSteps[0] );
for( int i=0; i<NUM_BACKGROUND_LAYERS; i++ )
pNewSong->m_BackgroundChanges[i].clear();
FOREACH_BackgroundLayer( i )
pNewSong->GetBackgroundChanges(i).clear();
pNewSong->m_bIsSymLink = true; // Very important so we don't double-parse later
pNewSong->m_sGroupName = sGroupFolder;
+21 -8
View File
@@ -3,11 +3,9 @@
#ifndef SONG_H
#define SONG_H
#include "PlayerNumber.h"
#include "BackgroundUtil.h"
#include "Grade.h"
#include "TimingData.h"
#include "Difficulty.h"
#include "EnumHelper.h"
class Steps;
class Style;
@@ -16,13 +14,20 @@ class LyricsLoader;
class Profile;
class StepsID;
struct lua_State;
struct BackgroundChange;
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;
enum BackgroundLayer
{
BACKGROUND_LAYER_1,
BACKGROUND_LAYER_2,
NUM_BackgroundLayer
};
#define FOREACH_BackgroundLayer( bl ) FOREACH_ENUM( BackgroundLayer, NUM_BackgroundLayer, bl )
struct LyricSegment
{
@@ -141,18 +146,26 @@ public:
bool Matches(CString sGroup, CString sSong) const;
TimingData m_Timing;
vector<BackgroundChange> m_BackgroundChanges[NUM_BACKGROUND_LAYERS]; // these must be sorted before gameplay
vector<BackgroundChange> m_ForegroundChanges; // this must be sorted before gameplay
private:
vector<BackgroundChange> *m_BackgroundChanges[NUM_BackgroundLayer]; // these must be sorted before gameplay
vector<BackgroundChange> *m_ForegroundChanges; // this must be sorted before gameplay
public:
const vector<BackgroundChange> &GetBackgroundChanges( BackgroundLayer bl ) const;
vector<BackgroundChange> &GetBackgroundChanges( BackgroundLayer bl );
const vector<BackgroundChange> &GetForegroundChanges() const;
vector<BackgroundChange> &GetForegroundChanges();
vector<LyricSegment> 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( int iLayer, BackgroundChange seg );
void AddBackgroundChange( BackgroundLayer blLayer, BackgroundChange seg );
void AddForegroundChange( BackgroundChange seg );
void AddLyricSegment( LyricSegment seg );
void GetDisplayBpms( DisplayBpms &AddTo ) const;
const BackgroundChange &GetBackgroundAtBeat( int iLayer, float fBeat ) const;
const BackgroundChange &GetBackgroundAtBeat( BackgroundLayer 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 ); }