2003-02-16 04:01:45 +00:00
|
|
|
#include "global.h"
|
2002-04-16 17:31:00 +00:00
|
|
|
#include "NoteField.h"
|
|
|
|
|
#include "RageUtil.h"
|
2002-05-01 19:14:55 +00:00
|
|
|
#include "GameConstantsAndTypes.h"
|
2002-07-23 01:41:40 +00:00
|
|
|
#include "PrefsManager.h"
|
2002-04-16 17:31:00 +00:00
|
|
|
#include "ArrowEffects.h"
|
|
|
|
|
#include "GameManager.h"
|
2002-07-23 01:41:40 +00:00
|
|
|
#include "GameState.h"
|
2002-07-27 19:29:51 +00:00
|
|
|
#include "RageException.h"
|
|
|
|
|
#include "RageTimer.h"
|
2002-09-10 08:21:55 +00:00
|
|
|
#include "RageLog.h"
|
2003-07-04 18:03:20 +00:00
|
|
|
#include "RageMath.h"
|
2002-11-11 04:53:31 +00:00
|
|
|
#include "ThemeManager.h"
|
2003-04-02 21:58:27 +00:00
|
|
|
#include "NoteFieldPositioning.h"
|
2003-07-14 17:33:04 +00:00
|
|
|
#include "NoteSkinManager.h"
|
2003-08-16 23:34:47 +00:00
|
|
|
#include "song.h"
|
2004-09-21 06:07:12 +00:00
|
|
|
#include "ScreenDimensions.h"
|
2004-12-20 06:25:59 +00:00
|
|
|
#include "PlayerState.h"
|
2005-01-15 02:01:26 +00:00
|
|
|
#include "Style.h"
|
2002-04-16 17:31:00 +00:00
|
|
|
|
|
|
|
|
NoteField::NoteField()
|
2003-08-16 23:34:47 +00:00
|
|
|
{
|
2005-01-22 02:50:45 +00:00
|
|
|
m_pNoteData = NULL;
|
|
|
|
|
|
2005-02-06 03:32:53 +00:00
|
|
|
m_textMeasureNumber.LoadFromFont( THEME->GetPathF("Common","normal") );
|
2002-04-16 17:31:00 +00:00
|
|
|
m_textMeasureNumber.SetZoom( 1.0f );
|
|
|
|
|
|
2004-03-20 02:59:08 +00:00
|
|
|
m_rectMarkerBar.SetShadowLength( 0 );
|
2003-02-18 23:15:38 +00:00
|
|
|
m_rectMarkerBar.SetEffectDiffuseShift( 2, RageColor(1,1,1,0.5f), RageColor(0.5f,0.5f,0.5f,0.5f) );
|
2002-04-16 17:31:00 +00:00
|
|
|
|
2005-02-06 03:32:53 +00:00
|
|
|
m_sprBars.Load( THEME->GetPathG("NoteField","bars") );
|
2003-02-22 00:22:27 +00:00
|
|
|
m_sprBars.StopAnimating();
|
|
|
|
|
|
2005-01-23 23:17:12 +00:00
|
|
|
m_iBeginMarker = m_iEndMarker = -1;
|
2002-06-27 17:49:10 +00:00
|
|
|
|
2002-08-01 21:55:40 +00:00
|
|
|
m_fPercentFadeToFail = -1;
|
2003-11-28 23:27:12 +00:00
|
|
|
LastDisplay = NULL;
|
2002-04-16 17:31:00 +00:00
|
|
|
}
|
|
|
|
|
|
2003-09-12 06:23:51 +00:00
|
|
|
NoteField::~NoteField()
|
|
|
|
|
{
|
|
|
|
|
Unload();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NoteField::Unload()
|
|
|
|
|
{
|
|
|
|
|
for( map<CString, NoteDisplayCols *>::iterator it = m_NoteDisplays.begin();
|
|
|
|
|
it != m_NoteDisplays.end(); ++it )
|
|
|
|
|
delete it->second;
|
|
|
|
|
m_NoteDisplays.clear();
|
2003-12-05 23:59:34 +00:00
|
|
|
LastDisplay = NULL;
|
2003-09-12 06:23:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NoteField::CacheNoteSkin( CString skin )
|
|
|
|
|
{
|
2005-01-15 03:26:38 +00:00
|
|
|
skin.ToLower();
|
|
|
|
|
|
2003-09-12 06:23:51 +00:00
|
|
|
if( m_NoteDisplays.find(skin) != m_NoteDisplays.end() )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
LOG->Trace("NoteField::CacheNoteSkin: cache %s", skin.c_str() );
|
2005-01-22 02:50:45 +00:00
|
|
|
NoteDisplayCols *nd = new NoteDisplayCols( m_pNoteData->GetNumTracks() );
|
|
|
|
|
for( int c=0; c<m_pNoteData->GetNumTracks(); c++ )
|
2004-12-20 06:25:59 +00:00
|
|
|
nd->display[c].Load( c, m_pPlayerState, skin, m_fYReverseOffsetPixels );
|
|
|
|
|
nd->m_ReceptorArrowRow.Load( m_pPlayerState, skin, m_fYReverseOffsetPixels );
|
|
|
|
|
nd->m_GhostArrowRow.Load( m_pPlayerState, skin, m_fYReverseOffsetPixels );
|
2003-11-28 00:45:31 +00:00
|
|
|
|
2003-09-12 06:23:51 +00:00
|
|
|
m_NoteDisplays[ skin ] = nd;
|
|
|
|
|
}
|
2002-04-16 17:31:00 +00:00
|
|
|
|
2005-01-15 03:26:38 +00:00
|
|
|
void NoteField::CacheAllUsedNoteSkins( bool bDeleteUnused )
|
2003-10-25 07:50:30 +00:00
|
|
|
{
|
|
|
|
|
/* Cache note skins. */
|
|
|
|
|
vector<CString> skins;
|
|
|
|
|
GAMESTATE->GetAllUsedNoteSkins( skins );
|
|
|
|
|
for( unsigned i=0; i < skins.size(); ++i )
|
|
|
|
|
CacheNoteSkin( skins[i] );
|
2005-01-15 03:26:38 +00:00
|
|
|
|
|
|
|
|
if( bDeleteUnused )
|
|
|
|
|
{
|
|
|
|
|
set<CString> setToDelete;
|
|
|
|
|
for( map<CString, NoteDisplayCols *>::iterator it = m_NoteDisplays.begin();
|
|
|
|
|
it != m_NoteDisplays.end(); ++it )
|
|
|
|
|
{
|
|
|
|
|
setToDelete.insert( it->first );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for( unsigned i=0; i < skins.size(); ++i )
|
|
|
|
|
{
|
|
|
|
|
CString sSkin = skins[i];
|
|
|
|
|
sSkin.ToLower();
|
|
|
|
|
setToDelete.erase( sSkin );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Free note skins that are no longer used. */
|
|
|
|
|
for( set<CString>::iterator it = setToDelete.begin(); it != setToDelete.end(); ++it )
|
|
|
|
|
{
|
|
|
|
|
NoteDisplayCols *pNoteDisplay = m_NoteDisplays[*it];
|
|
|
|
|
delete pNoteDisplay;
|
|
|
|
|
m_NoteDisplays.erase( *it );
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-10-25 07:50:30 +00:00
|
|
|
}
|
|
|
|
|
|
2004-12-20 06:25:59 +00:00
|
|
|
void NoteField::Load(
|
2005-01-22 02:50:45 +00:00
|
|
|
const NoteData *pNoteData,
|
2004-12-20 06:25:59 +00:00
|
|
|
const PlayerState* pPlayerState,
|
|
|
|
|
int iFirstPixelToDraw,
|
|
|
|
|
int iLastPixelToDraw,
|
|
|
|
|
float fYReverseOffsetPixels )
|
2002-04-16 17:31:00 +00:00
|
|
|
{
|
2005-01-22 02:50:45 +00:00
|
|
|
m_pNoteData = pNoteData;
|
2004-12-20 06:25:59 +00:00
|
|
|
m_pPlayerState = pPlayerState;
|
2003-08-16 23:34:47 +00:00
|
|
|
m_iStartDrawingPixel = iFirstPixelToDraw;
|
|
|
|
|
m_iEndDrawingPixel = iLastPixelToDraw;
|
2003-08-18 17:19:34 +00:00
|
|
|
m_fYReverseOffsetPixels = fYReverseOffsetPixels;
|
2002-07-28 20:28:37 +00:00
|
|
|
|
2002-08-01 21:55:40 +00:00
|
|
|
m_fPercentFadeToFail = -1;
|
2003-09-12 06:23:51 +00:00
|
|
|
m_LastSeenBeatToNoteSkinRev = -1;
|
2002-08-01 21:55:40 +00:00
|
|
|
|
2005-01-22 02:50:45 +00:00
|
|
|
ASSERT( m_pNoteData->GetNumTracks() == GAMESTATE->GetCurrentStyle()->m_iColsPerPlayer );
|
2003-09-12 06:23:51 +00:00
|
|
|
|
2005-01-15 03:26:38 +00:00
|
|
|
/* If we're in gameplay, we havn't applied course modifiers yet, so we don't know what
|
|
|
|
|
* note skins we'll need. Don't delete unused skins yet. */
|
|
|
|
|
CacheAllUsedNoteSkins( false );
|
2003-09-12 06:23:51 +00:00
|
|
|
RefreshBeatToNoteSkin();
|
2002-04-16 17:31:00 +00:00
|
|
|
}
|
|
|
|
|
|
2003-09-12 06:23:51 +00:00
|
|
|
|
|
|
|
|
void NoteField::RefreshBeatToNoteSkin()
|
2003-04-22 04:54:04 +00:00
|
|
|
{
|
2003-09-12 06:23:51 +00:00
|
|
|
if( GAMESTATE->m_BeatToNoteSkinRev == m_LastSeenBeatToNoteSkinRev )
|
|
|
|
|
return;
|
|
|
|
|
m_LastSeenBeatToNoteSkinRev = GAMESTATE->m_BeatToNoteSkinRev;
|
|
|
|
|
|
|
|
|
|
/* Set by GameState::ResetNoteSkins(): */
|
2004-12-20 06:25:59 +00:00
|
|
|
ASSERT( !m_pPlayerState->m_BeatToNoteSkin.empty() );
|
2003-09-12 06:23:51 +00:00
|
|
|
|
|
|
|
|
m_BeatToNoteDisplays.clear();
|
|
|
|
|
|
|
|
|
|
/* GAMESTATE->m_BeatToNoteSkin[pn] maps from song beats to note skins. Maintain
|
|
|
|
|
* m_BeatToNoteDisplays, to map from song beats to NoteDisplay*s, so we don't
|
|
|
|
|
* have to do it while rendering. */
|
2004-12-20 06:25:59 +00:00
|
|
|
|
|
|
|
|
for( map<float,CString>::const_iterator it = m_pPlayerState->m_BeatToNoteSkin.begin();
|
|
|
|
|
it != m_pPlayerState->m_BeatToNoteSkin.end();
|
|
|
|
|
++it )
|
2003-09-12 06:23:51 +00:00
|
|
|
{
|
|
|
|
|
const float Beat = it->first;
|
|
|
|
|
const CString &Skin = it->second;
|
|
|
|
|
|
|
|
|
|
map<CString, NoteDisplayCols *>::iterator display = m_NoteDisplays.find( Skin );
|
2003-10-26 08:24:46 +00:00
|
|
|
if( display == m_NoteDisplays.end() )
|
|
|
|
|
{
|
|
|
|
|
this->CacheNoteSkin( Skin );
|
|
|
|
|
display = m_NoteDisplays.find( Skin );
|
|
|
|
|
}
|
2003-09-12 06:23:51 +00:00
|
|
|
|
2004-06-16 00:38:31 +00:00
|
|
|
ASSERT_M( display != m_NoteDisplays.end(), ssprintf("Couldn't find %s", Skin.c_str()) );
|
2003-09-12 06:23:51 +00:00
|
|
|
|
|
|
|
|
NoteDisplayCols *cols = display->second;
|
|
|
|
|
m_BeatToNoteDisplays[Beat] = cols;
|
|
|
|
|
}
|
2003-04-22 04:54:04 +00:00
|
|
|
}
|
|
|
|
|
|
2002-07-28 20:28:37 +00:00
|
|
|
void NoteField::Update( float fDeltaTime )
|
2002-04-16 17:31:00 +00:00
|
|
|
{
|
2003-08-16 23:34:47 +00:00
|
|
|
ActorFrame::Update( fDeltaTime );
|
|
|
|
|
|
2002-04-16 17:31:00 +00:00
|
|
|
m_rectMarkerBar.Update( fDeltaTime );
|
2003-11-28 00:45:31 +00:00
|
|
|
|
|
|
|
|
NoteDisplayCols *cur = SearchForSongBeat();
|
2003-11-28 23:27:12 +00:00
|
|
|
|
|
|
|
|
if( cur != LastDisplay )
|
|
|
|
|
{
|
|
|
|
|
/* The display has changed. We might be in the middle of a step; copy any
|
|
|
|
|
* tweens. */
|
|
|
|
|
if( LastDisplay )
|
|
|
|
|
{
|
|
|
|
|
cur->m_GhostArrowRow.CopyTweening( LastDisplay->m_GhostArrowRow );
|
2003-12-22 10:30:10 +00:00
|
|
|
cur->m_ReceptorArrowRow.CopyTweening( LastDisplay->m_ReceptorArrowRow );
|
2003-11-28 23:27:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LastDisplay = cur;
|
|
|
|
|
}
|
|
|
|
|
|
2003-12-22 10:30:10 +00:00
|
|
|
cur->m_ReceptorArrowRow.Update( fDeltaTime );
|
2003-11-28 00:45:31 +00:00
|
|
|
cur->m_GhostArrowRow.Update( fDeltaTime );
|
2002-08-01 21:55:40 +00:00
|
|
|
|
|
|
|
|
if( m_fPercentFadeToFail >= 0 )
|
2002-09-05 20:42:49 +00:00
|
|
|
m_fPercentFadeToFail = min( m_fPercentFadeToFail + fDeltaTime/1.5f, 1 ); // take 1.5 seconds to totally fade
|
2003-09-12 06:23:51 +00:00
|
|
|
|
|
|
|
|
RefreshBeatToNoteSkin();
|
2004-03-01 05:58:19 +00:00
|
|
|
|
2004-08-21 00:34:24 +00:00
|
|
|
/*
|
|
|
|
|
* Update all NoteDisplays. Hack: We need to call this once per frame, not
|
|
|
|
|
* once per player.
|
|
|
|
|
*/
|
2004-12-20 06:25:59 +00:00
|
|
|
// TODO: Remove use of PlayerNumber.
|
|
|
|
|
PlayerNumber pn = m_pPlayerState->m_PlayerNumber;
|
|
|
|
|
if( pn == GAMESTATE->m_MasterPlayerNumber )
|
2004-08-21 00:34:24 +00:00
|
|
|
NoteDisplay::Update( fDeltaTime );
|
2002-04-16 17:31:00 +00:00
|
|
|
}
|
|
|
|
|
|
2003-02-19 07:59:00 +00:00
|
|
|
float NoteField::GetWidth()
|
2002-04-16 17:31:00 +00:00
|
|
|
{
|
2004-06-28 07:26:00 +00:00
|
|
|
const Style* pStyle = GAMESTATE->GetCurrentStyle();
|
2003-02-19 07:59:00 +00:00
|
|
|
float fMinX, fMaxX;
|
2004-12-20 06:25:59 +00:00
|
|
|
// TODO: Remove use of PlayerNumber.
|
|
|
|
|
pStyle->GetMinAndMaxColX( m_pPlayerState->m_PlayerNumber, fMinX, fMaxX );
|
2003-02-19 07:59:00 +00:00
|
|
|
|
|
|
|
|
return fMaxX - fMinX + ARROW_SIZE;
|
2003-02-18 23:15:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NoteField::DrawBeatBar( const float fBeat )
|
|
|
|
|
{
|
|
|
|
|
bool bIsMeasure = fmodf( fBeat, (float)BEATS_PER_MEASURE ) == 0;
|
|
|
|
|
int iMeasureIndex = (int)fBeat / BEATS_PER_MEASURE;
|
|
|
|
|
int iMeasureNoDisplay = iMeasureIndex+1;
|
|
|
|
|
|
|
|
|
|
NoteType nt = BeatToNoteType( fBeat );
|
2002-08-13 23:26:46 +00:00
|
|
|
|
2004-12-20 06:25:59 +00:00
|
|
|
const float fYOffset = ArrowEffects::GetYOffset( m_pPlayerState, 0, fBeat );
|
|
|
|
|
const float fYPos = ArrowEffects::GetYPos( m_pPlayerState, 0, fYOffset, m_fYReverseOffsetPixels );
|
2002-04-16 17:31:00 +00:00
|
|
|
|
2003-02-22 00:22:27 +00:00
|
|
|
float fAlpha;
|
|
|
|
|
int iState;
|
|
|
|
|
|
|
|
|
|
if( bIsMeasure )
|
2003-02-18 23:15:38 +00:00
|
|
|
{
|
2003-02-22 00:22:27 +00:00
|
|
|
fAlpha = 1;
|
|
|
|
|
iState = 0;
|
2003-02-18 23:15:38 +00:00
|
|
|
}
|
2003-02-22 00:22:27 +00:00
|
|
|
else
|
2003-02-18 23:15:38 +00:00
|
|
|
{
|
2004-12-20 06:25:59 +00:00
|
|
|
float fScrollSpeed = m_pPlayerState->m_CurrentPlayerOptions.m_fScrollSpeed;
|
2003-02-22 00:22:27 +00:00
|
|
|
switch( nt )
|
|
|
|
|
{
|
|
|
|
|
default: ASSERT(0);
|
|
|
|
|
case NOTE_TYPE_4TH: fAlpha = 1; iState = 1; break;
|
|
|
|
|
case NOTE_TYPE_8TH: fAlpha = SCALE(fScrollSpeed,1.f,2.f,0.f,1.f); iState = 2; break;
|
|
|
|
|
case NOTE_TYPE_16TH:fAlpha = SCALE(fScrollSpeed,2.f,4.f,0.f,1.f); iState = 3; break;
|
|
|
|
|
}
|
|
|
|
|
CLAMP( fAlpha, 0, 1 );
|
|
|
|
|
}
|
2003-02-20 21:22:18 +00:00
|
|
|
|
2003-02-22 00:22:27 +00:00
|
|
|
float fWidth = GetWidth();
|
|
|
|
|
float fFrameWidth = m_sprBars.GetUnzoomedWidth();
|
2003-02-20 21:22:18 +00:00
|
|
|
|
2003-02-22 00:22:27 +00:00
|
|
|
m_sprBars.SetX( 0 );
|
|
|
|
|
m_sprBars.SetY( fYPos );
|
|
|
|
|
m_sprBars.SetDiffuse( RageColor(1,1,1,fAlpha) );
|
|
|
|
|
m_sprBars.SetState( iState );
|
2003-06-23 04:49:28 +00:00
|
|
|
m_sprBars.SetCustomTextureRect( RectF(0,SCALE(iState,0.f,4.f,0.f,1.f), fWidth/fFrameWidth, SCALE(iState+1,0.f,4.f,0.f,1.f)) );
|
2003-02-22 00:22:27 +00:00
|
|
|
m_sprBars.SetZoomX( fWidth/m_sprBars.GetUnzoomedWidth() );
|
|
|
|
|
m_sprBars.Draw();
|
2003-02-18 23:15:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
if( bIsMeasure )
|
|
|
|
|
{
|
|
|
|
|
m_textMeasureNumber.SetDiffuse( RageColor(1,1,1,1) );
|
|
|
|
|
m_textMeasureNumber.SetGlow( RageColor(1,1,1,0) );
|
2003-03-13 08:43:04 +00:00
|
|
|
m_textMeasureNumber.SetHorizAlign( Actor::align_right );
|
2003-02-18 23:15:38 +00:00
|
|
|
m_textMeasureNumber.SetText( ssprintf("%d", iMeasureNoDisplay) );
|
2003-03-13 08:43:04 +00:00
|
|
|
m_textMeasureNumber.SetXY( -fWidth/2, fYPos );
|
2003-02-18 23:15:38 +00:00
|
|
|
m_textMeasureNumber.Draw();
|
|
|
|
|
}
|
2002-04-16 17:31:00 +00:00
|
|
|
}
|
|
|
|
|
|
2005-01-23 23:17:12 +00:00
|
|
|
void NoteField::DrawMarkerBar( int iBeat )
|
2002-04-16 17:31:00 +00:00
|
|
|
{
|
2005-01-23 23:17:12 +00:00
|
|
|
float fBeat = NoteRowToBeat( iBeat );
|
2004-12-20 06:25:59 +00:00
|
|
|
const float fYOffset = ArrowEffects::GetYOffset( m_pPlayerState, 0, fBeat );
|
|
|
|
|
const float fYPos = ArrowEffects::GetYPos( m_pPlayerState, 0, fYOffset, m_fYReverseOffsetPixels );
|
2002-04-16 17:31:00 +00:00
|
|
|
|
2003-02-19 07:59:00 +00:00
|
|
|
|
|
|
|
|
m_rectMarkerBar.StretchTo( RectF(-GetWidth()/2, fYPos-ARROW_SIZE/2, GetWidth()/2, fYPos+ARROW_SIZE/2) );
|
2002-04-16 17:31:00 +00:00
|
|
|
m_rectMarkerBar.Draw();
|
|
|
|
|
}
|
|
|
|
|
|
2005-01-23 23:17:12 +00:00
|
|
|
void NoteField::DrawAreaHighlight( int iStartBeat, int iEndBeat )
|
2003-02-18 23:15:38 +00:00
|
|
|
{
|
2005-01-23 23:17:12 +00:00
|
|
|
float fStartBeat = NoteRowToBeat( iStartBeat );
|
|
|
|
|
float fEndBeat = NoteRowToBeat( iEndBeat );
|
2004-12-20 06:25:59 +00:00
|
|
|
float fYStartOffset = ArrowEffects::GetYOffset( m_pPlayerState, 0, fStartBeat );
|
|
|
|
|
float fYStartPos = ArrowEffects::GetYPos( m_pPlayerState, 0, fYStartOffset, m_fYReverseOffsetPixels );
|
|
|
|
|
float fYEndOffset = ArrowEffects::GetYOffset( m_pPlayerState, 0, fEndBeat );
|
|
|
|
|
float fYEndPos = ArrowEffects::GetYPos( m_pPlayerState, 0, fYEndOffset, m_fYReverseOffsetPixels );
|
2003-02-19 06:55:07 +00:00
|
|
|
|
|
|
|
|
// Something in OpenGL crashes if this is values are too large. Strange. -Chris
|
|
|
|
|
fYStartPos = max( fYStartPos, -1000 );
|
|
|
|
|
fYEndPos = min( fYEndPos, +5000 );
|
2003-02-18 23:15:38 +00:00
|
|
|
|
2005-01-25 05:02:35 +00:00
|
|
|
m_rectAreaHighlight.StretchTo( RectF(-GetWidth()/2, fYStartPos, GetWidth()/2, fYEndPos) );
|
2003-02-18 23:15:38 +00:00
|
|
|
m_rectAreaHighlight.SetDiffuse( RageColor(1,0,0,0.3f) );
|
|
|
|
|
m_rectAreaHighlight.Draw();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2002-08-13 23:26:46 +00:00
|
|
|
void NoteField::DrawBPMText( const float fBeat, const float fBPM )
|
2002-06-29 11:59:09 +00:00
|
|
|
{
|
2004-12-20 06:25:59 +00:00
|
|
|
const float fYOffset = ArrowEffects::GetYOffset( m_pPlayerState, 0, fBeat );
|
|
|
|
|
const float fYPos = ArrowEffects::GetYPos( m_pPlayerState, 0, fYOffset, m_fYReverseOffsetPixels );
|
2002-06-29 11:59:09 +00:00
|
|
|
|
2003-03-16 00:05:23 +00:00
|
|
|
m_textMeasureNumber.SetHorizAlign( Actor::align_right );
|
2002-10-28 05:30:45 +00:00
|
|
|
m_textMeasureNumber.SetDiffuse( RageColor(1,0,0,1) );
|
2002-12-19 23:07:20 +00:00
|
|
|
m_textMeasureNumber.SetGlow( RageColor(1,1,1,cosf(RageTimer::GetTimeSinceStart()*2)/2+0.5f) );
|
2002-06-29 11:59:09 +00:00
|
|
|
m_textMeasureNumber.SetText( ssprintf("%.2f", fBPM) );
|
2003-02-18 23:15:38 +00:00
|
|
|
m_textMeasureNumber.SetXY( -GetWidth()/2.f - 60, fYPos );
|
2002-06-29 11:59:09 +00:00
|
|
|
m_textMeasureNumber.Draw();
|
|
|
|
|
}
|
|
|
|
|
|
2002-08-13 23:26:46 +00:00
|
|
|
void NoteField::DrawFreezeText( const float fBeat, const float fSecs )
|
2002-06-29 11:59:09 +00:00
|
|
|
{
|
2004-12-20 06:25:59 +00:00
|
|
|
const float fYOffset = ArrowEffects::GetYOffset( m_pPlayerState, 0, fBeat );
|
|
|
|
|
const float fYPos = ArrowEffects::GetYPos( m_pPlayerState, 0, fYOffset, m_fYReverseOffsetPixels );
|
2002-06-29 11:59:09 +00:00
|
|
|
|
2003-03-16 00:05:23 +00:00
|
|
|
m_textMeasureNumber.SetHorizAlign( Actor::align_right );
|
2002-10-28 05:30:45 +00:00
|
|
|
m_textMeasureNumber.SetDiffuse( RageColor(0.8f,0.8f,0,1) );
|
2002-12-19 23:07:20 +00:00
|
|
|
m_textMeasureNumber.SetGlow( RageColor(1,1,1,cosf(RageTimer::GetTimeSinceStart()*2)/2+0.5f) );
|
2002-06-29 11:59:09 +00:00
|
|
|
m_textMeasureNumber.SetText( ssprintf("%.2f", fSecs) );
|
2003-02-18 23:15:38 +00:00
|
|
|
m_textMeasureNumber.SetXY( -GetWidth()/2.f - 10, fYPos );
|
2002-06-29 11:59:09 +00:00
|
|
|
m_textMeasureNumber.Draw();
|
|
|
|
|
}
|
|
|
|
|
|
2002-08-23 20:18:29 +00:00
|
|
|
void NoteField::DrawBGChangeText( const float fBeat, const CString sNewBGName )
|
|
|
|
|
{
|
2004-12-20 06:25:59 +00:00
|
|
|
const float fYOffset = ArrowEffects::GetYOffset( m_pPlayerState, 0, fBeat );
|
|
|
|
|
const float fYPos = ArrowEffects::GetYPos( m_pPlayerState, 0, fYOffset, m_fYReverseOffsetPixels );
|
2002-08-23 20:18:29 +00:00
|
|
|
|
2003-03-16 00:05:23 +00:00
|
|
|
m_textMeasureNumber.SetHorizAlign( Actor::align_left );
|
2002-10-28 05:30:45 +00:00
|
|
|
m_textMeasureNumber.SetDiffuse( RageColor(0,1,0,1) );
|
2002-12-19 23:07:20 +00:00
|
|
|
m_textMeasureNumber.SetGlow( RageColor(1,1,1,cosf(RageTimer::GetTimeSinceStart()*2)/2+0.5f) );
|
2002-08-23 20:18:29 +00:00
|
|
|
m_textMeasureNumber.SetText( sNewBGName );
|
2003-03-16 00:05:23 +00:00
|
|
|
m_textMeasureNumber.SetXY( +GetWidth()/2.f, fYPos );
|
2002-08-23 20:18:29 +00:00
|
|
|
m_textMeasureNumber.Draw();
|
|
|
|
|
}
|
|
|
|
|
|
2003-09-16 18:32:39 +00:00
|
|
|
/* cur is an iterator within m_NoteDisplays. next is ++cur. Advance or rewind cur to
|
|
|
|
|
* point to the block that contains beat. We maintain next as an optimization, as this
|
|
|
|
|
* is called for every tap. */
|
2003-09-12 06:23:51 +00:00
|
|
|
void NoteField::SearchForBeat( NDMap::iterator &cur, NDMap::iterator &next, float Beat )
|
|
|
|
|
{
|
2003-09-16 18:32:39 +00:00
|
|
|
/* cur is too far ahead: */
|
|
|
|
|
while( cur != m_BeatToNoteDisplays.begin() && cur->first > Beat )
|
|
|
|
|
{
|
|
|
|
|
next = cur;
|
|
|
|
|
--cur;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* cur is too far behind: */
|
2003-09-12 06:23:51 +00:00
|
|
|
while( next != m_BeatToNoteDisplays.end() && next->first < Beat )
|
|
|
|
|
{
|
|
|
|
|
cur = next;
|
|
|
|
|
++next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-11-28 00:45:31 +00:00
|
|
|
NoteField::NoteDisplayCols *NoteField::SearchForSongBeat()
|
|
|
|
|
{
|
|
|
|
|
return SearchForBeat( GAMESTATE->m_fSongBeat );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NoteField::NoteDisplayCols *NoteField::SearchForBeat( float Beat )
|
|
|
|
|
{
|
|
|
|
|
NDMap::iterator it = m_BeatToNoteDisplays.lower_bound( Beat );
|
|
|
|
|
/* The first entry should always be lower than any Beat we might receive. */
|
2004-01-20 03:32:48 +00:00
|
|
|
// This assert is firing with Beat = -7408. -Chris
|
2004-01-25 22:20:24 +00:00
|
|
|
// Again with Beat = -7254 and GAMESTATE->m_fMusicSeconds = -3043.61
|
2004-01-26 04:39:14 +00:00
|
|
|
// Again with Beat = -9806 and GAMESTATE->m_fMusicSeconds = -3017.22
|
2004-02-04 07:58:02 +00:00
|
|
|
// Again with Beat = -9806 and GAMESTATE->m_fMusicSeconds = -3017.22
|
|
|
|
|
// Again in the middle of Remember December in Hardcore Galore:
|
|
|
|
|
// Beat = -9373.56 and GAMESTATE->m_fMusicSeconds = -2923.48
|
2004-06-16 00:38:31 +00:00
|
|
|
ASSERT_M( it != m_BeatToNoteDisplays.begin(), ssprintf("%f",Beat) );
|
2003-11-28 00:45:31 +00:00
|
|
|
--it;
|
2004-06-16 00:38:31 +00:00
|
|
|
ASSERT_M( it != m_BeatToNoteDisplays.end(), ssprintf("%f",Beat) );
|
2003-11-28 00:45:31 +00:00
|
|
|
|
|
|
|
|
return it->second;
|
|
|
|
|
}
|
2003-09-12 06:23:51 +00:00
|
|
|
|
|
|
|
|
// CPU OPTIMIZATION OPPORTUNITY:
|
|
|
|
|
// change this probing to binary search
|
2004-12-20 06:25:59 +00:00
|
|
|
float FindFirstDisplayedBeat( const PlayerState* pPlayerState, int iFirstPixelToDraw )
|
2003-09-12 06:23:51 +00:00
|
|
|
{
|
|
|
|
|
float fFirstBeatToDraw = GAMESTATE->m_fSongBeat-4; // Adjust to balance off performance and showing enough notes.
|
|
|
|
|
|
|
|
|
|
while( fFirstBeatToDraw < GAMESTATE->m_fSongBeat )
|
|
|
|
|
{
|
2004-12-20 06:25:59 +00:00
|
|
|
float fYOffset = ArrowEffects::GetYOffset( pPlayerState, 0, fFirstBeatToDraw, true );
|
2003-09-26 03:31:58 +00:00
|
|
|
if( fYOffset < iFirstPixelToDraw ) // off screen
|
2003-09-12 06:23:51 +00:00
|
|
|
fFirstBeatToDraw += 0.1f; // move toward fSongBeat
|
|
|
|
|
else // on screen
|
|
|
|
|
break; // stop probing
|
|
|
|
|
}
|
|
|
|
|
fFirstBeatToDraw -= 0.1f; // rewind if we intentionally overshot
|
|
|
|
|
return fFirstBeatToDraw;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-20 06:25:59 +00:00
|
|
|
float FindLastDisplayedBeat( const PlayerState* pPlayerState, int iLastPixelToDraw )
|
2003-09-12 06:23:51 +00:00
|
|
|
{
|
2003-09-16 07:22:54 +00:00
|
|
|
//
|
|
|
|
|
// Probe for last note to draw.
|
|
|
|
|
// worst case is 0.25x + boost. Adjust search distance to
|
|
|
|
|
// so that notes don't pop onto the screen.
|
|
|
|
|
//
|
2003-09-18 04:23:58 +00:00
|
|
|
float fSearchDistance = 10;
|
2003-09-16 07:22:54 +00:00
|
|
|
float fLastBeatToDraw = GAMESTATE->m_fSongBeat+fSearchDistance;
|
2003-09-17 22:25:29 +00:00
|
|
|
|
2003-09-18 04:23:58 +00:00
|
|
|
const int NUM_ITERATIONS = 20;
|
2003-09-16 07:22:54 +00:00
|
|
|
|
|
|
|
|
for( int i=0; i<NUM_ITERATIONS; i++ )
|
2003-09-12 06:23:51 +00:00
|
|
|
{
|
2004-12-20 06:25:59 +00:00
|
|
|
float fYOffset = ArrowEffects::GetYOffset( pPlayerState, 0, fLastBeatToDraw, true );
|
2003-09-16 07:22:54 +00:00
|
|
|
|
2003-09-26 03:31:58 +00:00
|
|
|
if( fYOffset > iLastPixelToDraw ) // off screen
|
2003-09-16 07:22:54 +00:00
|
|
|
fLastBeatToDraw -= fSearchDistance;
|
2003-09-12 06:23:51 +00:00
|
|
|
else // on screen
|
2003-09-16 07:22:54 +00:00
|
|
|
fLastBeatToDraw += fSearchDistance;
|
|
|
|
|
|
|
|
|
|
fSearchDistance /= 2;
|
2003-09-12 06:23:51 +00:00
|
|
|
}
|
2003-09-16 07:22:54 +00:00
|
|
|
|
2003-09-12 06:23:51 +00:00
|
|
|
return fLastBeatToDraw;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
void NoteField::DrawPrimitives()
|
2002-04-16 17:31:00 +00:00
|
|
|
{
|
2002-07-31 19:40:40 +00:00
|
|
|
//LOG->Trace( "NoteField::DrawPrimitives()" );
|
2002-04-16 17:31:00 +00:00
|
|
|
|
2003-09-12 06:23:51 +00:00
|
|
|
/* This should be filled in on the first update. */
|
|
|
|
|
ASSERT( !m_BeatToNoteDisplays.empty() );
|
2003-01-25 11:05:12 +00:00
|
|
|
|
2003-11-28 00:45:31 +00:00
|
|
|
NoteDisplayCols *cur = SearchForSongBeat();
|
2003-12-22 10:30:10 +00:00
|
|
|
cur->m_ReceptorArrowRow.Draw();
|
2003-11-27 05:18:28 +00:00
|
|
|
|
2004-12-20 06:25:59 +00:00
|
|
|
const PlayerOptions ¤t_po = m_pPlayerState->m_CurrentPlayerOptions;
|
2004-08-29 05:56:51 +00:00
|
|
|
|
2003-04-01 19:31:27 +00:00
|
|
|
//
|
|
|
|
|
// Adjust draw range depending on some effects
|
|
|
|
|
//
|
2003-08-16 23:34:47 +00:00
|
|
|
int iFirstPixelToDraw = m_iStartDrawingPixel;
|
2004-08-29 07:12:37 +00:00
|
|
|
// HACK: if boomerang and centered are on, then we want to draw much
|
2004-08-29 05:56:51 +00:00
|
|
|
// earlier to that the notes don't pop on screen.
|
2004-08-29 07:12:37 +00:00
|
|
|
float fCenteredTimesBoomerang =
|
|
|
|
|
current_po.m_fScrolls[PlayerOptions::SCROLL_CENTERED] *
|
2004-08-29 05:56:51 +00:00
|
|
|
current_po.m_fAccels[PlayerOptions::ACCEL_BOOMERANG];
|
2004-08-29 10:00:27 +00:00
|
|
|
iFirstPixelToDraw += int(SCALE( fCenteredTimesBoomerang, 0.f, 1.f, 0.f, -SCREEN_HEIGHT/2 ));
|
2003-08-16 23:34:47 +00:00
|
|
|
int iLastPixelToDraw = m_iEndDrawingPixel;
|
2003-04-01 19:31:27 +00:00
|
|
|
|
|
|
|
|
float fDrawScale = 1;
|
2004-08-29 05:56:51 +00:00
|
|
|
fDrawScale *= 1 + 0.5f * fabsf( current_po.m_fPerspectiveTilt );
|
|
|
|
|
fDrawScale *= 1 + fabsf( current_po.m_fEffects[PlayerOptions::EFFECT_MINI] );
|
2003-04-17 21:16:56 +00:00
|
|
|
|
2005-01-15 01:38:42 +00:00
|
|
|
iFirstPixelToDraw = (int)(iFirstPixelToDraw * fDrawScale);
|
|
|
|
|
iLastPixelToDraw = (int)(iLastPixelToDraw * fDrawScale);
|
2003-04-01 19:31:27 +00:00
|
|
|
|
|
|
|
|
|
2004-01-01 21:14:18 +00:00
|
|
|
// Probe for first and last notes on the screen
|
2004-12-20 06:25:59 +00:00
|
|
|
float fFirstBeatToDraw = FindFirstDisplayedBeat( m_pPlayerState, iFirstPixelToDraw );
|
|
|
|
|
float fLastBeatToDraw = FindLastDisplayedBeat( m_pPlayerState, iLastPixelToDraw );
|
2003-01-25 11:05:12 +00:00
|
|
|
|
2004-12-20 06:25:59 +00:00
|
|
|
m_pPlayerState->m_fLastDrawnBeat = fLastBeatToDraw;
|
2003-01-25 11:05:12 +00:00
|
|
|
|
2002-08-13 23:26:46 +00:00
|
|
|
const int iFirstIndexToDraw = BeatToNoteRow(fFirstBeatToDraw);
|
|
|
|
|
const int iLastIndexToDraw = BeatToNoteRow(fLastBeatToDraw);
|
2002-04-16 17:31:00 +00:00
|
|
|
|
2003-01-25 11:05:12 +00:00
|
|
|
// LOG->Trace( "start = %f.1, end = %f.1", fFirstBeatToDraw-fSongBeat, fLastBeatToDraw-fSongBeat );
|
2002-09-11 04:49:07 +00:00
|
|
|
// LOG->Trace( "Drawing elements %d through %d", iFirstIndexToDraw, iLastIndexToDraw );
|
2002-04-16 17:31:00 +00:00
|
|
|
|
2002-07-28 20:28:37 +00:00
|
|
|
if( GAMESTATE->m_bEditing )
|
2002-04-16 17:31:00 +00:00
|
|
|
{
|
2003-01-31 02:37:23 +00:00
|
|
|
ASSERT(GAMESTATE->m_pCurSong);
|
|
|
|
|
|
2002-06-29 11:59:09 +00:00
|
|
|
//
|
2003-02-18 23:15:38 +00:00
|
|
|
// Draw beat bars
|
2002-06-29 11:59:09 +00:00
|
|
|
//
|
2003-02-18 23:15:38 +00:00
|
|
|
{
|
2004-10-24 17:44:51 +00:00
|
|
|
float fStartDrawingMeasureBars = max( 0, Quantize(fFirstBeatToDraw-0.25f,0.25f) );
|
2003-02-18 23:15:38 +00:00
|
|
|
for( float f=fStartDrawingMeasureBars; f<fLastBeatToDraw; f+=0.25f )
|
|
|
|
|
DrawBeatBar( f );
|
|
|
|
|
}
|
2002-04-16 17:31:00 +00:00
|
|
|
|
2002-06-29 11:59:09 +00:00
|
|
|
//
|
|
|
|
|
// BPM text
|
|
|
|
|
//
|
2003-12-18 04:48:26 +00:00
|
|
|
vector<BPMSegment> &aBPMSegments = GAMESTATE->m_pCurSong->m_Timing.m_BPMSegments;
|
2004-09-21 07:53:39 +00:00
|
|
|
for( unsigned i=0; i<aBPMSegments.size(); i++ )
|
2003-01-30 20:12:39 +00:00
|
|
|
{
|
2005-01-23 21:55:01 +00:00
|
|
|
if(aBPMSegments[i].m_iStartIndex >= iFirstIndexToDraw &&
|
|
|
|
|
aBPMSegments[i].m_iStartIndex <= iLastIndexToDraw)
|
|
|
|
|
DrawBPMText( NoteRowToBeat(aBPMSegments[i].m_iStartIndex), aBPMSegments[i].GetBPM() );
|
2003-01-30 20:12:39 +00:00
|
|
|
}
|
2002-06-29 11:59:09 +00:00
|
|
|
//
|
|
|
|
|
// Freeze text
|
|
|
|
|
//
|
2003-12-18 04:48:26 +00:00
|
|
|
vector<StopSegment> &aStopSegments = GAMESTATE->m_pCurSong->m_Timing.m_StopSegments;
|
2004-09-21 07:53:39 +00:00
|
|
|
for( unsigned i=0; i<aStopSegments.size(); i++ )
|
2003-01-30 20:12:39 +00:00
|
|
|
{
|
2005-01-23 21:55:01 +00:00
|
|
|
if(aStopSegments[i].m_iStartRow >= iFirstIndexToDraw &&
|
|
|
|
|
aStopSegments[i].m_iStartRow <= iLastIndexToDraw)
|
|
|
|
|
DrawFreezeText( NoteRowToBeat(aStopSegments[i].m_iStartRow), NoteRowToBeat(aStopSegments[i].m_iStartRow) );
|
2003-01-30 20:12:39 +00:00
|
|
|
}
|
2002-06-29 11:59:09 +00:00
|
|
|
|
2002-08-23 20:18:29 +00:00
|
|
|
//
|
|
|
|
|
// BGChange text
|
|
|
|
|
//
|
2003-01-03 05:56:28 +00:00
|
|
|
vector<BackgroundChange> &aBackgroundChanges = GAMESTATE->m_pCurSong->m_BackgroundChanges;
|
2004-09-21 07:53:39 +00:00
|
|
|
for( unsigned i=0; i<aBackgroundChanges.size(); i++ )
|
2003-01-30 20:12:39 +00:00
|
|
|
{
|
|
|
|
|
if(aBackgroundChanges[i].m_fStartBeat >= fFirstBeatToDraw &&
|
|
|
|
|
aBackgroundChanges[i].m_fStartBeat <= fLastBeatToDraw)
|
2003-04-14 04:10:01 +00:00
|
|
|
{
|
|
|
|
|
const BackgroundChange& change = aBackgroundChanges[i];
|
|
|
|
|
CString sChangeText = ssprintf("%s\n%.0f%%%s%s%s",
|
2003-04-25 00:27:30 +00:00
|
|
|
change.m_sBGName.c_str(),
|
2003-04-14 04:10:01 +00:00
|
|
|
change.m_fRate*100,
|
|
|
|
|
change.m_bFadeLast ? " Fade" : "",
|
|
|
|
|
change.m_bRewindMovie ? " Rewind" : "",
|
|
|
|
|
change.m_bLoop ? " Loop" : "" );
|
|
|
|
|
|
|
|
|
|
DrawBGChangeText( change.m_fStartBeat, sChangeText );
|
|
|
|
|
}
|
2003-01-30 20:12:39 +00:00
|
|
|
}
|
2002-08-23 20:18:29 +00:00
|
|
|
|
2002-06-29 11:59:09 +00:00
|
|
|
//
|
|
|
|
|
// Draw marker bars
|
|
|
|
|
//
|
2005-01-23 23:17:12 +00:00
|
|
|
if( m_iBeginMarker != -1 && m_iEndMarker != -1 )
|
|
|
|
|
DrawAreaHighlight( m_iBeginMarker, m_iEndMarker );
|
|
|
|
|
else if( m_iBeginMarker != -1 )
|
|
|
|
|
DrawMarkerBar( m_iBeginMarker );
|
|
|
|
|
else if( m_iEndMarker != -1 )
|
|
|
|
|
DrawMarkerBar( m_iEndMarker );
|
2002-06-29 11:59:09 +00:00
|
|
|
|
2002-04-16 17:31:00 +00:00
|
|
|
}
|
|
|
|
|
|
2002-06-29 11:59:09 +00:00
|
|
|
|
2004-03-01 05:58:19 +00:00
|
|
|
|
2002-04-16 17:31:00 +00:00
|
|
|
//
|
2002-08-23 20:18:29 +00:00
|
|
|
// Optimization is very important here because there are so many arrows to draw.
|
|
|
|
|
// Draw the arrows in order of column. This minimize texture switches and let us
|
|
|
|
|
// draw in big batches.
|
2002-08-13 23:26:46 +00:00
|
|
|
//
|
|
|
|
|
|
2003-02-19 06:27:20 +00:00
|
|
|
float fSelectedRangeGlow = SCALE( cosf(RageTimer::GetTimeSinceStart()*2), -1, 1, 0.1f, 0.3f );
|
|
|
|
|
|
2005-01-22 02:50:45 +00:00
|
|
|
for( int c=0; c<m_pNoteData->GetNumTracks(); c++ ) // for each arrow column
|
2002-04-28 20:42:32 +00:00
|
|
|
{
|
2004-12-20 06:25:59 +00:00
|
|
|
// TODO: Remove use of PlayerNumber.
|
|
|
|
|
PlayerNumber pn = m_pPlayerState->m_PlayerNumber;
|
2005-01-15 02:01:26 +00:00
|
|
|
NoteFieldMode::BeginDrawTrack( pn, c );
|
2003-04-02 21:58:27 +00:00
|
|
|
|
2003-11-15 08:51:47 +00:00
|
|
|
//
|
2002-06-14 22:25:22 +00:00
|
|
|
// Draw all HoldNotes in this column (so that they appear under the tap notes)
|
2004-09-21 07:53:39 +00:00
|
|
|
//
|
2003-09-12 06:23:51 +00:00
|
|
|
NDMap::iterator CurDisplay = m_BeatToNoteDisplays.begin();
|
|
|
|
|
ASSERT( CurDisplay != m_BeatToNoteDisplays.end() );
|
|
|
|
|
NDMap::iterator NextDisplay = CurDisplay; ++NextDisplay;
|
2005-01-25 05:02:35 +00:00
|
|
|
|
2002-04-16 17:31:00 +00:00
|
|
|
{
|
2005-01-25 05:02:35 +00:00
|
|
|
NoteData::TrackMap::const_iterator begin, end;
|
|
|
|
|
m_pNoteData->GetTapNoteRangeInclusive( c, iFirstIndexToDraw, iLastIndexToDraw, begin, end );
|
|
|
|
|
|
|
|
|
|
for( ; begin != end; ++begin )
|
|
|
|
|
{
|
|
|
|
|
const TapNote &tn = begin->second; //m_pNoteData->GetTapNote(c, i);
|
|
|
|
|
if( tn.type != TapNote::hold_head )
|
|
|
|
|
continue; // skip
|
|
|
|
|
|
|
|
|
|
const HoldNoteResult &Result = tn.HoldResult;
|
|
|
|
|
if( Result.hns == HNS_OK ) // if this HoldNote was completed
|
|
|
|
|
continue; // don't draw anything
|
|
|
|
|
|
|
|
|
|
int iStartRow = begin->first;
|
|
|
|
|
int iEndRow = iStartRow + tn.iDuration;
|
|
|
|
|
|
|
|
|
|
// TRICKY: If boomerang is on, then all notes in the range
|
|
|
|
|
// [iFirstIndexToDraw,iLastIndexToDraw] aren't necessarily visible.
|
|
|
|
|
// Test every note to make sure it's on screen before drawing
|
|
|
|
|
float fYStartOffset = ArrowEffects::GetYOffset( m_pPlayerState, c, NoteRowToBeat(iStartRow) );
|
|
|
|
|
float fYEndOffset = ArrowEffects::GetYOffset( m_pPlayerState, c, NoteRowToBeat(iEndRow) );
|
|
|
|
|
if( !( iFirstPixelToDraw <= fYEndOffset && fYEndOffset <= iLastPixelToDraw ||
|
|
|
|
|
iFirstPixelToDraw <= fYStartOffset && fYStartOffset <= iLastPixelToDraw ||
|
|
|
|
|
fYStartOffset < iFirstPixelToDraw && fYEndOffset > iLastPixelToDraw ) )
|
|
|
|
|
{
|
|
|
|
|
continue; // skip
|
|
|
|
|
}
|
2004-04-15 01:31:28 +00:00
|
|
|
|
2005-01-25 05:02:35 +00:00
|
|
|
const bool bIsActive = tn.HoldResult.bActive;
|
|
|
|
|
const bool bIsHoldingNote = tn.HoldResult.bHeld;
|
|
|
|
|
if( bIsActive )
|
|
|
|
|
SearchForSongBeat()->m_GhostArrowRow.SetHoldIsActive( c );
|
|
|
|
|
|
|
|
|
|
ASSERT_M( NoteRowToBeat(iStartRow) > -2000, ssprintf("%i %i %i", iStartRow, iEndRow, c) );
|
|
|
|
|
SearchForBeat( CurDisplay, NextDisplay, NoteRowToBeat(iStartRow) );
|
2002-08-01 03:15:27 +00:00
|
|
|
|
2005-01-25 05:02:35 +00:00
|
|
|
bool bIsInSelectionRange = false;
|
|
|
|
|
if( m_iBeginMarker!=-1 && m_iEndMarker!=-1 )
|
|
|
|
|
bIsInSelectionRange = (m_iBeginMarker <= iStartRow && iEndRow < m_iEndMarker);
|
2002-04-16 17:31:00 +00:00
|
|
|
|
2005-01-25 05:02:35 +00:00
|
|
|
NoteDisplayCols *nd = CurDisplay->second;
|
2005-02-07 21:00:21 +00:00
|
|
|
nd->display[c].DrawHold( tn, c, iStartRow, bIsHoldingNote, bIsActive, Result, bIsInSelectionRange ? fSelectedRangeGlow : m_fPercentFadeToFail, false, m_fYReverseOffsetPixels, (float) iFirstPixelToDraw, (float) iLastPixelToDraw );
|
2005-01-25 05:02:35 +00:00
|
|
|
}
|
2002-04-16 17:31:00 +00:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2002-06-14 22:25:22 +00:00
|
|
|
|
2003-11-15 08:51:47 +00:00
|
|
|
//
|
2004-05-24 04:17:19 +00:00
|
|
|
// Draw all TapNotes in this column
|
2003-11-15 08:51:47 +00:00
|
|
|
//
|
2003-09-12 06:23:51 +00:00
|
|
|
CurDisplay = m_BeatToNoteDisplays.begin();
|
|
|
|
|
NextDisplay = CurDisplay; ++NextDisplay;
|
2003-09-16 07:22:54 +00:00
|
|
|
|
|
|
|
|
// draw notes from furthest to closest
|
2005-01-22 03:11:29 +00:00
|
|
|
|
|
|
|
|
NoteData::TrackMap::const_iterator begin, end;
|
|
|
|
|
m_pNoteData->GetTapNoteRange( c, iFirstIndexToDraw, iLastIndexToDraw, begin, end );
|
|
|
|
|
for( ; begin != end; ++begin )
|
2002-06-14 22:25:22 +00:00
|
|
|
{
|
2005-01-22 03:11:29 +00:00
|
|
|
int i = begin->first;
|
|
|
|
|
const TapNote &tn = begin->second; //m_pNoteData->GetTapNote(c, i);
|
2005-01-25 05:02:35 +00:00
|
|
|
switch( tn.type )
|
|
|
|
|
{
|
|
|
|
|
case TapNote::empty: // no note here
|
|
|
|
|
case TapNote::hold_head:
|
2002-08-13 23:26:46 +00:00
|
|
|
continue; // skip
|
2005-01-25 05:02:35 +00:00
|
|
|
}
|
2002-08-13 23:26:46 +00:00
|
|
|
|
2005-01-22 02:50:45 +00:00
|
|
|
/* Don't draw hidden (fully judged) steps. */
|
|
|
|
|
if( tn.result.bHidden )
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
2004-01-01 21:14:18 +00:00
|
|
|
// TRICKY: If boomerang is on, then all notes in the range
|
|
|
|
|
// [iFirstIndexToDraw,iLastIndexToDraw] aren't necessarily visible.
|
|
|
|
|
// Test every note to make sure it's on screen before drawing
|
2004-12-20 06:25:59 +00:00
|
|
|
float fYOffset = ArrowEffects::GetYOffset( m_pPlayerState, c, NoteRowToBeat(i) );
|
2004-01-01 21:14:18 +00:00
|
|
|
if( fYOffset > iLastPixelToDraw ) // off screen
|
|
|
|
|
continue; // skip
|
|
|
|
|
if( fYOffset < iFirstPixelToDraw ) // off screen
|
|
|
|
|
continue; // skip
|
|
|
|
|
|
2005-01-22 05:00:33 +00:00
|
|
|
ASSERT_M( NoteRowToBeat(i) > -2000, ssprintf("%i %i %i, %f %f", i, iLastIndexToDraw, iFirstIndexToDraw, GAMESTATE->m_fSongBeat, GAMESTATE->m_fMusicSeconds) );
|
|
|
|
|
SearchForBeat( CurDisplay, NextDisplay, NoteRowToBeat(i) );
|
|
|
|
|
NoteDisplayCols *nd = CurDisplay->second;
|
|
|
|
|
|
|
|
|
|
// See if there is a hold step that begins on this index. Only do this
|
|
|
|
|
// if the note skin cares.
|
2002-08-13 23:26:46 +00:00
|
|
|
bool bHoldNoteBeginsOnThisBeat = false;
|
2005-01-22 05:00:33 +00:00
|
|
|
if( nd->display[c].DrawHoldHeadForTapsOnSameRow() )
|
2002-06-14 22:25:22 +00:00
|
|
|
{
|
2005-01-22 05:00:33 +00:00
|
|
|
for( int c2=0; c2<m_pNoteData->GetNumTracks(); c2++ )
|
2002-06-14 22:25:22 +00:00
|
|
|
{
|
2005-01-22 05:00:33 +00:00
|
|
|
if( m_pNoteData->GetTapNote(c2, i).type == TapNote::hold_head)
|
|
|
|
|
{
|
|
|
|
|
bHoldNoteBeginsOnThisBeat = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2002-06-14 22:25:22 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-18 23:15:38 +00:00
|
|
|
bool bIsInSelectionRange = false;
|
2005-01-23 23:17:12 +00:00
|
|
|
if( m_iBeginMarker!=-1 && m_iEndMarker!=-1 )
|
2005-01-25 05:02:35 +00:00
|
|
|
bIsInSelectionRange = m_iBeginMarker<=i && i<m_iEndMarker;
|
2003-08-10 06:00:30 +00:00
|
|
|
|
2004-09-12 05:56:24 +00:00
|
|
|
bool bIsAddition = (tn.source == TapNote::addition);
|
|
|
|
|
bool bIsMine = (tn.type == TapNote::mine);
|
|
|
|
|
bool bIsAttack = (tn.type == TapNote::attack);
|
2003-08-10 06:00:30 +00:00
|
|
|
|
2003-11-15 23:19:13 +00:00
|
|
|
if( bIsAttack )
|
2003-11-15 06:08:13 +00:00
|
|
|
{
|
2003-11-15 23:19:13 +00:00
|
|
|
Sprite sprite;
|
2005-02-06 03:32:53 +00:00
|
|
|
sprite.Load( THEME->GetPathG("NoteField","attack "+tn.sAttackModifiers) );
|
2003-11-15 23:19:13 +00:00
|
|
|
float fBeat = NoteRowToBeat(i);
|
2003-12-31 08:15:34 +00:00
|
|
|
nd->display[c].DrawActor( &sprite, c, fBeat, bIsInSelectionRange ? fSelectedRangeGlow : m_fPercentFadeToFail, 1, m_fYReverseOffsetPixels, false );
|
2003-11-15 23:19:13 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
nd->display[c].DrawTap( c, NoteRowToBeat(i), bHoldNoteBeginsOnThisBeat, bIsAddition, bIsMine, bIsInSelectionRange ? fSelectedRangeGlow : m_fPercentFadeToFail, 1, m_fYReverseOffsetPixels );
|
2003-11-15 06:08:13 +00:00
|
|
|
}
|
2002-08-13 23:26:46 +00:00
|
|
|
}
|
2003-04-02 21:58:27 +00:00
|
|
|
|
2003-11-15 08:51:47 +00:00
|
|
|
|
2005-01-15 02:01:26 +00:00
|
|
|
NoteFieldMode::EndDrawTrack( c );
|
2002-04-16 17:31:00 +00:00
|
|
|
}
|
2002-04-28 20:42:32 +00:00
|
|
|
|
2003-11-28 00:45:31 +00:00
|
|
|
cur->m_GhostArrowRow.Draw();
|
2002-04-16 17:31:00 +00:00
|
|
|
}
|
|
|
|
|
|
2002-08-01 21:55:40 +00:00
|
|
|
void NoteField::FadeToFail()
|
|
|
|
|
{
|
|
|
|
|
m_fPercentFadeToFail = max( 0.0f, m_fPercentFadeToFail ); // this will slowly increase every Update()
|
|
|
|
|
// don't fade all over again if this is called twice
|
2002-11-16 09:12:55 +00:00
|
|
|
}
|
2003-11-28 00:45:31 +00:00
|
|
|
|
2004-07-02 20:08:17 +00:00
|
|
|
void NoteField::Step( int iCol, TapNoteScore score ) { SearchForSongBeat()->m_ReceptorArrowRow.Step( iCol, score ); }
|
2003-12-22 10:30:10 +00:00
|
|
|
void NoteField::SetPressed( int iCol ) { SearchForSongBeat()->m_ReceptorArrowRow.SetPressed( iCol ); }
|
2003-11-28 00:45:31 +00:00
|
|
|
void NoteField::DidTapNote( int iCol, TapNoteScore score, bool bBright ) { SearchForSongBeat()->m_GhostArrowRow.DidTapNote( iCol, score, bBright ); }
|
2004-01-01 01:53:25 +00:00
|
|
|
void NoteField::DidHoldNote( int iCol ) { /*SearchForSongBeat()->m_GhostArrowRow.DidHoldNote( iCol );*/ }
|
2004-06-08 00:08:04 +00:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* (c) 2001-2004 Chris Danford
|
|
|
|
|
* All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the
|
|
|
|
|
* "Software"), to deal in the Software without restriction, including
|
|
|
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
|
* distribute, and/or sell copies of the Software, and to permit persons to
|
|
|
|
|
* whom the Software is furnished to do so, provided that the above
|
|
|
|
|
* copyright notice(s) and this permission notice appear in all copies of
|
|
|
|
|
* the Software and that both the above copyright notice(s) and this
|
|
|
|
|
* permission notice appear in supporting documentation.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
|
|
|
|
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
|
|
|
|
|
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
|
|
|
|
|
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
|
|
|
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
|
|
|
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
|
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
*/
|