fix long hold + boomerang artifacts: didn't draw if neither the head nor the tail were on-screen, tail bottom would be positioned above the head causing the hold to magically grow once the tail comes on screen
This commit is contained in:
@@ -25,8 +25,13 @@ static float GetNoteFieldHeight( const PlayerState* pPlayerState )
|
||||
|
||||
/* 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, bool bAbsolute )
|
||||
float ArrowEffects::GetYOffset( const PlayerState* pPlayerState, int iCol, float fNoteBeat, float &fPeakYOffsetOut, bool &bIsPastPeakOut, bool bAbsolute )
|
||||
{
|
||||
// Default values that are returned if boomerang is off.
|
||||
fPeakYOffsetOut = FLT_MAX;
|
||||
bIsPastPeakOut = true;
|
||||
|
||||
|
||||
float fYOffset = 0;
|
||||
|
||||
/* Usually, fTimeSpacing is 0 or 1, in which case we use entirely beat spacing or
|
||||
@@ -84,9 +89,22 @@ float ArrowEffects::GetYOffset( const PlayerState* pPlayerState, int iCol, float
|
||||
|
||||
fYOffset += fYAdjust;
|
||||
|
||||
//
|
||||
// Factor in boomerang
|
||||
//
|
||||
if( fAccels[PlayerOptions::ACCEL_BOOMERANG] > 0 )
|
||||
fYOffset += fAccels[PlayerOptions::ACCEL_BOOMERANG] * (fYOffset * SCALE( fYOffset, 0.f, SCREEN_HEIGHT, 1.5f, 0.5f )- fYOffset);
|
||||
{
|
||||
float fOriginalYOffset = fYOffset;
|
||||
|
||||
fYOffset = (-1*fOriginalYOffset*fOriginalYOffset/SCREEN_HEIGHT) + 1.5*fOriginalYOffset;
|
||||
float fPeakAtYOffset = SCREEN_HEIGHT * 0.75; // zero point of function above
|
||||
fPeakYOffsetOut = (-1*fPeakAtYOffset*fPeakAtYOffset/SCREEN_HEIGHT) + 1.5*fPeakAtYOffset;
|
||||
bIsPastPeakOut = fOriginalYOffset < fPeakAtYOffset;
|
||||
}
|
||||
|
||||
//
|
||||
// Factor in scroll speed
|
||||
//
|
||||
float fScrollSpeed = pPlayerState->m_CurrentPlayerOptions.m_fScrollSpeed;
|
||||
if( pPlayerState->m_CurrentPlayerOptions.m_fRandomSpeed > 0 && !bAbsolute )
|
||||
{
|
||||
@@ -119,11 +137,11 @@ float ArrowEffects::GetYOffset( const PlayerState* pPlayerState, int iCol, float
|
||||
}
|
||||
|
||||
fYOffset *= fScrollSpeed;
|
||||
fPeakYOffsetOut *= fScrollSpeed;
|
||||
|
||||
return fYOffset;
|
||||
}
|
||||
|
||||
|
||||
void ArrowGetReverseShiftAndScale( const PlayerState* pPlayerState, int iCol, float fYReverseOffsetPixels, float &fShiftOut, float &fScaleOut )
|
||||
{
|
||||
/* XXX: Hack: we need to scale the reverse shift by the zoom. */
|
||||
|
||||
@@ -12,7 +12,13 @@ public:
|
||||
// fYOffset is a vertical position in pixels relative to the center.
|
||||
// (positive if has not yet been stepped on, negative if has already passed).
|
||||
// The ArrowEffect and ScrollSpeed is applied in this stage.
|
||||
static float GetYOffset( const PlayerState* pPlayerState, int iCol, float fNoteBeat, bool bAbsolute=false );
|
||||
static float GetYOffset( const PlayerState* pPlayerState, int iCol, float fNoteBeat, float &fPeakYOffsetOut, bool &bIsPastPeakYOffset, bool bAbsolute=false );
|
||||
static float GetYOffset( const PlayerState* pPlayerState, int iCol, float fNoteBeat, bool bAbsolute=false )
|
||||
{
|
||||
float fThrowAway;
|
||||
bool bThrowAway;
|
||||
return GetYOffset( pPlayerState, iCol, fNoteBeat, fThrowAway, bThrowAway, bAbsolute );
|
||||
}
|
||||
|
||||
/* Actual display position, with reverse and post-reverse-effects factored in
|
||||
* (fYOffset -> YPos). */
|
||||
|
||||
@@ -986,20 +986,34 @@ void NoteDisplay::DrawHoldHead( const TapNote& tn, int iCol, int iRow, const boo
|
||||
|
||||
void NoteDisplay::DrawHold( const TapNote &tn, int iCol, int iRow, bool bIsBeingHeld, bool bIsActive, const HoldNoteResult &Result, float fPercentFadeToFail, bool bDrawGlowOnly, float fReverseOffsetPixels, float fYStartOffset, float fYEndOffset )
|
||||
{
|
||||
int iEndBeat = iRow + tn.iDuration;
|
||||
int iEndRow = iRow + tn.iDuration;
|
||||
|
||||
// bDrawGlowOnly is a little hacky. We need to draw the diffuse part and the glow part one pass at a time to minimize state changes
|
||||
|
||||
bool bReverse = m_pPlayerState->m_CurrentPlayerOptions.GetReversePercentForColumn(iCol) > 0.5f;
|
||||
float fStartBeat = NoteRowToBeat( max(tn.HoldResult.iLastHeldRow, iRow) );
|
||||
float fStartYOffset = ArrowEffects::GetYOffset( m_pPlayerState, iCol, fStartBeat );
|
||||
|
||||
// HACK: If active, don't allow the top of the hold to go above the receptor
|
||||
if( bIsActive )
|
||||
fStartYOffset = 0;
|
||||
float fThrowAway = 0;
|
||||
|
||||
// HACK: If active, don't set YOffset to 0 so that it doesn't jiggle around the receptor.
|
||||
bool bStartIsPastPeak = true;
|
||||
float fStartYOffset = 0;
|
||||
if( bIsActive )
|
||||
; // use the default values filled in above
|
||||
else
|
||||
fStartYOffset = ArrowEffects::GetYOffset( m_pPlayerState, iCol, fStartBeat, fThrowAway, bStartIsPastPeak );
|
||||
|
||||
float fStartYPos = ArrowEffects::GetYPos( m_pPlayerState, iCol, fStartYOffset, fReverseOffsetPixels );
|
||||
float fEndYOffset = ArrowEffects::GetYOffset( m_pPlayerState, iCol, NoteRowToBeat(iEndBeat) );
|
||||
float fEndPeakYOffset = 0;
|
||||
bool bEndIsPastPeak = false;
|
||||
float fEndYOffset = ArrowEffects::GetYOffset( m_pPlayerState, iCol, NoteRowToBeat(iEndRow), fEndPeakYOffset, bEndIsPastPeak );
|
||||
|
||||
// In boomerang, the arrows reverse direction at Y offset value fPeakAtYOffset.
|
||||
// If fPeakAtYOffset lies inside of the hold we're drawing, then the we
|
||||
// want to draw the tail at that max Y offset, or else the hold will appear
|
||||
// to magically grow as the tail approaches the max Y offset.
|
||||
if( bStartIsPastPeak && !bEndIsPastPeak )
|
||||
fEndYOffset = fEndPeakYOffset; // use the calculated PeakYOffset so that long holds don't appear to grow
|
||||
|
||||
float fEndYPos = ArrowEffects::GetYPos( m_pPlayerState, iCol, fEndYOffset, fReverseOffsetPixels );
|
||||
|
||||
const float fYHead = bReverse ? fEndYPos : fStartYPos; // the center of the head
|
||||
|
||||
@@ -572,12 +572,18 @@ void NoteField::DrawPrimitives()
|
||||
// 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 ) )
|
||||
float fThrowAway;
|
||||
bool bStartIsPastPeak = false;
|
||||
bool bEndIsPastPeak = false;
|
||||
float fStartYOffset = ArrowEffects::GetYOffset( m_pPlayerState, c, NoteRowToBeat(iStartRow), fThrowAway, bStartIsPastPeak );
|
||||
float fEndYOffset = ArrowEffects::GetYOffset( m_pPlayerState, c, NoteRowToBeat(iEndRow), fThrowAway, bEndIsPastPeak );
|
||||
|
||||
bool bTailIsOnVisible = iFirstPixelToDraw <= fEndYOffset && fEndYOffset <= iLastPixelToDraw;
|
||||
bool bHeadIsVisible = iFirstPixelToDraw <= fStartYOffset && fStartYOffset <= iLastPixelToDraw;
|
||||
bool bStraddlingVisible = bStartIsPastPeak && !bEndIsPastPeak;
|
||||
if( !(bTailIsOnVisible || bHeadIsVisible || bStraddlingVisible) )
|
||||
{
|
||||
//LOG->Trace( "skip drawing this hold." );
|
||||
continue; // skip
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user