Pull complicated computations out of per-arrow code, and run them just once per

frame.

This is a minor optimization, but it can gain a couple FPS.  More importantly,
it reduces the amount of code in the time-critical functions, which makes it
easier to profile and optimize the time-critical parts.  (Eventually, this should
probably be real class.)
This commit is contained in:
Glenn Maynard
2005-10-23 04:22:29 +00:00
parent 2378994167
commit 8b0223350f
3 changed files with 154 additions and 109 deletions
+151 -109
View File
@@ -21,6 +21,150 @@ static float GetNoteFieldHeight( const PlayerState* pPlayerState )
return SCREEN_HEIGHT + fabsf(pPlayerState->m_CurrentPlayerOptions.m_fPerspectiveTilt)*200;
}
namespace
{
float g_fExpandSeconds = 0;
struct PerPlayerData
{
float m_fMinTornadoX[MAX_COLS_PER_PLAYER];
float m_fMaxTornadoX[MAX_COLS_PER_PLAYER];
float m_fInvertDistance;
float m_fBeatFactor;
};
PerPlayerData g_EffectData[NUM_PLAYERS];
};
void ArrowEffects::Update()
{
const Style* pStyle = GAMESTATE->GetCurrentStyle();
{
static float fLastTime = 0;
float fTime = RageTimer::GetTimeSinceStartFast();
if( !GAMESTATE->m_bFreeze )
{
g_fExpandSeconds += fTime - fLastTime;
g_fExpandSeconds = fmodf( g_fExpandSeconds, PI*2 );
}
fLastTime = fTime;
}
FOREACH_PlayerNumber( pn )
{
const Style::ColumnInfo* pCols = pStyle->m_ColumnInfo[pn];
PerPlayerData &data = g_EffectData[pn];
//
// Update Tornado
//
for( int iColNum = 0; iColNum < MAX_COLS_PER_PLAYER; ++iColNum )
{
// TRICKY: Tornado is very unplayable in doubles, so use a smaller
// tornado width if there are many columns
bool bWideField = pStyle->m_iColsPerPlayer > 4;
int iTornadoWidth = bWideField ? 2 : 3;
int iStartCol = iColNum - iTornadoWidth;
int iEndCol = iColNum + iTornadoWidth;
CLAMP( iStartCol, 0, pStyle->m_iColsPerPlayer-1 );
CLAMP( iEndCol, 0, pStyle->m_iColsPerPlayer-1 );
data.m_fMinTornadoX[iColNum] = FLT_MAX;
data.m_fMaxTornadoX[iColNum] = FLT_MIN;
for( int i=iStartCol; i<=iEndCol; i++ )
{
data.m_fMinTornadoX[iColNum] = min( data.m_fMinTornadoX[iColNum], pCols[i].fXOffset );
data.m_fMaxTornadoX[iColNum] = max( data.m_fMaxTornadoX[iColNum], pCols[i].fXOffset );
}
}
//
// Update Invert
//
{
const int iNumCols = pStyle->m_iColsPerPlayer;
const int iNumSides = pStyle->m_StyleType==ONE_PLAYER_TWO_SIDES ? 2 : 1;
const int iNumColsPerSide = iNumCols / iNumSides;
const int iSideIndex = iColNum / iNumColsPerSide;
const int iColOnSide = iColNum % iNumColsPerSide;
const int iColLeftOfMiddle = (iNumColsPerSide-1)/2;
const int iColRightOfMiddle = (iNumColsPerSide+1)/2;
int iFirstColOnSide = -1;
int iLastColOnSide = -1;
if( iColOnSide <= iColLeftOfMiddle )
{
iFirstColOnSide = 0;
iLastColOnSide = iColLeftOfMiddle;
}
else if( iColOnSide >= iColRightOfMiddle )
{
iFirstColOnSide = iColRightOfMiddle;
iLastColOnSide = iNumColsPerSide-1;
}
else
{
iFirstColOnSide = iColOnSide/2;
iLastColOnSide = iColOnSide/2;
}
// mirror
const int iNewColOnSide = SCALE( iColOnSide, iFirstColOnSide, iLastColOnSide, iLastColOnSide, iFirstColOnSide );
const int iNewCol = iSideIndex*iNumColsPerSide + iNewColOnSide;
const float fOldPixelOffset = pCols[iColNum].fXOffset;
const float fNewPixelOffset = pCols[iNewCol].fXOffset;
data.m_fInvertDistance = fNewPixelOffset - fOldPixelOffset;
}
//
// Update Beat
//
{
float fAccelTime = 0.2f, fTotalTime = 0.5f;
/* If the song is really fast, slow down the rate, but speed up the
* acceleration to compensate or it'll look weird. */
const float fBPM = GAMESTATE->m_fCurBPS * 60;
const float fDiv = max(1.0f, truncf( fBPM / 150.0f ));
fAccelTime /= fDiv;
fTotalTime /= fDiv;
float fBeat = GAMESTATE->m_fSongBeat + fAccelTime;
fBeat /= fDiv;
const bool bEvenBeat = ( int(fBeat) % 2 ) != 0;
data.m_fBeatFactor = 0;
if( fBeat < 0 )
break;
/* -100.2 -> -0.2 -> 0.2 */
fBeat -= truncf( fBeat );
fBeat += 1;
fBeat -= truncf( fBeat );
if( fBeat >= fTotalTime )
break;
if( fBeat < fAccelTime )
{
data.m_fBeatFactor = SCALE( fBeat, 0.0f, fAccelTime, 0.0f, 1.0f);
data.m_fBeatFactor *= data.m_fBeatFactor;
} else /* fBeat < fTotalTime */ {
data.m_fBeatFactor = SCALE( fBeat, fAccelTime, fTotalTime, 1.0f, 0.0f);
data.m_fBeatFactor = 1 - (1-data.m_fBeatFactor) * (1-data.m_fBeatFactor);
}
if( bEvenBeat )
data.m_fBeatFactor *= -1;
data.m_fBeatFactor *= 20.0f;
} while(0);
}
}
/* For visibility testing: if bAbsolute is false, random modifiers must return the
* minimum possible scroll speed. */
float ArrowEffects::GetYOffset( const PlayerState* pPlayerState, int iCol, float fNoteBeat, float &fPeakYOffsetOut, bool &bIsPastPeakOut, bool bAbsolute )
@@ -124,17 +268,7 @@ float ArrowEffects::GetYOffset( const PlayerState* pPlayerState, int iCol, float
if( fAccels[PlayerOptions::ACCEL_EXPAND] != 0 )
{
static float fExpandSeconds = 0;
static float fLastTime = 0;
float fTime = RageTimer::GetTimeSinceStartFast();
if( !GAMESTATE->m_bFreeze )
{
fExpandSeconds += fTime - fLastTime;
fExpandSeconds = fmodf( fExpandSeconds, PI*2 );
}
fLastTime = fTime;
float fExpandMultiplier = SCALE( RageFastCos(fExpandSeconds*3), -1, 1, 0.75f, 1.75f );
float fExpandMultiplier = SCALE( RageFastCos(g_fExpandSeconds*3), -1, 1, 0.75f, 1.75f );
fScrollSpeed *= SCALE( fAccels[PlayerOptions::ACCEL_EXPAND], 0.f, 1.f, 1.f, fExpandMultiplier );
}
@@ -144,7 +278,7 @@ float ArrowEffects::GetYOffset( const PlayerState* pPlayerState, int iCol, float
return fYOffset;
}
void ArrowGetReverseShiftAndScale( const PlayerState* pPlayerState, int iCol, float fYReverseOffsetPixels, float &fShiftOut, float &fScaleOut )
static void ArrowGetReverseShiftAndScale( const PlayerState* pPlayerState, int iCol, float fYReverseOffsetPixels, float &fShiftOut, float &fScaleOut )
{
float fPercentReverse = pPlayerState->m_CurrentPlayerOptions.GetReversePercentForColumn(iCol);
fShiftOut = SCALE( fPercentReverse, 0.f, 1.f, -fYReverseOffsetPixels/2, fYReverseOffsetPixels/2 );
@@ -201,34 +335,16 @@ float ArrowEffects::GetXPos( const PlayerState* pPlayerState, int iColNum, float
// TODO: Don't index by PlayerNumber.
const Style::ColumnInfo* pCols = pStyle->m_ColumnInfo[pPlayerState->m_PlayerNumber];
PerPlayerData &data = g_EffectData[pPlayerState->m_PlayerNumber];
if( fEffects[PlayerOptions::EFFECT_TORNADO] != 0 )
{
// TRICKY: Tornado is very unplayable in doubles, so use a smaller
// tornado width if there are many columns
bool bWideField = pStyle->m_iColsPerPlayer > 4;
int iTornadoWidth = bWideField ? 2 : 3;
int iStartCol = iColNum - iTornadoWidth;
int iEndCol = iColNum + iTornadoWidth;
CLAMP( iStartCol, 0, pStyle->m_iColsPerPlayer-1 );
CLAMP( iEndCol, 0, pStyle->m_iColsPerPlayer-1 );
float fMinX = FLT_MAX;
float fMaxX = FLT_MIN;
for( int i=iStartCol; i<=iEndCol; i++ )
{
fMinX = min( fMinX, pCols[i].fXOffset );
fMaxX = max( fMaxX, pCols[i].fXOffset );
}
const float fRealPixelOffset = pCols[iColNum].fXOffset;
const float fPositionBetween = SCALE( fRealPixelOffset, fMinX, fMaxX, -1, 1 );
const float fPositionBetween = SCALE( fRealPixelOffset, data.m_fMinTornadoX[iColNum], data.m_fMaxTornadoX[iColNum], -1, 1 );
float fRads = acosf( fPositionBetween );
fRads += fYOffset * 6 / SCREEN_HEIGHT;
const float fAdjustedPixelOffset = SCALE( RageFastCos(fRads), -1, 1, fMinX, fMaxX );
const float fAdjustedPixelOffset = SCALE( RageFastCos(fRads), -1, 1, data.m_fMinTornadoX[iColNum], data.m_fMaxTornadoX[iColNum] );
fPixelOffsetFromCenter += (fAdjustedPixelOffset - fRealPixelOffset) * fEffects[PlayerOptions::EFFECT_TORNADO];
}
@@ -246,85 +362,11 @@ float ArrowEffects::GetXPos( const PlayerState* pPlayerState, int iColNum, float
fPixelOffsetFromCenter += fDistance * fEffects[PlayerOptions::EFFECT_FLIP];
}
if( fEffects[PlayerOptions::EFFECT_INVERT] != 0 )
{
const int iNumCols = pStyle->m_iColsPerPlayer;
const int iNumSides = pStyle->m_StyleType==ONE_PLAYER_TWO_SIDES ? 2 : 1;
const int iNumColsPerSide = iNumCols / iNumSides;
const int iSideIndex = iColNum / iNumColsPerSide;
const int iColOnSide = iColNum % iNumColsPerSide;
const int iColLeftOfMiddle = (iNumColsPerSide-1)/2;
const int iColRightOfMiddle = (iNumColsPerSide+1)/2;
int iFirstColOnSide = -1;
int iLastColOnSide = -1;
if( iColOnSide <= iColLeftOfMiddle )
{
iFirstColOnSide = 0;
iLastColOnSide = iColLeftOfMiddle;
}
else if( iColOnSide >= iColRightOfMiddle )
{
iFirstColOnSide = iColRightOfMiddle;
iLastColOnSide = iNumColsPerSide-1;
}
else
{
iFirstColOnSide = iColOnSide/2;
iLastColOnSide = iColOnSide/2;
}
// mirror
const int iNewColOnSide = SCALE( iColOnSide, iFirstColOnSide, iLastColOnSide, iLastColOnSide, iFirstColOnSide );
const int iNewCol = iSideIndex*iNumColsPerSide + iNewColOnSide;
const float fOldPixelOffset = pCols[iColNum].fXOffset;
const float fNewPixelOffset = pCols[iNewCol].fXOffset;
const float fDistance = fNewPixelOffset - fOldPixelOffset;
fPixelOffsetFromCenter += fDistance * fEffects[PlayerOptions::EFFECT_INVERT];
}
fPixelOffsetFromCenter += data.m_fInvertDistance * fEffects[PlayerOptions::EFFECT_INVERT];
if( fEffects[PlayerOptions::EFFECT_BEAT] != 0 )
do {
float fAccelTime = 0.2f, fTotalTime = 0.5f;
/* If the song is really fast, slow down the rate, but speed up the
* acceleration to compensate or it'll look weird. */
const float fBPM = GAMESTATE->m_fCurBPS * 60;
const float fDiv = max(1.0f, truncf( fBPM / 150.0f ));
fAccelTime /= fDiv;
fTotalTime /= fDiv;
float fBeat = GAMESTATE->m_fSongBeat + fAccelTime;
fBeat /= fDiv;
const bool bEvenBeat = ( int(fBeat) % 2 ) != 0;
if( fBeat < 0 )
break;
/* -100.2 -> -0.2 -> 0.2 */
fBeat -= truncf( fBeat );
fBeat += 1;
fBeat -= truncf( fBeat );
if( fBeat >= fTotalTime )
break;
float fAmount;
if( fBeat < fAccelTime )
{
fAmount = SCALE( fBeat, 0.0f, fAccelTime, 0.0f, 1.0f);
fAmount *= fAmount;
} else /* fBeat < fTotalTime */ {
fAmount = SCALE( fBeat, fAccelTime, fTotalTime, 1.0f, 0.0f);
fAmount = 1 - (1-fAmount) * (1-fAmount);
}
if( bEvenBeat )
fAmount *= -1;
const float fShift = 20.0f*fAmount*RageFastSin( fYOffset / 15.0f + PI/2.0f );
const float fShift = data.m_fBeatFactor*RageFastSin( fYOffset / 15.0f + PI/2.0f );
fPixelOffsetFromCenter += fEffects[PlayerOptions::EFFECT_BEAT] * fShift;
} while(0);
+1
View File
@@ -8,6 +8,7 @@ class PlayerState;
class ArrowEffects
{
public:
static void Update();
// fYOffset is a vertical position in pixels relative to the center.
// (positive if has not yet been stepped on, negative if has already passed).
+2
View File
@@ -460,6 +460,8 @@ void NoteField::DrawPrimitives()
/* This should be filled in on the first update. */
ASSERT( !m_BeatToNoteDisplays.empty() );
ArrowEffects::Update();
NoteDisplayCols *cur = SearchForSongBeat();
cur->m_ReceptorArrowRow.Draw();