#include "stdafx.h" /* ----------------------------------------------------------------------------- File: MusicWheel.h Desc: A graphic displayed in the MusicWheel during Dancing. Copyright (c) 2001 Chris Danford. All rights reserved. ----------------------------------------------------------------------------- */ #include "MusicWheel.h" #include "RageUtil.h" #include "SongManager.h" #include "ScreenDimensions.h" #include "ThemeManager.h" #include "RageMusic.h" #include "WindowManager.h" // for sending SM_PlayMusicSample const float SWITCH_MUSIC_TIME = 0.3f; const float SORT_ICON_ON_SCREEN_X = -395; const float SORT_ICON_ON_SCREEN_Y = -176; const float SORT_ICON_OFF_SCREEN_X = SORT_ICON_ON_SCREEN_X - 200; const float SORT_ICON_OFF_SCREEN_Y = SORT_ICON_ON_SCREEN_Y; D3DXCOLOR COLOR_BANNER_TINTS[] = { D3DXCOLOR( 0.0f, 1.0f, 0.0f, 1 ), D3DXCOLOR( 0.0f, 1.0f, 1.0f, 1 ), D3DXCOLOR( 1.0f, 0.0f, 1.0f, 1 ), D3DXCOLOR( 1.0f, 0.0f, 0.0f, 1 ), D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1 ), }; const int NUM_BANNER_TINTS = sizeof(COLOR_BANNER_TINTS) / sizeof(D3DXCOLOR); D3DXCOLOR COLOR_SECTION_TINTS[] = { D3DXCOLOR( 0.9f, 0.0f, 0.2f, 1 ), // red D3DXCOLOR( 0.6f, 0.0f, 0.4f, 1 ), // pink D3DXCOLOR( 0.2f, 0.1f, 0.3f, 1 ), // purple D3DXCOLOR( 0.0f, 0.4f, 0.8f, 1 ), // sky blue D3DXCOLOR( 0.0f, 0.6f, 0.6f, 1 ), // sea green D3DXCOLOR( 0.0f, 0.6f, 0.2f, 1 ), // green D3DXCOLOR( 0.8f, 0.6f, 0.0f, 1 ), // orange }; const int NUM_SECTION_TINTS = sizeof(COLOR_SECTION_TINTS) / sizeof(D3DXCOLOR); D3DXCOLOR COLOR_SECTION_LETTER = D3DXCOLOR(1,1,0.3f,1); WheelItemData::WheelItemData() { m_pSong = NULL; m_MusicStatusDisplayType = TYPE_NONE; } void WheelItemData::LoadFromSectionName( CString sSectionName ) { m_WheelItemType = TYPE_SECTION; m_sSectionName = sSectionName; m_colorTint = D3DXCOLOR(0.5f,0.5f,0.5f,1); } void WheelItemData::LoadFromSong( Song* pSong ) { ASSERT( pSong != NULL ); m_pSong = pSong; m_WheelItemType = TYPE_MUSIC; } WheelItemDisplay::WheelItemDisplay() { m_MusicStatusDisplay.SetXY( -132, 0 ); m_Banner.SetHorizAlign( align_left ); m_Banner.SetXY( 15, 0 ); m_sprSectionBackground.Load( THEME->GetPathTo(GRAPHIC_SECTION_BACKGROUND) ); m_sprSectionBackground.SetXY( -30, 0 ); m_textSectionName.Load( THEME->GetPathTo(FONT_OUTLINE) ); m_textSectionName.TurnShadowOff(); m_textSectionName.SetHorizAlign( align_center ); m_textSectionName.SetVertAlign( align_middle ); m_textSectionName.SetXY( m_sprSectionBackground.GetX(), 0 ); m_textSectionName.SetZoom( 1.5f ); m_textSectionName.SetDiffuseColor( COLOR_SECTION_LETTER ); } void WheelItemDisplay::LoadFromWheelItemData( WheelItemData* pWID ) { ASSERT( pWID != NULL ); // copy all data items m_WheelItemType = pWID->m_WheelItemType; m_colorTint = pWID->m_colorTint; m_sSectionName = pWID->m_sSectionName; m_pSong = pWID->m_pSong; m_MusicStatusDisplayType = pWID->m_MusicStatusDisplayType; // init type specific stuff switch( pWID->m_WheelItemType ) { case TYPE_SECTION: if( m_sSectionName.GetLength() > 15 && -1 != m_sSectionName.Find(' ', m_sSectionName.GetLength()/3) ) // this is space in the name { int iIndexSplit = m_sSectionName.Find( ' ', m_sSectionName.GetLength()/3 ); m_sSectionName.SetAt( iIndexSplit, '\n' ); m_textSectionName.SetZoom( 0.75f ); m_textSectionName.SetText( m_sSectionName ); } else // this is a short name { m_textSectionName.SetZoom( 1.5f ); m_textSectionName.SetText( m_sSectionName ); } m_sprSectionBackground.SetDiffuseColor( m_colorTint ); break; case TYPE_MUSIC: m_Banner.LoadFromSong( m_pSong ); m_Banner.SetDiffuseColor( m_colorTint ); m_MusicStatusDisplay.SetType( m_MusicStatusDisplayType ); break; default: ASSERT( false ); // invalid type } } void WheelItemDisplay::SetDiffuseColor( D3DXCOLOR c ) { Actor::SetDiffuseColor( c ); D3DXCOLOR colorTempTint = m_colorTint; colorTempTint.a = c.a; colorTempTint.r *= c.r; colorTempTint.g *= c.g; colorTempTint.b *= c.b; m_Banner.SetDiffuseColor( colorTempTint ); m_sprSectionBackground.SetDiffuseColor( colorTempTint ); D3DXCOLOR colorTempLetter = COLOR_SECTION_LETTER; colorTempLetter.a = c.a; colorTempLetter.r *= c.r; colorTempLetter.g *= c.g; colorTempLetter.b *= c.b; m_textSectionName.SetDiffuseColor( colorTempLetter ); D3DXCOLOR colorTempDisplay = D3DXCOLOR( 1, 1 ,1, c.a); m_MusicStatusDisplay.SetDiffuseColor( colorTempDisplay ); } void WheelItemDisplay::Update( float fDeltaTime ) { switch( m_WheelItemType ) { case TYPE_SECTION: m_sprSectionBackground.Update( fDeltaTime ); m_textSectionName.Update( fDeltaTime ); break; case TYPE_MUSIC: m_MusicStatusDisplay.Update( fDeltaTime ); m_Banner.Update( fDeltaTime ); break; } } void WheelItemDisplay::RenderPrimitives() { switch( m_WheelItemType ) { case TYPE_SECTION: m_sprSectionBackground.Draw(); m_textSectionName.Draw(); break; case TYPE_MUSIC: m_MusicStatusDisplay.Draw(); m_Banner.Draw(); break; } } MusicWheel::MusicWheel() { RageLog( "MusicWheel::MusicWheel()" ); m_sprSelectionBackground.Load( THEME->GetPathTo(GRAPHIC_MUSIC_SELECTION_HIGHLIGHT) ); m_sprSelectionBackground.SetXY( 0, 0 ); m_sprSelectionBackground.SetDiffuseColor( D3DXCOLOR(0,0,0.7f,0.5f) ); // dark transparent blue m_sprSelectionOverlay.Load( THEME->GetPathTo(GRAPHIC_MUSIC_SELECTION_HIGHLIGHT) ); m_sprSelectionOverlay.SetXY( 0, 0 ); m_sprSelectionOverlay.SetDiffuseColor( D3DXCOLOR(0,0,0,0) ); // invisible m_sprSelectionOverlay.SetEffectGlowing( 1.5f, D3DXCOLOR(1,1,1,0.1f), D3DXCOLOR(1,1,1,1) ); m_MusicSortDisplay.SetZ( -2 ); m_MusicSortDisplay.SetXY( SORT_ICON_ON_SCREEN_X, SORT_ICON_ON_SCREEN_Y ); this->AddActor( &m_MusicSortDisplay ); m_soundChangeMusic.Load( THEME->GetPathTo(SOUND_SWITCH_MUSIC) ); m_soundChangeSort.Load( THEME->GetPathTo(SOUND_SWITCH_SORT) ); m_soundExpand.Load( THEME->GetPathTo(SOUND_EXPAND) ); // init m_mapGroupNameToBannerColor CArray arraySongs; arraySongs.Copy( SONGS->m_pSongs ); SortSongPointerArrayByGroup( arraySongs ); int iNextGroupBannerColor = 0; CString sLastGroupNameSeen = ""; for( int i=0; iGetGroupName(); if( sThisGroupName != sLastGroupNameSeen ) { m_mapGroupNameToColorPtr.SetAt( sThisGroupName, &COLOR_BANNER_TINTS[iNextGroupBannerColor++] ); if( iNextGroupBannerColor >= NUM_BANNER_TINTS-1 ) iNextGroupBannerColor = 0; } sLastGroupNameSeen = sThisGroupName; } m_SortOrder = PREFS->m_SongSortOrder; m_MusicSortDisplay.Set( m_SortOrder ); m_MusicSortDisplay.SetXY( SORT_ICON_ON_SCREEN_X, SORT_ICON_ON_SCREEN_Y ); m_sExpandedSectionName = ""; m_iSelection = 0; m_WheelState = STATE_IDLE; m_fTimeLeftInState = FADE_TIME; m_fPositionOffsetFromSelection = 0; // build all of the wheel item datas for( int so=0; som_pCurSong == NULL && // if there is no currently selected song SONGS->m_pSongs.GetSize() > 0 ) // and there is at least one song { SONGS->m_pCurSong = SONGS->m_pSongs[0]; // select the first song } // find the previously selected song (if any) for( i=0; im_pCurSong ) { m_iSelection = i; // select it m_sExpandedSectionName = GetCurWheelItemDatas()[m_iSelection].m_sSectionName; // make its group the currently expanded group } } // rebuild the WheelItems that appear on screen RebuildWheelItemDisplays(); } MusicWheel::~MusicWheel() { PREFS->m_SongSortOrder = m_SortOrder; } void MusicWheel::BuildWheelItemDatas( CArray &arrayWheelItemDatas, SongSortOrder so ) { /////////////////////////////////// // Make an array of Song*, then sort them /////////////////////////////////// CArray arraySongs; // copy only song that have at least one Steps for the current GameMode for( int i=0; im_pSongs.GetSize(); i++ ) { Song* pSong = SONGS->m_pSongs[i]; CArray arraySteps; pSong->GetStepsThatMatchGameMode( PREFS->m_GameMode, arraySteps ); if( arraySteps.GetSize() > 0 ) arraySongs.Add( pSong ); } // sort the songs switch( so ) { case SORT_GROUP: SortSongPointerArrayByGroup( arraySongs ); break; case SORT_TITLE: SortSongPointerArrayByTitle( arraySongs ); break; case SORT_BPM: SortSongPointerArrayByBPM( arraySongs ); break; // case SORT_ARTIST: // SortSongPointerArrayByArtist( arraySongs ); // break; case SORT_MOST_PLAYED: SortSongPointerArrayByMostPlayed( arraySongs ); break; default: ASSERT( false ); // unhandled SORT_ORDER } /////////////////////////////////// // Build an array of WheelItemDatas from the sorted list of Song* /////////////////////////////////// arrayWheelItemDatas.RemoveAll(); // clear out the previous wheel items... // ...and load new ones switch( so ) { case SORT_MOST_PLAYED: case SORT_BPM: // make WheelItems without sections arrayWheelItemDatas.SetSize( arraySongs.GetSize() ); { for( int i=0; iGetGroupName()]; WID.m_sSectionName = ""; } } break; case SORT_GROUP: case SORT_TITLE: // case SORT_ARTIST: { // make WheelItemDatas with sections arrayWheelItemDatas.SetSize( arraySongs.GetSize()*2 ); // make sure we have enough room for all music and section items CString sLastSection = ""; int iCurWheelItem = 0; int iNextSectionTint = 0; for( int i=0; i< arraySongs.GetSize(); i++ ) { Song* pSong = arraySongs[i]; CString sThisSection = GetSectionNameFromSongAndSort( pSong, so ); if( sThisSection != sLastSection ) // new section, make a section item { WheelItemData &WID = arrayWheelItemDatas[iCurWheelItem++]; WID.LoadFromSectionName( sThisSection ); WID.m_colorTint = COLOR_SECTION_TINTS[iNextSectionTint++]; if( iNextSectionTint >= NUM_SECTION_TINTS ) iNextSectionTint = 0; sLastSection = sThisSection; } WheelItemData &WID = arrayWheelItemDatas[iCurWheelItem++]; WID.LoadFromSong( pSong ); WID.m_sSectionName = sThisSection; WID.m_colorTint = *m_mapGroupNameToColorPtr[pSong->GetGroupName()]; } arrayWheelItemDatas.SetSize( iCurWheelItem ); // make sure we have enough room for all music and section items } break; default: ASSERT( false ); // unhandled SORT_ORDER } // init crowns for( i=0; iGetNumTimesPlayed()==0) ? TYPE_NEW : TYPE_NONE; arrayWheelItemDatas[i].m_MusicStatusDisplayType = crown; } } if( so == SORT_MOST_PLAYED ) { // init crown icons for( int i=0; i GetCurWheelItemDatas().GetSize()-1 ) m_iSelection = 0; for( int i=0; i GetCurWheelItemDatas().GetSize()-1 ) iIndex = 0; } while( GetCurWheelItemDatas()[iIndex].m_WheelItemType == TYPE_MUSIC && GetCurWheelItemDatas()[iIndex].m_sSectionName != "" && GetCurWheelItemDatas()[iIndex].m_sSectionName != m_sExpandedSectionName ); } } void MusicWheel::RenderPrimitives() { m_sprSelectionBackground.Draw(); for( int i=0; iSendMessageToTopWindow( SM_PlaySongSample, 0 ); break; case STATE_FLYING_OFF_BEFORE_NEXT_SORT: { m_WheelState = STATE_FLYING_ON_AFTER_NEXT_SORT; m_fTimeLeftInState = FADE_TIME; Song* pPrevSelectedSong = GetCurWheelItemDatas()[m_iSelection].m_pSong; CString sPrevSelectedSection = GetCurWheelItemDatas()[m_iSelection].m_sSectionName; // change the sort order m_SortOrder = SongSortOrder(m_SortOrder+1); if( m_SortOrder > NUM_SORT_ORDERS-1 ) m_SortOrder = (SongSortOrder)0; m_sExpandedSectionName = GetSectionNameFromSongAndSort( pPrevSelectedSong, m_SortOrder ); //RebuildWheelItems(); m_MusicSortDisplay.Set( m_SortOrder ); m_MusicSortDisplay.BeginTweening( FADE_TIME, TWEEN_BIAS_BEGIN ); m_MusicSortDisplay.SetTweenXY( SORT_ICON_ON_SCREEN_X, SORT_ICON_ON_SCREEN_Y ); m_iSelection = 0; if( pPrevSelectedSong != NULL ) // the previous selected item was a song { // find the previously selected song, and select it for( i=0; iSendMessageToTopWindow( SM_PlaySongSample, 0 ); m_WheelState = STATE_IDLE; // now, wait for input break; case STATE_TWEENING_ON_SCREEN: WM->SendMessageToTopWindow( SM_PlaySongSample, 0 ); m_WheelState = STATE_IDLE; m_fTimeLeftInState = 0; break; case STATE_TWEENING_OFF_SCREEN: m_WheelState = STATE_WAITING_OFF_SCREEN; m_fTimeLeftInState = 0; break; case STATE_IDLE: m_fTimeLeftInState = 0; break; } } // "rotate" wheel toward selected song if( fabsf(m_fPositionOffsetFromSelection) < 0.02f ) m_fPositionOffsetFromSelection = 0; else { m_fPositionOffsetFromSelection -= fDeltaTime * m_fPositionOffsetFromSelection*4; // linear float fSign = m_fPositionOffsetFromSelection / fabsf(m_fPositionOffsetFromSelection); m_fPositionOffsetFromSelection -= fDeltaTime * fSign; // constant } } void MusicWheel::PrevMusic() { switch( m_WheelState ) { case STATE_IDLE: case STATE_SWITCHING_MUSIC: break; // fall through default: return; // don't fall through } MUSIC->Stop(); // decrement m_iSelection do { m_iSelection--; if( m_iSelection < 0 ) m_iSelection = GetCurWheelItemDatas().GetSize()-1; } while( GetCurWheelItemDatas()[m_iSelection].m_WheelItemType == TYPE_MUSIC && GetCurWheelItemDatas()[m_iSelection].m_sSectionName != "" && GetCurWheelItemDatas()[m_iSelection].m_sSectionName != m_sExpandedSectionName ); RebuildWheelItemDisplays(); m_fPositionOffsetFromSelection -= 1; m_WheelState = STATE_SWITCHING_MUSIC; m_fTimeLeftInState = SWITCH_MUSIC_TIME; m_soundChangeMusic.PlayRandom(); } void MusicWheel::NextMusic() { switch( m_WheelState ) { case STATE_IDLE: case STATE_SWITCHING_MUSIC: break; // fall through default: return; // don't continue } MUSIC->Stop(); // increment m_iSelection do { m_iSelection++; if( m_iSelection > GetCurWheelItemDatas().GetSize()-1 ) m_iSelection = 0; } while( GetCurWheelItemDatas()[m_iSelection].m_WheelItemType == TYPE_MUSIC && GetCurWheelItemDatas()[m_iSelection].m_sSectionName != "" && GetCurWheelItemDatas()[m_iSelection].m_sSectionName != m_sExpandedSectionName ); RebuildWheelItemDisplays(); m_fPositionOffsetFromSelection += 1; m_WheelState = STATE_SWITCHING_MUSIC; m_fTimeLeftInState = SWITCH_MUSIC_TIME; m_soundChangeMusic.PlayRandom(); } void MusicWheel::NextSort() { switch( m_WheelState ) { case STATE_IDLE: case STATE_SWITCHING_MUSIC: case STATE_FLYING_ON_AFTER_NEXT_SORT: break; // fall through default: return; // don't continue } MUSIC->Stop(); m_soundChangeSort.PlayRandom(); m_MusicSortDisplay.BeginTweening( FADE_TIME, TWEEN_BIAS_END ); m_MusicSortDisplay.SetTweenXY( SORT_ICON_OFF_SCREEN_X, SORT_ICON_OFF_SCREEN_Y ); m_WheelState = STATE_FLYING_OFF_BEFORE_NEXT_SORT; m_fTimeLeftInState = FADE_TIME; } bool MusicWheel::Select() { switch( GetCurWheelItemDatas()[m_iSelection].m_WheelItemType ) { case TYPE_SECTION: { CString sThisItemSectionName = GetCurWheelItemDatas()[m_iSelection].m_sSectionName; if( m_sExpandedSectionName == sThisItemSectionName ) // already expanded m_sExpandedSectionName = ""; // collapse it else // already collapsed m_sExpandedSectionName = sThisItemSectionName; // expand it RebuildWheelItemDisplays(); m_soundExpand.PlayRandom(); m_iSelection = 0; // reset in case we can't find the last selected song // find the section header and select it for( int i=0; i