From 0f6ed81fafacfa61b4e93b5a442fa38039eea651 Mon Sep 17 00:00:00 2001 From: Chris Danford Date: Wed, 29 Sep 2004 06:43:57 +0000 Subject: [PATCH] Use a associative arrays instead of normal vectors to hold TapNotes. More places NoteDataUtil, NoteDataWithScoring need to be converted to use the new row iteration macros. --- stepmania/src/NoteData.cpp | 263 ++++++++++++++------------ stepmania/src/NoteData.h | 47 +++-- stepmania/src/NoteDataUtil.cpp | 62 +++--- stepmania/src/NoteDataWithScoring.cpp | 33 ++-- stepmania/src/NoteTypes.h | 12 ++ stepmania/src/NotesLoaderBMS.cpp | 3 +- stepmania/src/Player.cpp | 2 +- 7 files changed, 233 insertions(+), 189 deletions(-) diff --git a/stepmania/src/NoteData.cpp b/stepmania/src/NoteData.cpp index 2d30855778..6b9b7440fc 100644 --- a/stepmania/src/NoteData.cpp +++ b/stepmania/src/NoteData.cpp @@ -36,14 +36,6 @@ void NoteData::SetNumTracks( int iNewNumTracks ) m_TapNotes.resize( iNewNumTracks ); - // Enforce that all track vectors have the same length. - unsigned uNumRows = m_TapNotes[0].size(); - - for( unsigned t=0; t= 0; --h ) @@ -56,9 +48,9 @@ void NoteData::SetNumTracks( int iNewNumTracks ) void NoteData::ClearRange( int iNoteIndexBegin, int iNoteIndexEnd ) { this->ConvertHoldNotesTo4s(); - for( unsigned t=0; tConvert4sToHoldNotes(); @@ -66,7 +58,7 @@ void NoteData::ClearRange( int iNoteIndexBegin, int iNoteIndexEnd ) void NoteData::ClearAll() { - for( unsigned t=0; tFrom4s( To ); @@ -124,10 +115,6 @@ void NoteData::CopyAll( const NoteData* pFrom ) bool NoteData::IsRowEmpty( int index ) const { - /* If this is out of range, we don't have any notes there, so all tracks are empty. */ - if( index < 0 || index >= GetNumRows() ) - return true; - for( int t=0; t& addTo ) const int NoteData::GetFirstNonEmptyTrack( int index ) const { - /* If this is out of range, we don't have any notes there, so all tracks are empty. */ - if( index < 0 || index >= GetNumRows() ) - return 0; - for( int t=0; t= GetNumRows() ) - return 0; - int iNum = 0; for( int t=0; t= GetNumRows() ) - return 0; - int iNum = 0; for( int t=0; t= GetNumRows() ) - return -1; - for( int t=0; t= GetNumRows() ) - return -1; - for( int t=0; t setUsedIndices; - int num_rows = GetNumRows(); for( int t=0; tfirst; + else + iEarliestRowFoundSoFar = min( iEarliestRowFoundSoFar, iter->first ); } for( int i=0; i=0; i-- ) // iterate back to front + for( unsigned t=0; t < GetNumTracks(); t++ ) { - if( !IsRowEmpty(i) ) - { - iOldestRowFoundSoFar = i; - break; - } + const TrackMap &trackMap = m_TapNotes[t]; + const TrackMap::const_reverse_iterator iter = trackMap.rbegin(); + if( iter == trackMap.rend() ) // trackMap is empty + continue; + iOldestRowFoundSoFar = max( iOldestRowFoundSoFar, iter->first ); } for( int i=0; i=0 && trackfirst > rowInOut ); + rowInOut = iter->first; + return true; + } + else + { + return false; + } +} + +bool NoteData::GetNextTapNoteRowForAllTracks( int &rowInOut ) const +{ + int iClosestNextRow = 999999; + bool bAnyHaveNextNote = false; + for( int t=0; t #include "Attack.h" +#define FOREACH_NONEMPTY_ROW_IN_TRACK( nd, track, row ) \ + for( int row = 0; (nd).GetNextTapNoteRowForTrack(track,row); ) +#define FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( nd, track, row, start, last ) \ + for( int row = start-1; (nd).GetNextTapNoteRowForTrack(track,row) && row <= (last); ) +#define FOREACH_NONEMPTY_ROW_ALL_TRACKS( nd, row ) \ + for( int row = 0; (nd).GetNextTapNoteRowForAllTracks(row); ) +#define FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( nd, row, start, last ) \ + for( int row = start-1; (nd).GetNextTapNoteRowForAllTracks(row) && row <= (last); ) class NoteData { - /* By convention, all TrackVectors have the same size. - * If you want to set the size of one, be sure to set the rest. */ - typedef vector TrackVector; - vector m_TapNotes; + // There's no point in inserting empty notes into the map. + // Any blank space in the map is defined to be empty. + typedef map TrackMap; + vector m_TapNotes; vector m_HoldNotes; @@ -44,9 +52,7 @@ public: * range; pretend the song goes on with TAP_EMPTYs indefinitely. */ inline TapNote GetTapNote(unsigned track, int row) const { - if(row < 0 || row >= (int) m_TapNotes[track].size()) - return TAP_EMPTY; - return m_TapNotes[track][row]; + return GetTapNoteX( track, row ); } void ReserveRows( int row ); @@ -54,8 +60,20 @@ public: * which is much faster. Be sure that 0 <= row < GetNumRows(). */ inline TapNote GetTapNoteX(unsigned track, int row) const { - return m_TapNotes[track][row]; + const TrackMap &mapTrack = m_TapNotes[track]; + TrackMap::const_iterator iter = mapTrack.find( row ); + if( iter != mapTrack.end() ) + return iter->second; + else + return TAP_EMPTY; } + + // Use this to iterate over notes. + // Returns the row index of the first TapNote on the track that has a row + // index > afterRow. + bool GetNextTapNoteRowForTrack( int track, int &rowInOut ) const; + bool GetNextTapNoteRowForAllTracks( int &rowInOut ) const; + void MoveTapNoteTrack(int dest, int src); void SetTapNote(int track, int row, TapNote t); @@ -102,15 +120,10 @@ public: // // statistics // - /* Return the number of beats/rows that might contain notes. Use - * GetLast* if you need to know the location of the last note. */ - float GetNumBeats() const { return NoteRowToBeat(GetNumRows()); } - int GetNumRows() const { return int(m_TapNotes[0].size()); } - - float GetFirstBeat() const; // return the beat number of the first note - int GetFirstRow() const; - float GetLastBeat() const; // return the beat number of the last note - int GetLastRow() const; + int GetFirstRow() const; // return the beat number of the first note + float GetFirstBeat() const { return NoteRowToBeat( GetFirstRow() ); } + int GetLastRow() const; // return the beat number of the last note + float GetLastBeat() const { return NoteRowToBeat( GetLastRow() ); } int GetNumTapNotes( const float fStartBeat = 0, const float fEndBeat = -1 ) const; int GetNumMines( const float fStartBeat = 0, const float fEndBeat = -1 ) const; int GetNumHands( const float fStartBeat = 0, const float fEndBeat = -1 ) const; diff --git a/stepmania/src/NoteDataUtil.cpp b/stepmania/src/NoteDataUtil.cpp index 5b3ae19e76..4b352b8940 100644 --- a/stepmania/src/NoteDataUtil.cpp +++ b/stepmania/src/NoteDataUtil.cpp @@ -342,8 +342,8 @@ void NoteDataUtil::LoadOverlapped( const NoteData &input, NoteData &out, int iNe const int ShiftThreshold = BeatToNoteRow(1); - const int iNumRows = in.GetNumRows(); - for( int row = 0; row < iNumRows; ++row ) + const int iLastRow = in.GetLastRow(); + for( int row = 0; row <= iLastRow; ++row ) { for ( int i = 0; i < in.GetNumTracks(); i++ ) { @@ -389,7 +389,8 @@ void NoteDataUtil::LoadTransformedLights( const NoteData &in, NoteData &out, int out.Config(in); out.SetNumTracks( iNewNumTracks ); - for( int r=0; r < Original.GetNumRows(); ++r ) + int iLastRow = Original.GetLastRow(); + for( int r=0; r <= iLastRow; ++r ) { if( Original.IsRowEmpty( r ) ) continue; @@ -496,10 +497,10 @@ float NoteDataUtil::GetChaosRadarValue( const NoteData &in, float fSongSeconds ) return 0.0f; // count number of triplets or 16ths int iNumChaosNotes = 0; - int rows = in.GetLastRow(); - for( int r=0; r<=rows; r++ ) + + FOREACH_NONEMPTY_ROW_ALL_TRACKS( in, r ) { - if( !in.IsRowEmpty(r) && GetNoteType(r) >= NOTE_TYPE_12TH ) + if( GetNoteType(r) >= NOTE_TYPE_12TH ) iNumChaosNotes++; } @@ -531,11 +532,8 @@ void NoteDataUtil::RemoveSimultaneousNotes(NoteData &in, int iMaxSimultaneous, f int iEndIndex = BeatToNoteRow( fEndBeat ); // turn all the HoldNotes into TapNotes - for( int r=iStartIndex; r<=iEndIndex; r++ ) // iterate backwards so we can delete + FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( in, r, iStartIndex, iEndIndex ) { - if( in.IsRowEmpty(r) ) - continue; // skip - set viTracksHeld; in.GetTracksHeldAtRow( r, viTracksHeld ); @@ -586,7 +584,7 @@ void NoteDataUtil::RemoveMines(NoteData &in, float fStartBeat, float fEndBeat ) int iRowStart = BeatToNoteRow(fStartBeat); int iRowEnd = BeatToNoteRow(fEndBeat); for( int t=0; t=0; i-- ) if( fmodf(in.GetHoldNote(i).GetStartBeat(),1) != 0 ) // doesn't start on a beat @@ -1508,7 +1511,8 @@ void NoteDataUtil::FixImpossibleRows( NoteData &in, StepsType st ) return; // each row must pass at least one valid mask - for( int r=0; rGetTapNote(t, i).type != TapNote::empty && GetTapNoteScore(t, i) >= tns ) + if( GetTapNoteScore(t, i) >= tns ) iNumSuccessfulTapNotes++; } } @@ -44,13 +45,13 @@ int NoteDataWithScoring::GetNumTapNotesWithScore( TapNoteScore tns, const float int NoteDataWithScoring::GetNumNWithScore( TapNoteScore tns, int MinTaps, const float fStartBeat, float fEndBeat ) const { if( fEndBeat == -1 ) - fEndBeat = GetNumBeats(); + fEndBeat = GetLastBeat(); int iStartIndex = BeatToNoteRow( fStartBeat ); int iEndIndex = BeatToNoteRow( fEndBeat ); iStartIndex = max( iStartIndex, 0 ); - iEndIndex = min( iEndIndex, GetNumRows()-1 ); + iEndIndex = min( iEndIndex, GetLastRow() ); int iNumSuccessfulDoubles = 0; for( int i=iStartIndex; i<=iEndIndex; i++ ) @@ -76,10 +77,10 @@ int NoteDataWithScoring::GetNumNWithScore( TapNoteScore tns, int MinTaps, const int NoteDataWithScoring::GetNumHoldNotesWithScore( HoldNoteScore hns, const float fStartBeat, float fEndBeat ) const { - int iNumSuccessfulHolds = 0; + if( fEndBeat == -1 ) + fEndBeat = GetLastBeat(); - if(fEndBeat == -1) - fEndBeat = GetNumBeats(); + int iNumSuccessfulHolds = 0; int iStartIndex = BeatToNoteRow( fStartBeat ); int iEndIndex = BeatToNoteRow( fEndBeat ); @@ -98,13 +99,13 @@ int NoteDataWithScoring::GetNumHoldNotesWithScore( HoldNoteScore hns, const floa int NoteDataWithScoring::GetSuccessfulMines( float fStartBeat, float fEndBeat ) const { if( fEndBeat == -1 ) - fEndBeat = GetNumBeats(); + fEndBeat = GetLastBeat(); int iStartIndex = BeatToNoteRow( fStartBeat ); int iEndIndex = BeatToNoteRow( fEndBeat ); iStartIndex = max( iStartIndex, 0 ); - iEndIndex = min( iEndIndex, GetNumRows()-1 ); + iEndIndex = min( iEndIndex, GetLastRow() ); int iNumSuccessfulMinesNotes = 0; for( int i=iStartIndex; i<=iEndIndex; i++ ) @@ -123,14 +124,14 @@ int NoteDataWithScoring::GetSuccessfulMines( float fStartBeat, float fEndBeat ) int NoteDataWithScoring::GetSuccessfulHands( float fStartBeat, float fEndBeat ) const { if( fEndBeat == -1 ) - fEndBeat = GetNumBeats(); + fEndBeat = GetLastBeat(); int iStartIndex = BeatToNoteRow( fStartBeat ); int iEndIndex = BeatToNoteRow( fEndBeat ); /* Clamp to known-good ranges. */ iStartIndex = max( iStartIndex, 0 ); - iEndIndex = min( iEndIndex, GetNumRows()-1 ); + iEndIndex = min( iEndIndex, GetLastRow() ); int iNum = 0; for( int i=iStartIndex; i<=iEndIndex; i++ ) diff --git a/stepmania/src/NoteTypes.h b/stepmania/src/NoteTypes.h index 613f846c41..b9af1ac2a3 100644 --- a/stepmania/src/NoteTypes.h +++ b/stepmania/src/NoteTypes.h @@ -38,6 +38,18 @@ struct TapNote source = source_; attackIndex = attackIndex_; } + bool operator==( const TapNote &other ) + { +#define COMPARE(x) if(x!=other.x) return false; + COMPARE(type); + COMPARE(source); +// COMPARE(bAttack); +// COMPARE(bKeysound); + COMPARE(attackIndex); +// COMPARE(keysoundIndex); +#undef COMPARE + return true; + } }; const unsigned MAX_NUM_ATTACKS = 2*2*2; // 3 bits to hold the attack index currently diff --git a/stepmania/src/NotesLoaderBMS.cpp b/stepmania/src/NotesLoaderBMS.cpp index 4235a6341c..240d5d857d 100644 --- a/stepmania/src/NotesLoaderBMS.cpp +++ b/stepmania/src/NotesLoaderBMS.cpp @@ -115,9 +115,10 @@ static StepsType DetermineStepsType( int iPlayer, const NoteData &nd ) bool bTrackHasNote[NUM_BMS_TRACKS]; ZERO( bTrackHasNote ); + int iLastRow = nd.GetLastRow(); for( int t=0; tm_pCurSong, m_PlayerNumber, fStartBeat, fEndBeat ); - fEndBeat = min( fEndBeat, GetNumBeats() ); + fEndBeat = min( fEndBeat, GetLastBeat() ); LOG->Trace( "Applying transform '%s' from %f to %f to '%s'", mod.sModifier.c_str(), fStartBeat, fEndBeat, GAMESTATE->m_pCurSong->GetTranslitMainTitle().c_str() );