diff --git a/stepmania/src/GraphDisplay.cpp b/stepmania/src/GraphDisplay.cpp index 4a2ca52152..46070d9d55 100644 --- a/stepmania/src/GraphDisplay.cpp +++ b/stepmania/src/GraphDisplay.cpp @@ -5,6 +5,8 @@ #include "RageDisplay.h" #include "RageUtil.h" #include "StageStats.h" +#include "Foreach.h" +#include "Song.h" //#define DIVIDE_LINE_WIDTH THEME->GetMetricI(m_sName,"TexturedBottomHalf") @@ -14,7 +16,7 @@ GraphDisplay::GraphDisplay() } -void GraphDisplay::Load( const CString &TexturePath, float height ) +void GraphDisplay::Load( const CString &TexturePath, float fInitialHeight, const CString &sJustBarelyPath ) { m_Position = 1; memset( m_CurValues, 0, sizeof(m_CurValues) ); @@ -27,8 +29,10 @@ void GraphDisplay::Load( const CString &TexturePath, float height ) m_size.y = (float) m_pTexture->GetSourceHeight(); for( int i = 0; i < VALUE_RESOLUTION; ++i ) - m_CurValues[i] = height; + m_CurValues[i] = fInitialHeight; UpdateVerts(); + + m_sprJustBarely.Load( sJustBarelyPath ); } void GraphDisplay::Unload() @@ -37,35 +41,92 @@ void GraphDisplay::Unload() TEXTUREMAN->UnloadTexture( m_pTexture ); m_pTexture = NULL; + + m_sprJustBarely.Unload(); + FOREACH( AutoActor*, m_vpSongBoundaries, p ) + SAFE_DELETE( *p ); + m_vpSongBoundaries.clear(); + + ActorFrame::RemoveAllChildren(); } -void GraphDisplay::LoadFromStageStats( const StageStats &ss, const PlayerStageStats &pss ) +void GraphDisplay::LoadFromStageStats( const StageStats &ss, const PlayerStageStats &pss, const CString &sSongBoundaryPath ) { + float fTotalStepSeconds = ss.GetTotalPossibleStepsSeconds(); + memcpy( m_LastValues, m_CurValues, sizeof(m_CurValues) ); m_Position = 0; pss.GetLifeRecord( m_DestValues, VALUE_RESOLUTION, ss.GetTotalPossibleStepsSeconds() ); for( unsigned i=0; ifirst; + float fLife = i->second; + if( fLife < fMinLifeSoFar ) + { + fMinLifeSoFar = fLife; + fMinLifeSoFarAtSecond = fSec; + } + } + + if( fMinLifeSoFar < 0.1f ) + { + float fX = SCALE( fMinLifeSoFarAtSecond, 0, fTotalStepSeconds, m_quadVertices.left, m_quadVertices.right ); + fX = Quantize( fX, 1.0f ); + m_sprJustBarely->SetXY( fX, 0 ); + } + else + { + m_sprJustBarely->SetHidden( true ); + } + this->AddChild( m_sprJustBarely ); + } + + // + // Show song boundaries + // + float fSec = 0; + FOREACH_CONST( Song*, ss.vpPossibleSongs, song ) + { + if( song == ss.vpPossibleSongs.end()-1 ) + continue; + fSec += (*song)->GetStepsSeconds(); + + AutoActor *p = new AutoActor; + m_vpSongBoundaries.push_back( p ); + p->Load( sSongBoundaryPath ); + float fX = SCALE( fSec, 0, fTotalStepSeconds, m_quadVertices.left, m_quadVertices.right ); + (*p)->SetX( fX ); + this->AddChild( *p ); + } } void GraphDisplay::UpdateVerts() { - RectF quadVertices; - switch( m_HorizAlign ) { - case align_left: quadVertices.left = 0; quadVertices.right = m_size.x; break; - case align_center: quadVertices.left = -m_size.x/2; quadVertices.right = m_size.x/2; break; - case align_right: quadVertices.left = -m_size.x; quadVertices.right = 0; break; + case align_left: m_quadVertices.left = 0; m_quadVertices.right = m_size.x; break; + case align_center: m_quadVertices.left = -m_size.x/2; m_quadVertices.right = m_size.x/2; break; + case align_right: m_quadVertices.left = -m_size.x; m_quadVertices.right = 0; break; default: ASSERT( false ); } switch( m_VertAlign ) { - case align_top: quadVertices.top = 0; quadVertices.bottom = m_size.y; break; - case align_middle: quadVertices.top = -m_size.y/2; quadVertices.bottom = m_size.y/2; break; - case align_bottom: quadVertices.top = -m_size.y; quadVertices.bottom = 0; break; + case align_top: m_quadVertices.top = 0; m_quadVertices.bottom = m_size.y; break; + case align_middle: m_quadVertices.top = -m_size.y/2; m_quadVertices.bottom = m_size.y/2; break; + case align_bottom: m_quadVertices.top = -m_size.y; m_quadVertices.bottom = 0; break; default: ASSERT(0); } @@ -76,14 +137,14 @@ void GraphDisplay::UpdateVerts() for( int i = 0; i < NumSlices; ++i ) { - const float Left = SCALE( float(i), 0.0f, float(NumSlices), quadVertices.left, quadVertices.right ); - const float Right = SCALE( float(i+1), 0.0f, float(NumSlices), quadVertices.left, quadVertices.right ); - const float LeftTop = SCALE( float(m_CurValues[i]), 0.0f, 1.0f, quadVertices.bottom, quadVertices.top ); - const float RightTop = SCALE( float(m_CurValues[i+1]), 0.0f, 1.0f, quadVertices.bottom, quadVertices.top ); + const float Left = SCALE( float(i), 0.0f, float(NumSlices), m_quadVertices.left, m_quadVertices.right ); + const float Right = SCALE( float(i+1), 0.0f, float(NumSlices), m_quadVertices.left, m_quadVertices.right ); + const float LeftTop = SCALE( float(m_CurValues[i]), 0.0f, 1.0f, m_quadVertices.bottom, m_quadVertices.top ); + const float RightTop = SCALE( float(m_CurValues[i+1]), 0.0f, 1.0f, m_quadVertices.bottom, m_quadVertices.top ); Slices[i*4+0].p = RageVector3( Left, LeftTop, 0 ); // top left - Slices[i*4+1].p = RageVector3( Left, quadVertices.bottom, 0 ); // bottom left - Slices[i*4+2].p = RageVector3( Right, quadVertices.bottom, 0 ); // bottom right + Slices[i*4+1].p = RageVector3( Left, m_quadVertices.bottom, 0 ); // bottom left + Slices[i*4+2].p = RageVector3( Right, m_quadVertices.bottom, 0 ); // bottom right Slices[i*4+3].p = RageVector3( Right, RightTop, 0 ); // top right // Slices[i*4+0].c = RageColor(.2,.2,.2,1); @@ -93,17 +154,12 @@ void GraphDisplay::UpdateVerts() } const RectF *tex = m_pTexture->GetTextureCoordRect( 0 ); - for( int i = 0; i < NumSlices; ++i ) + for( int i = 0; i < ARRAYSIZE(Slices); ++i ) { - const float Left = SCALE( float(i), 0.0f, float(NumSlices), tex->left, tex->right ); - const float Right = SCALE( float(i+1), 0.0f, float(NumSlices), tex->left, tex->right ); - const float LeftTop = SCALE( float(m_CurValues[i]), 0.0f, 1.0f, tex->bottom, tex->top ); - const float RightTop = SCALE( float(m_CurValues[i+1]), 0.0f, 1.0f, tex->bottom, tex->top ); - - Slices[i*4+0].t = RageVector2( Left, LeftTop ); // top left - Slices[i*4+1].t = RageVector2( Left, tex->bottom ); // bottom left - Slices[i*4+2].t = RageVector2( Right, tex->bottom ); // bottom right - Slices[i*4+3].t = RageVector2( Right, RightTop ); // top right + Slices[i].t = RageVector2( + SCALE( Slices[i].p.x, m_quadVertices.left, m_quadVertices.right, tex->left, tex->right ), + SCALE( Slices[i].p.y, m_quadVertices.top, m_quadVertices.bottom, tex->top, tex->bottom ) + ); } } @@ -132,6 +188,8 @@ void GraphDisplay::DrawPrimitives() DISPLAY->DrawQuads( Slices, ARRAYSIZE(Slices) ); DISPLAY->SetTexture( 0, NULL ); + + ActorFrame::DrawPrimitives(); } /* diff --git a/stepmania/src/GraphDisplay.h b/stepmania/src/GraphDisplay.h index dd4f1bdc96..e8bc397cc0 100644 --- a/stepmania/src/GraphDisplay.h +++ b/stepmania/src/GraphDisplay.h @@ -3,6 +3,7 @@ #include "ActorFrame.h" #include "RageTexture.h" +#include "AutoActor.h" struct StageStats; struct PlayerStageStats; @@ -12,10 +13,10 @@ class GraphDisplay: public ActorFrame public: GraphDisplay(); ~GraphDisplay() { Unload(); } - void Load( const CString &TexturePath, float height ); + void Load( const CString &sTexturePath, float fInitialHeight, const CString &sJustBarelyPath ); void Unload(); - void LoadFromStageStats( const StageStats &ss, const PlayerStageStats &s ); + void LoadFromStageStats( const StageStats &ss, const PlayerStageStats &s, const CString &sSongBoundaryPath ); void Update( float fDeltaTime ); void DrawPrimitives(); @@ -28,9 +29,13 @@ private: float m_LastValues[VALUE_RESOLUTION]; float m_Position; + RectF m_quadVertices; RageSpriteVertex Slices[4*(VALUE_RESOLUTION-1)]; RageTexture *m_pTexture; + + AutoActor m_sprJustBarely; + vector m_vpSongBoundaries; }; #endif diff --git a/stepmania/src/ScreenEvaluation.cpp b/stepmania/src/ScreenEvaluation.cpp index b426f20fa9..711ef4d2ff 100644 --- a/stepmania/src/ScreenEvaluation.cpp +++ b/stepmania/src/ScreenEvaluation.cpp @@ -70,7 +70,7 @@ const char* STATS_STRING[NUM_STATS_LINES] = #define SHOW_COMBO_AREA THEME->GetMetricB(m_sName,"ShowComboArea") #define SHOW_PER_DIFFICULTY_AWARD THEME->GetMetricB(m_sName,"ShowPerDifficultyAward") #define SHOW_PEAK_COMBO_AWARD THEME->GetMetricB(m_sName,"ShowPeakComboAward") -#define GRAPH_START_HEIGHT THEME->GetMetricF(m_sName,"GraphStartHeight") +#define LIFE_GRAPH_START_HEIGHT THEME->GetMetricF(m_sName,"LifeGraphStartHeight") #define TYPE THEME->GetMetric (m_sName,"Type") #define PASSED_SOUND_TIME THEME->GetMetricF(m_sName,"PassedSoundTime") #define FAILED_SOUND_TIME THEME->GetMetricF(m_sName,"FailedSoundTime") @@ -454,8 +454,8 @@ void ScreenEvaluation::Init() this->AddChild( m_sprGraphFrame[p] ); m_LifeGraph[p].SetName( ssprintf("LifeGraphP%i",p+1) ); - m_LifeGraph[p].Load( THEME->GetPathG(m_sName,ssprintf("LifeGraph p%i", p+1)), GRAPH_START_HEIGHT ); - m_LifeGraph[p].LoadFromStageStats( stageStats, stageStats.m_player[p] ); + m_LifeGraph[p].Load( THEME->GetPathG(m_sName,ssprintf("LifeGraph p%i", p+1)), LIFE_GRAPH_START_HEIGHT, THEME->GetPathG(m_sName,"JustBarely") ); + m_LifeGraph[p].LoadFromStageStats( stageStats, stageStats.m_player[p], THEME->GetPathG(m_sName,"SongBoundary") ); SET_XY_AND_ON_COMMAND( m_LifeGraph[p] ); this->AddChild( &m_LifeGraph[p] ); } @@ -468,7 +468,6 @@ void ScreenEvaluation::Init() m_ComboGraph[p].SetName( m_sName, ssprintf("ComboGraphP%i",p+1) ); m_ComboGraph[p].Load( m_sName, ssprintf("ComboGraph p%i",p+1), stageStats, stageStats.m_player[p] ); SET_XY_AND_ON_COMMAND( m_ComboGraph[p] ); - this->AddChild( &m_ComboGraph[p] ); } } diff --git a/stepmania/src/Song.cpp b/stepmania/src/Song.cpp index 6f052a2118..35ecd3e25b 100644 --- a/stepmania/src/Song.cpp +++ b/stepmania/src/Song.cpp @@ -1417,6 +1417,11 @@ bool Song::HasSignificantBpmChangesOrStops() const return m_Timing.HasBpmChangesOrStops(); } +float Song::GetStepsSeconds() const +{ + return GetElapsedTimeFromBeat( m_fLastBeat ) - GetElapsedTimeFromBeat( m_fFirstBeat ); +} + bool Song::IsEditDescriptionUnique( StepsType st, CString sPreferredDescription, const Steps *pExclude ) const { FOREACH_CONST( Steps*, m_vpSteps, s ) diff --git a/stepmania/src/StageStats.cpp b/stepmania/src/StageStats.cpp index be9ad88a56..d624453446 100644 --- a/stepmania/src/StageStats.cpp +++ b/stepmania/src/StageStats.cpp @@ -97,7 +97,7 @@ float StageStats::GetTotalPossibleStepsSeconds() const { float fSecs = 0; FOREACH_CONST( Song*, vpPossibleSongs, s ) - fSecs += (*s)->GetElapsedTimeFromBeat( (*s)->m_fLastBeat ) - (*s)->GetElapsedTimeFromBeat( (*s)->m_fFirstBeat ); + fSecs += (*s)->GetStepsSeconds(); return fSecs; } diff --git a/stepmania/src/song.h b/stepmania/src/song.h index 578c39c297..3cb18ca7c0 100644 --- a/stepmania/src/song.h +++ b/stepmania/src/song.h @@ -173,6 +173,7 @@ public: float GetBeatFromElapsedTime( float fElapsedTime ) const { return m_Timing.GetBeatFromElapsedTime( fElapsedTime ); } float GetElapsedTimeFromBeat( float fBeat ) const { return m_Timing.GetElapsedTimeFromBeat( fBeat ); } bool HasSignificantBpmChangesOrStops() const; + float GetStepsSeconds() const; bool SongCompleteForStyle( const Style *st ) const; bool HasStepsType( StepsType st ) const;