diff --git a/stepmania/README-FIRST.TXT b/stepmania/README-FIRST.TXT index f13ef66f36..dcec47226f 100644 --- a/stepmania/README-FIRST.TXT +++ b/stepmania/README-FIRST.TXT @@ -114,15 +114,16 @@ keyboad, dance pad, or other game controller. The following is a list of special keys. -Any time: +Anywhere: * F4 = toggle fullscreen * F5 = toggle detail - * Tab = increase game speed 4x (useful for moving through menus quickly) - * LShift = decrease game speed to 1/4x + * Hold Tab = increase game speed 4x (useful for moving through menus quickly) + * Hold LShift = decrease game speed to 1/4x In menus: * Arrow keys navigate menus - * Enter = Start, Escape = Back + * Enter = Start + * Escape = Back In gameplay: * F8 = toggle AutoPlay @@ -1141,8 +1142,10 @@ CHANGE: KSF title discovery will use song foler name if KSF file contains BUG FIX: Stepping before start of a note at beat 0 no longer results in a BAD. BUG FIX: Editor now works with dance-couple note patterns BUG FIX: Lead-in/lead-out time added to Play and Record in editor. -CHANGE: Song specific Background Animations removed in favor of a more powerful - system. +CHANGE: Song specific Background Animations removed. It will be replaced with + a more powerful system soon. +CHANGE: BGAnimations are now chose randomly from all animations rather than + from a specific group ("trance", "techno", etc). NEW FEATURE: "Show Danger" toggle in game options to enable/disable flashing danger message. CHANGE: "Event Mode" option renamed to "Unlimited Arcade Stages". @@ -1153,9 +1156,13 @@ NEW FEATURE: Graphic Option "MovieDecodeMS". Controls how many milliseconds CHANGE: "SongFolders" renamed to "AdditionalSongFolders". BUG FIX: AdditionalSongFolers no longer creates duplicate entries on program load. -CHANGE: RandomMovies do not start playing until the first beat +CHANGE: RandomMovies now start playing on the note and stop playing on the + last note. +CHANGE: Background Movies now start playing at beat 0, and the movie should + synchronize with the notes (BMR's Colors, etc). OPTIMIZATION: New deferred rendering architecture uses more CPU in order to create more efficient operations for the graphics card. +BUG FIX: Select Group no longer crashes with > 15 groups. ------------------------CVS after 3.00 beta 5---------------- OPTIMIZATION: Much faster song loading. diff --git a/stepmania/src/Background.cpp b/stepmania/src/Background.cpp index 68a1e471f1..9a768c31a8 100644 --- a/stepmania/src/Background.cpp +++ b/stepmania/src/Background.cpp @@ -134,7 +134,7 @@ void Background::LoadFromSong( Song* pSong, bool bDisableVisualizations ) case MODE_MOVIE_BG: { pTempBGA = new BackgroundAnimation; - pTempBGA->LoadFromMovie( pSong->GetMovieBackgroundPath() ); + pTempBGA->LoadFromMovieBG( pSong->GetMovieBackgroundPath() ); m_BackgroundAnimations.Add( pTempBGA ); } break; @@ -178,7 +178,7 @@ void Background::LoadFromSong( Song* pSong, bool bDisableVisualizations ) { int index = rand() % arrayPossibleMovies.GetSize(); pTempBGA = new BackgroundAnimation; - pTempBGA->LoadFromMovie( arrayPossibleMovies[index] ); + pTempBGA->LoadFromRandomMovie( arrayPossibleMovies[index] ); m_BackgroundAnimations.Add( pTempBGA ); arrayPossibleMovies.RemoveAt( index ); } @@ -221,13 +221,13 @@ void Background::LoadFromSong( Song* pSong, bool bDisableVisualizations ) const BPMSegment& bpmseg = pSong->m_BPMSegments[i]; if( bpmseg.m_fStartBeat < fFirstBeat || bpmseg.m_fStartBeat > fLastBeat ) - continue; // skip + continue; // skip] int index; if( m_BackgroundAnimations.GetSize()==1 ) index = 0; else - int index = 1 + int(bpmseg.m_fBPM)%(m_BackgroundAnimations.GetSize()-1); + index = 1 + int(bpmseg.m_fBPM)%(m_BackgroundAnimations.GetSize()-1); m_aAnimSegs.Add( AnimSeg(bpmseg.m_fStartBeat,index) ); } diff --git a/stepmania/src/RageMovieTexture.cpp b/stepmania/src/RageMovieTexture.cpp index bd9e9d30b1..13444ecb78 100644 --- a/stepmania/src/RageMovieTexture.cpp +++ b/stepmania/src/RageMovieTexture.cpp @@ -51,7 +51,7 @@ CTextureRenderer::CTextureRenderer( LPUNKNOWN pUnk, HRESULT *phr ) { // Store and ARageef the texture for our use. m_pTexture = NULL; - m_bLocked[0] = m_bLocked[1] = FALSE; + m_bBackBufferLocked = FALSE; *phr = S_OK; } @@ -157,23 +157,23 @@ HRESULT CTextureRenderer::DoRenderSample( IMediaSample * pSample ) pSample->GetPointer( &pBmpBuffer ); - // Find which texture we should render to. - LPDIRECT3DTEXTURE8 pD3DTexture; - - switch( m_pTexture->m_iIndexActiveTexture ) + // Find which texture we should render to. We want to copy to the "back buffer" + LPDIRECT3DTEXTURE8 pD3DTextureCopyTo; + switch( m_pTexture->m_iIndexFrontBuffer ) { - case 0: pD3DTexture = m_pTexture->m_pd3dTexture[1]; break; // 0 is active, so render to 1 - case 1: pD3DTexture = m_pTexture->m_pd3dTexture[0]; break; // 1 is active, so render to 0 + case 0: pD3DTextureCopyTo = m_pTexture->m_pd3dTexture[1]; break; // 0 is front, so copy to 1 + case 1: pD3DTextureCopyTo = m_pTexture->m_pd3dTexture[0]; break; // 1 is front, so copy to 0 } // Lock the Texture D3DLOCKED_RECT d3dlr; - if (FAILED(pD3DTexture->LockRect(0, &d3dlr, 0, 0))) { - DXTRACE_ERR_NOMSGBOX(TEXT("Failed to lock the texture!"), E_FAIL); - return E_FAIL; + while( FAILED( pD3DTextureCopyTo->LockRect(0, &d3dlr, 0, 0) ) ) + { + LOG->Warn( "Failed to lock the texture for rendering movie!" ); + // keep trying until we get the lock } - m_bLocked[m_pTexture->m_iIndexActiveTexture] = TRUE; + m_bBackBufferLocked = TRUE; // Get the texture buffer & pitch pTxtBuffer = static_cast(d3dlr.pBits); @@ -183,56 +183,65 @@ HRESULT CTextureRenderer::DoRenderSample( IMediaSample * pSample ) // Copy the bits // OPTIMIZATION OPPORTUNITY: Use a video and texture // format that allows a simpler copy than this one. - if (m_TextureFormat == D3DFMT_A8R8G8B8) { - for(int y = 0; y < m_lVidHeight; y++ ) { - BYTE *pBmpBufferOld = pBmpBuffer; - BYTE *pTxtBufferOld = pTxtBuffer; - for (int x = 0; x < m_lVidWidth; x++) { - pTxtBuffer[0] = pBmpBuffer[0]; - pTxtBuffer[1] = pBmpBuffer[1]; - pTxtBuffer[2] = pBmpBuffer[2]; - pTxtBuffer[3] = 0xff; - pTxtBuffer += 4; - pBmpBuffer += 3; - } - pBmpBuffer = pBmpBufferOld + m_lVidPitch; - pTxtBuffer = pTxtBufferOld + lTxtPitch; - } - } - - if (m_TextureFormat == D3DFMT_A1R5G5B5) { - for(int y = 0; y < m_lVidHeight; y++ ) { - BYTE *pBmpBufferOld = pBmpBuffer; - BYTE *pTxtBufferOld = pTxtBuffer; - for (int x = 0; x < m_lVidWidth; x++) { - *(WORD *)pTxtBuffer = - 0x8000 + - ((pBmpBuffer[2] & 0xF8) << 7) + - ((pBmpBuffer[1] & 0xF8) << 2) + - (pBmpBuffer[0] >> 3); - pTxtBuffer += 2; - pBmpBuffer += 3; - } - pBmpBuffer = pBmpBufferOld + m_lVidPitch; - pTxtBuffer = pTxtBufferOld + lTxtPitch; - } - } + switch( m_TextureFormat ) + { + case D3DFMT_A8R8G8B8: + { + for(int y = 0; y < m_lVidHeight; y++ ) { + BYTE *pBmpBufferOld = pBmpBuffer; + BYTE *pTxtBufferOld = pTxtBuffer; + for (int x = 0; x < m_lVidWidth; x++) { + pTxtBuffer[0] = pBmpBuffer[0]; + pTxtBuffer[1] = pBmpBuffer[1]; + pTxtBuffer[2] = pBmpBuffer[2]; + pTxtBuffer[3] = 0xff; + pTxtBuffer += 4; + pBmpBuffer += 3; + } + pBmpBuffer = pBmpBufferOld + m_lVidPitch; + pTxtBuffer = pTxtBufferOld + lTxtPitch; + } + } + break; + case D3DFMT_A1R5G5B5: + { + for(int y = 0; y < m_lVidHeight; y++ ) { + BYTE *pBmpBufferOld = pBmpBuffer; + BYTE *pTxtBufferOld = pTxtBuffer; + for (int x = 0; x < m_lVidWidth; x++) { + *(WORD *)pTxtBuffer = + 0x8000 + + ((pBmpBuffer[2] & 0xF8) << 7) + + ((pBmpBuffer[1] & 0xF8) << 2) + + (pBmpBuffer[0] >> 3); + pTxtBuffer += 2; + pBmpBuffer += 3; + } + pBmpBuffer = pBmpBufferOld + m_lVidPitch; + pTxtBuffer = pTxtBufferOld + lTxtPitch; + } + } + break; + default: + ASSERT(0); + } // Unlock the Texture - if (FAILED(pD3DTexture->UnlockRect(0))) { - DXTRACE_ERR_NOMSGBOX(TEXT("Failed to unlock the texture!"), E_FAIL); + if( FAILED( pD3DTextureCopyTo->UnlockRect(0) ) ) + { + LOG->Warn( "Failed to unlock the texture!" ); return E_FAIL; } - m_bLocked[m_pTexture->m_iIndexActiveTexture] = FALSE; + m_bBackBufferLocked = FALSE; // flip active texture - switch( m_pTexture->m_iIndexActiveTexture ) + switch( m_pTexture->m_iIndexFrontBuffer ) { - case 0: m_pTexture->m_iIndexActiveTexture = 1; break; - case 1: m_pTexture->m_iIndexActiveTexture = 0; break; + case 0: m_pTexture->m_iIndexFrontBuffer = 1; break; + case 1: m_pTexture->m_iIndexFrontBuffer = 0; break; } @@ -257,7 +266,7 @@ RageMovieTexture::RageMovieTexture( LOG->Trace( "RageBitmapTexture::RageBitmapTexture()" ); m_pd3dTexture[0] = m_pd3dTexture[1] = NULL; - m_iIndexActiveTexture = 0; + m_iIndexFrontBuffer = 0; Create(); @@ -269,6 +278,8 @@ RageMovieTexture::RageMovieTexture( m_TextureCoordRects[i].top = m_TextureCoordRects[i].bottom; m_TextureCoordRects[i].bottom = fTemp; } + + m_bLoop = true; } RageMovieTexture::~RageMovieTexture() @@ -296,23 +307,11 @@ void RageMovieTexture::Reload( //----------------------------------------------------------------------------- LPDIRECT3DTEXTURE8 RageMovieTexture::GetD3DTexture() { - // Wait until the TextureRenderer is not copying to our texture. - // If we try to draw using the texture while it is locked, the primitive - // will appear without a texture. - // Most of the time, the TextureRenderer is not busy copying (copying - // a frame of video is very quick). If it is busy, it's usually becase - // the video fell behind and is trying to copy several frames in a row - // to catch up. So, if the TextureRenderer is busy, give it a 1ms slice of - // time for it to catch up and copy all the frames it fell behind on. -// while( m_pCTR->IsLocked() ) { -// ::Sleep(1); -// LOG->Trace( "Sleeping waiting for unlock..." ); -// } + CheckMovieStatus(); // restart the movie if we reach the end - // restart the movie if we reach the end - CheckMovieStatus(); - - return m_pd3dTexture[m_iIndexActiveTexture]; + // Return the front buffer because it's guaranteed that CTextureRenderer + // doesn't have it locked. + return m_pd3dTexture[m_iIndexFrontBuffer]; } @@ -436,13 +435,13 @@ HRESULT RageMovieTexture::CreateD3DTexture() if( FAILED( hr = D3DXCreateTexture(m_pd3dDevice, m_iSourceWidth, m_iSourceHeight, 1, 0, - D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_pd3dTexture[0] ) ) ) + D3DFMT_A1R5G5B5, D3DPOOL_MANAGED, &m_pd3dTexture[0] ) ) ) throw RageException( hr, "Could not create the D3DX texture!" ); if( FAILED( hr = D3DXCreateTexture(m_pd3dDevice, m_iSourceWidth, m_iSourceHeight, 1, 0, - D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_pd3dTexture[1] ) ) ) + D3DFMT_A1R5G5B5, D3DPOOL_MANAGED, &m_pd3dTexture[1] ) ) ) throw RageException( hr, "Could not create the D3DX texture!" ); // D3DXCreateTexture can silently change the parameters on us @@ -484,7 +483,7 @@ void RageMovieTexture::CheckMovieStatus() // Check for completion events m_pME->GetEvent( &lEventCode, &lParam1, &lParam2, 0 ); - if( EC_COMPLETE == lEventCode ) + if( EC_COMPLETE == lEventCode && m_bLoop ) m_pMP->put_CurrentPosition(0); } @@ -504,11 +503,6 @@ void RageMovieTexture::Play() PlayMovie(); } -void RageMovieTexture::SetPosition( float fSeconds ) -{ - m_pMP->put_CurrentPosition(0); -} - void RageMovieTexture::Pause() { HRESULT hr; @@ -516,3 +510,26 @@ void RageMovieTexture::Pause() throw RageException( hr, "Could not pause the DirectShow graph." ); } + +void RageMovieTexture::Stop() +{ + HRESULT hr; + if( FAILED( hr = m_pMC->Stop() ) ) + throw RageException( hr, "Could not stop the DirectShow graph." ); +} + +void RageMovieTexture::TurnLoopOn() +{ + m_bLoop = true; +} + +void RageMovieTexture::TurnLoopOff() +{ + m_bLoop = false; +} + +void RageMovieTexture::SetPosition( float fSeconds ) +{ + m_pMP->put_CurrentPosition(0); +} + diff --git a/stepmania/src/RageMovieTexture.h b/stepmania/src/RageMovieTexture.h index 07745912d4..f939829dcd 100644 --- a/stepmania/src/RageMovieTexture.h +++ b/stepmania/src/RageMovieTexture.h @@ -51,7 +51,6 @@ public: LONG GetVidWidth() {return m_lVidWidth;}; LONG GetVidHeight(){return m_lVidHeight;}; HRESULT SetRenderTarget( RageMovieTexture* pTexture ); - BOOL IsLocked(int iIndex) { return m_bLocked[iIndex]; }; protected: LONG m_lVidWidth; // Video width @@ -60,8 +59,7 @@ protected: RageMovieTexture* m_pTexture; // the video surface we will copy new frames to D3DFORMAT m_TextureFormat; // Texture format - BOOL m_bLocked[2]; // Is the texture currently locked while we - // copy the movie frame to it? + BOOL m_bBackBufferLocked; }; @@ -94,12 +92,15 @@ public: LPDIRECT3DTEXTURE8 GetD3DTexture(); virtual void Play(); - virtual void SetPosition( float fSeconds ); virtual void Pause(); + virtual void Stop(); + virtual void SetPosition( float fSeconds ); virtual bool IsAMovie() { return true; }; + virtual void TurnLoopOn(); + virtual void TurnLoopOff(); LPDIRECT3DTEXTURE8 m_pd3dTexture[2]; // double buffered - int m_iIndexActiveTexture; // either 0 or 1 + int m_iIndexFrontBuffer; // index of the buffer that should be rendered from - either 0 or 1 protected: virtual VOID Create(); @@ -118,5 +119,5 @@ protected: CComPtr m_pMP; // Media Postion CComPtr m_pME; // Media Event CTextureRenderer *m_pCTR; // DShow Texture renderer - + bool m_bLoop; }; diff --git a/stepmania/src/RageTexture.cpp b/stepmania/src/RageTexture.cpp index d32a491b0e..1edda40181 100644 --- a/stepmania/src/RageTexture.cpp +++ b/stepmania/src/RageTexture.cpp @@ -111,3 +111,11 @@ void RageTexture::GetFrameDimensionsFromFileName( CString sPath, int* piFramesWi } } + +void RageTexture::TurnLoopOn() +{ +} + +void RageTexture::TurnLoopOff() +{ +} diff --git a/stepmania/src/RageTexture.h b/stepmania/src/RageTexture.h index 89fb1d1355..63d17a3961 100644 --- a/stepmania/src/RageTexture.h +++ b/stepmania/src/RageTexture.h @@ -61,9 +61,12 @@ public: virtual LPDIRECT3DTEXTURE8 GetD3DTexture() = 0; virtual void Play() {}; - virtual void SetPosition( float fSeconds ) {}; + virtual void Stop() {}; virtual void Pause() {}; + virtual void SetPosition( float fSeconds ) {}; virtual bool IsAMovie() { return false; }; + virtual void TurnLoopOn(); + virtual void TurnLoopOff(); int GetSourceWidth() {return m_iSourceWidth;}; int GetSourceHeight() {return m_iSourceHeight;}; diff --git a/stepmania/src/ScreenAppearanceOptions.cpp b/stepmania/src/ScreenAppearanceOptions.cpp index 9488e84bb7..76a9dc1dee 100644 --- a/stepmania/src/ScreenAppearanceOptions.cpp +++ b/stepmania/src/ScreenAppearanceOptions.cpp @@ -93,7 +93,7 @@ void ScreenAppearanceOptions::ImportOptions() CStringArray arrayThemeNames; THEME->GetThemeNamesForCurGame( arrayThemeNames ); - m_OptionLineData[AO_THEME].iNumOptions = arrayThemeNames.GetSize() + 1; + m_OptionLineData[AO_THEME].iNumOptions = arrayThemeNames.GetSize(); for( i=0; iGetPathTo("Fonts","normal") ); m_textInfo.SetXY( INFO_X, INFO_Y ); m_textInfo.SetHorizAlign( Actor::align_right ); - m_textInfo.SetVertAlign( Actor::align_top ); + m_textInfo.SetVertAlign( Actor::align_bottom ); m_textInfo.SetZoom( 0.5f ); m_textInfo.SetShadowLength( 2 ); //m_textInfo.SetText(); // set this below every frame @@ -302,10 +302,10 @@ void ScreenEdit::Update( float fDeltaTime ) { if( m_EditMode == MODE_RECORDING ) { - TransitionToEditFromRecord(); + TransitionFromRecordToEdit(); GAMESTATE->m_fSongBeat = m_NoteFieldEdit.m_fEndMarker; m_rectRecordBack.BeginTweening( 0.5f ); - m_rectRecordBack.SetDiffuseColor( D3DXCOLOR(0,0,0,0) ); + m_rectRecordBack.SetTweenDiffuseColor( D3DXCOLOR(0,0,0,0) ); } else if( m_EditMode == MODE_PLAYING ) { @@ -313,7 +313,7 @@ void ScreenEdit::Update( float fDeltaTime ) m_EditMode = MODE_EDITING; GAMESTATE->m_fSongBeat = m_NoteFieldEdit.m_fEndMarker; m_rectRecordBack.BeginTweening( 0.5f ); - m_rectRecordBack.SetDiffuseColor( D3DXCOLOR(0,0,0,0) ); + m_rectRecordBack.SetTweenDiffuseColor( D3DXCOLOR(0,0,0,0) ); } } } @@ -965,7 +965,11 @@ void ScreenEdit::InputRecord( const DeviceInput& DeviceI, const InputEventType t switch( DeviceI.button ) { case DIK_ESCAPE: - TransitionToEditFromRecord(); + TransitionFromRecordToEdit(); + + m_rectRecordBack.BeginTweening( 0.5f ); + m_rectRecordBack.SetTweenDiffuseColor( D3DXCOLOR(0,0,0,0) ); + break; } } @@ -1054,6 +1058,8 @@ void ScreenEdit::InputPlay( const DeviceInput& DeviceI, const InputEventType typ case DIK_ESCAPE: m_EditMode = MODE_EDITING; m_soundMusic.Stop(); + m_rectRecordBack.BeginTweening( 0.5f ); + m_rectRecordBack.SetTweenDiffuseColor( D3DXCOLOR(0,0,0,0) ); GAMESTATE->m_fSongBeat = froundf( GAMESTATE->m_fSongBeat, NoteTypeToBeat(m_SnapDisplay.GetSnapMode()) ); break; @@ -1070,7 +1076,7 @@ void ScreenEdit::InputPlay( const DeviceInput& DeviceI, const InputEventType typ } -void ScreenEdit::TransitionToEditFromRecord() +void ScreenEdit::TransitionFromRecordToEdit() { m_EditMode = MODE_EDITING; m_soundMusic.Stop(); diff --git a/stepmania/src/ScreenEdit.h b/stepmania/src/ScreenEdit.h index c02c8b941e..ff85b8ceb6 100644 --- a/stepmania/src/ScreenEdit.h +++ b/stepmania/src/ScreenEdit.h @@ -38,7 +38,7 @@ public: void InputRecord( const DeviceInput& DeviceI, const InputEventType type, const GameInput &GameI, const MenuInput &MenuI, const StyleInput &StyleI ); void InputPlay( const DeviceInput& DeviceI, const InputEventType type, const GameInput &GameI, const MenuInput &MenuI, const StyleInput &StyleI ); virtual void HandleScreenMessage( const ScreenMessage SM ); - void TransitionToEditFromRecord(); + void TransitionFromRecordToEdit(); protected: diff --git a/stepmania/src/ScreenGameplay.cpp b/stepmania/src/ScreenGameplay.cpp index 70b515ee2c..56e6ae07f0 100644 --- a/stepmania/src/ScreenGameplay.cpp +++ b/stepmania/src/ScreenGameplay.cpp @@ -781,7 +781,7 @@ void ScreenGameplay::Update( float fDeltaTime ) if( fSongBeat > GAMESTATE->m_pCurSong->m_fLastBeat+4 ) { GAMESTATE->m_fSongBeat = 0; - m_soundMusic.Stop(); + m_soundMusic.Pause(); this->SendScreenMessage( SM_NotesEnded, 0 ); } diff --git a/stepmania/src/ScreenGraphicOptions.cpp b/stepmania/src/ScreenGraphicOptions.cpp index 0cdb457e26..822791b444 100644 --- a/stepmania/src/ScreenGraphicOptions.cpp +++ b/stepmania/src/ScreenGraphicOptions.cpp @@ -45,7 +45,7 @@ OptionLineData g_GraphicOptionsLines[NUM_GRAPHIC_OPTIONS_LINES] = { { "Show Stats", 2, {"OFF","ON"} }, { "BG Mode", 4, {"OFF","ANIMATIONS","VISUALIZATIONS","RANDOM MOVIES"} }, { "BG Brightness", 5, {"20%","40%","60%","80%","100%"} }, - { "Movie Decode", 5, {"1ms","2ms","3ms","4ms","5ms"} }, + { "Movie Decode", 4, {"1ms","2ms","3ms","4ms"} }, }; ScreenGraphicOptions::ScreenGraphicOptions() : diff --git a/stepmania/src/ScreenSelectGroup.cpp b/stepmania/src/ScreenSelectGroup.cpp index ab1165bc60..eb17b8ceef 100644 --- a/stepmania/src/ScreenSelectGroup.cpp +++ b/stepmania/src/ScreenSelectGroup.cpp @@ -67,129 +67,76 @@ ScreenSelectGroup::ScreenSelectGroup() // and groups that do not contain any steps for the current // style (such as solo) are omitted. Bear with me! // -- dro kulix + + // Chris: + // This is excellent! I'm going to move the filtering of songs + // that can't be played by current style to be the first action. + // This will simply the code a bit, and fix a weird case that + // causes a crash when there are duplicate song names. - // m_arrayGroupNames will contain all relevant group names - CMap*, CArray*> - mapGroupToSongArray; // Will contain all relevant songs + CArray aAllSongs; + aAllSongs.Copy( SONGMAN->m_pSongs ); - { // Let's get local! - // (There are some variables we want deallocated before continuing.) + // Filter out Songs that can't be played by the current Style + NotesType nt = GAMESTATE->GetCurrentStyleDef()->m_NotesType; - // Retrieve list of ALL song groups and ALL songs + for( i=aAllSongs.GetSize()-1; i>=0; i-- ) // foreach Song, back to front + { + Song* pSong = aAllSongs[i]; - SONGMAN->GetGroupNames( m_arrayGroupNames ); - - CArray arrayAllSongs; - arrayAllSongs.Copy( SONGMAN->m_pSongs ); - - // Retrieve the identities (Song*) of all songs under these groups - - for( i=0; im_apNotes.GetSize(); j++ ) // foreach Notes { - CArray *p_arrayGroupSongs = new CArray; - // WARNING! We are creating new objects that must be destroyed. - const CString &sCurGroupName = m_arrayGroupNames[i]; - - SONGMAN->GetSongsInGroup( sCurGroupName, *p_arrayGroupSongs ); - mapGroupToSongArray.SetAt(GetHashForString(sCurGroupName), p_arrayGroupSongs); - } + Notes* pNotes = pSong->m_apNotes[j]; - { - // Add "ALL MUSIC" group - CArray *p_arrayGroupSongs = new CArray; - // WARNING! (Same as last.) - m_arrayGroupNames.InsertAt(0, "ALL MUSIC"); - - p_arrayGroupSongs->Copy( arrayAllSongs ); - mapGroupToSongArray.SetAt(GetHashForString("ALL MUSIC"), p_arrayGroupSongs); - } - - // Now, create a map of all songs to their support for the current style. - // (Song *) -> (Support current style?) - CMap mapStyleSupport; - mapStyleSupport.InitHashTable(arrayAllSongs.GetSize()); - - // The following loop is functionally identical to one used in MusicWheel - NotesType curNotesType = GAMESTATE->GetCurrentStyleDef()->m_NotesType; - for( i=0; i arraySteps; - - arrayAllSongs.GetAt(i)->GetNotesThatMatch( curNotesType, arraySteps ); - - if( arraySteps.GetSize() > 0 ) - mapStyleSupport.SetAt(arrayAllSongs.GetAt(i), true); - else - mapStyleSupport.SetAt(arrayAllSongs.GetAt(i), false); - } - - // Here's the fun part! - - // Recurse each group of songs, removing the ones unsupported by this style. - // If a group ends up empty, remove it from the list. - - { - int gi = 0; - - // Group iteration - while (gi < m_arrayGroupNames.GetSize()) + if( pNotes->m_NotesType == nt ) { - - int si = 0; - - int curKey = GetHashForString(m_arrayGroupNames.GetAt(gi)); - CArray * p_arrayGroupSongs = 0; - mapGroupToSongArray.Lookup(curKey, p_arrayGroupSongs); - - // Song iteration - while (si < p_arrayGroupSongs->GetSize()) - { - Song* curSong = p_arrayGroupSongs->GetAt(si); - bool bSongSupported = false; - - mapStyleSupport.Lookup(curSong, bSongSupported); - - if (bSongSupported) - { - // Increment only if no remove - si++; - } - else - { - // Remove - p_arrayGroupSongs->RemoveAt(si); - } - } - - - // Do we remove group? - // Never remove "ALL MUSIC". - if ( (gi > 0) && (p_arrayGroupSongs->GetSize() <= 0) ) - { - // Yes, remove group, since it is empty and is not "ALL MUSIC". - // Deallocate empty song array - delete p_arrayGroupSongs; - // Remove from groups array and map - mapGroupToSongArray.RemoveKey(curKey); - m_arrayGroupNames.RemoveAt(gi); - } - else - { - // Keep this group; move on. - gi++; - } - + bSongCanBePlayedByCurrentStyle = true; + break; } - } // End recurse - } // Ends local song-paring block. + } + if( !bSongCanBePlayedByCurrentStyle ) + aAllSongs.RemoveAt( i ); + } + // Get group names by thowing them into a hash + CMapStringToString mapGroupToNothing; + for( i=0; im_sGroupName ] = ""; - // Retrieve list of song groups - //SONGMAN->GetGroupNames( m_arrayGroupNames ); - //m_arrayGroupNames.InsertAt( 0, "ALL MUSIC" ); + // Read group names back out into an m_asGroupNames + m_asGroupNames.Add( "ALL MUSIC" ); + for( POSITION pos = mapGroupToNothing.GetStartPosition(); pos != NULL; ) + { + CString sGroupName, sValue; + mapGroupToNothing.GetNextAssoc( pos, sGroupName, sValue ); + m_asGroupNames.Add( sGroupName ); + if( m_asGroupNames.GetSize() == MAX_GROUPS-1 ) + break; // stop adding + } + SortCStringArray( m_asGroupNames, true ); + + // Add songs to groups (this isn't very efficient, but oh well... + CArray aSongsInGroup[MAX_GROUPS]; + aSongsInGroup[0].Copy( aAllSongs ); // add to ALL MUSIC + for( i=0; im_sGroupName == m_asGroupNames[j] ) + { + aSongsInGroup[j].Add( pSong ); + break; + } + } + } + + m_iSelection = 0; m_bChosen = false; @@ -236,10 +183,9 @@ ScreenSelectGroup::ScreenSelectGroup() } - // This part is still compatible with the new pare routine. - for( i=0; iGetPathTo("Graphics","select group button") ); m_sprButton[i].SetXY( BUTTON_X, BUTTON_START_Y + i*BUTTON_SPACING_Y ); @@ -262,29 +208,35 @@ ScreenSelectGroup::ScreenSelectGroup() // // Generate what text will show in the contents for each group // - // This block is modified for the new paring routine - for( i=0; i* p_arraySongs; - const CString &sCurGroupName = m_arrayGroupNames[i]; - - mapGroupToSongArray.Lookup( GetHashForString(sCurGroupName), p_arraySongs); + CArray& aSongs = aSongsInGroup[i]; + m_iNumSongsInGroup[i] = aSongs.GetSize(); + SortSongPointerArrayByTitle( aSongs ); - m_iNumSongsInGroup[i] = p_arraySongs->GetSize(); - - SortSongPointerArrayByTitle( *p_arraySongs ); - - for( int c=0; cGetSize() ) + int iIndex = c*TITLES_ROWS + r; + if( iIndex < aSongs.GetSize() ) { - if( j == TITLES_COLUMNS * TITLES_ROWS - 1 ) - sText += ssprintf( "%d more.....", p_arraySongs->GetSize() - TITLES_COLUMNS * TITLES_ROWS - 1 ); + if( c == TITLES_COLUMNS-1 && r == TITLES_ROWS-1 ) + { + sText += ssprintf( "%d more.....", aSongs.GetSize() - TITLES_COLUMNS * TITLES_ROWS - 1 ); + } else - sText += (*p_arraySongs)[j]->GetFullTitle() + "\n"; + { + CString sTitle = aSongs[iIndex]->GetFullTitle(); + // TODO: Move this crop threshold into a theme metric or make automatic based on column width + if( sTitle.GetLength() > 40 ) + { + sTitle = sTitle.Left( 37 ); + sTitle += "..."; + } + sText += sTitle + "\n"; + } } } m_sContentsText[i][c] = sText; @@ -306,23 +258,6 @@ ScreenSelectGroup::ScreenSelectGroup() m_Menu.TweenOnScreenFromMenu( SM_None ); TweenOnScreen(); AfterChange(); - - - // Deallocate remaining song arrays in map - { - int csKey; - CArray* pSongArray; - - POSITION Pos; - Pos = mapGroupToSongArray.GetStartPosition(); - - - while (Pos) - { - mapGroupToSongArray.GetNextAssoc(Pos, csKey, pSongArray); - delete pSongArray; - } - } } @@ -397,7 +332,7 @@ void ScreenSelectGroup::AfterChange() for( int c=0; cm_pCurSong = NULL; - GAMESTATE->m_sPreferredGroup = m_arrayGroupNames[m_iSelection]; + GAMESTATE->m_sPreferredGroup = m_asGroupNames[m_iSelection]; if( 0 == stricmp(GAMESTATE->m_sPreferredGroup, "All Music") ) SOUND->PlayOnceStreamedFromDir( ANNOUNCER->GetPathTo(ANNOUNCER_SELECT_GROUP_COMMENT_ALL_MUSIC) ); @@ -505,7 +440,7 @@ void ScreenSelectGroup::TweenOffScreen() } - for( i=0; i