Moved tap and hold rendering logic out of NoteField and into NoteDisplay.
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "NoteDisplay.h"
|
#include "NoteDisplay.h"
|
||||||
#include "GameState.h"
|
#include "GameState.h"
|
||||||
|
#include "GhostArrowRow.h"
|
||||||
|
#include "NoteData.h"
|
||||||
#include "NoteSkinManager.h"
|
#include "NoteSkinManager.h"
|
||||||
#include "ArrowEffects.h"
|
#include "ArrowEffects.h"
|
||||||
#include "RageLog.h"
|
#include "RageLog.h"
|
||||||
@@ -317,6 +319,189 @@ void NoteDisplay::Load( int iColNum, const PlayerState* pPlayerState, float fYRe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline float NoteRowToVisibleBeat( const PlayerState *pPlayerState, int iRow )
|
||||||
|
{
|
||||||
|
return NoteRowToBeat(iRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NoteDisplay::IsOnScreen( float fBeat, int iCol, int iDrawDistanceAfterTargetsPixels, int iDrawDistanceBeforeTargetsPixels ) const
|
||||||
|
{
|
||||||
|
// IMPORTANT: Do not modify this function without also modifying the
|
||||||
|
// version that is in NoteField.cpp or coming up with a good way to
|
||||||
|
// merge them. -Kyz
|
||||||
|
// TRICKY: If boomerang is on, then ones in the range
|
||||||
|
// [iFirstRowToDraw,iLastRowToDraw] aren't necessarily visible.
|
||||||
|
// Test to see if this beat is visible before drawing.
|
||||||
|
float fYOffset = ArrowEffects::GetYOffset( m_pPlayerState, iCol, fBeat );
|
||||||
|
if( fYOffset > iDrawDistanceBeforeTargetsPixels ) // off screen
|
||||||
|
return false;
|
||||||
|
if( fYOffset < iDrawDistanceAfterTargetsPixels ) // off screen
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NoteDisplay::DrawHoldsInRange(NoteDisplayRenderArgs const& args,
|
||||||
|
vector<NoteData::TrackMap::const_iterator> const& tap_set)
|
||||||
|
{
|
||||||
|
bool any_upcoming = false;
|
||||||
|
for(vector<NoteData::TrackMap::const_iterator>::const_iterator tapit=
|
||||||
|
tap_set.begin(); tapit != tap_set.end(); ++tapit)
|
||||||
|
{
|
||||||
|
TapNote const& tn= (*tapit)->second;
|
||||||
|
HoldNoteResult const& result= tn.HoldResult;
|
||||||
|
int start_row= (*tapit)->first;
|
||||||
|
int end_row = start_row + tn.iDuration;
|
||||||
|
|
||||||
|
// TRICKY: If boomerang is on, then all notes in the range
|
||||||
|
// [first_row,last_row] aren't necessarily visible.
|
||||||
|
// Test every note to make sure it's on screen before drawing
|
||||||
|
float throw_away;
|
||||||
|
bool start_past_peak = false;
|
||||||
|
bool end_past_peak = false;
|
||||||
|
float start_y = ArrowEffects::GetYOffset(m_pPlayerState, args.column,
|
||||||
|
NoteRowToVisibleBeat(m_pPlayerState, start_row), throw_away,
|
||||||
|
start_past_peak);
|
||||||
|
float end_y = ArrowEffects::GetYOffset(m_pPlayerState, args.column,
|
||||||
|
NoteRowToVisibleBeat(m_pPlayerState, end_row), throw_away,
|
||||||
|
end_past_peak);
|
||||||
|
bool tail_visible = args.draw_pixels_after_targets <= end_y &&
|
||||||
|
end_y <= args.draw_pixels_before_targets;
|
||||||
|
bool head_visible = args.draw_pixels_after_targets <= start_y &&
|
||||||
|
start_y <= args.draw_pixels_before_targets;
|
||||||
|
bool straddling_visible = start_y <= args.draw_pixels_after_targets &&
|
||||||
|
args.draw_pixels_before_targets <= end_y;
|
||||||
|
bool straddling_peak = start_past_peak && !end_past_peak;
|
||||||
|
if(!(tail_visible || head_visible || straddling_visible || straddling_peak))
|
||||||
|
{
|
||||||
|
//LOG->Trace( "skip drawing this hold." );
|
||||||
|
continue; // skip
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_addition = (tn.source == TapNoteSource_Addition);
|
||||||
|
bool hopo_possible = (tn.bHopoPossible);
|
||||||
|
bool use_addition_coloring = is_addition || hopo_possible;
|
||||||
|
const bool hold_ghost_showing = tn.HoldResult.bActive && tn.HoldResult.fLife > 0;
|
||||||
|
const bool is_holding = tn.HoldResult.bHeld;
|
||||||
|
if(hold_ghost_showing)
|
||||||
|
{
|
||||||
|
args.ghost_row.SetHoldShowing(args.column, tn);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_M(NoteRowToBeat(start_row) > -2000, ssprintf("%i %i %i", start_row, end_row, args.column));
|
||||||
|
|
||||||
|
bool in_selection_range = false;
|
||||||
|
if(args.selection_begin_marker != -1 && args.selection_end_marker != -1)
|
||||||
|
{
|
||||||
|
in_selection_range = (args.selection_begin_marker <= start_row &&
|
||||||
|
end_row < args.selection_end_marker);
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawHold(tn, args.column, start_row, is_holding, result,
|
||||||
|
use_addition_coloring,
|
||||||
|
in_selection_range ? args.selection_glow : args.fail_fade,
|
||||||
|
m_fYReverseOffsetPixels, (float)args.draw_pixels_after_targets,
|
||||||
|
(float)args.draw_pixels_before_targets,
|
||||||
|
args.draw_pixels_before_targets, args.fade_before_targets);
|
||||||
|
|
||||||
|
bool note_upcoming = NoteRowToBeat(start_row) >
|
||||||
|
m_pPlayerState->GetDisplayedPosition().m_fSongBeat;
|
||||||
|
any_upcoming |= note_upcoming;
|
||||||
|
}
|
||||||
|
return any_upcoming;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NoteDisplay::DrawTapsInRange(NoteDisplayRenderArgs const& args,
|
||||||
|
vector<NoteData::TrackMap::const_iterator> const& tap_set)
|
||||||
|
{
|
||||||
|
bool any_upcoming= false;
|
||||||
|
// draw notes from furthest to closest
|
||||||
|
for(vector<NoteData::TrackMap::const_iterator>::const_iterator tapit=
|
||||||
|
tap_set.begin(); tapit != tap_set.end(); ++tapit)
|
||||||
|
{
|
||||||
|
int tap_row= (*tapit)->first;
|
||||||
|
TapNote const& tn= (*tapit)->second;
|
||||||
|
|
||||||
|
// TRICKY: If boomerang is on, then all notes in the range
|
||||||
|
// [first_row,last_row] aren't necessarily visible.
|
||||||
|
// Test every note to make sure it's on screen before drawing.
|
||||||
|
if(!IsOnScreen(NoteRowToBeat(tap_row), args.column,
|
||||||
|
args.draw_pixels_after_targets, args.draw_pixels_before_targets))
|
||||||
|
{
|
||||||
|
continue; // skip
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hm, this assert used to pass the first and last rows to draw, when it
|
||||||
|
// was in NoteField, but those aren't available here.
|
||||||
|
// Well, anyone who has to investigate hitting it can use a debugger to
|
||||||
|
// discover the values, hopefully. -Kyz
|
||||||
|
ASSERT_M(NoteRowToBeat(tap_row) > -2000,
|
||||||
|
ssprintf("Invalid tap_row: %i, %f %f",
|
||||||
|
tap_row,
|
||||||
|
m_pPlayerState->GetDisplayedPosition().m_fSongBeat,
|
||||||
|
m_pPlayerState->GetDisplayedPosition().m_fMusicSeconds));
|
||||||
|
|
||||||
|
// See if there is a hold step that begins on this index.
|
||||||
|
// Only do this if the noteskin cares.
|
||||||
|
bool hold_begins_on_this_beat = false;
|
||||||
|
if(DrawHoldHeadForTapsOnSameRow())
|
||||||
|
{
|
||||||
|
for(int c2= 0; c2 < args.note_data.GetNumTracks(); ++c2)
|
||||||
|
{
|
||||||
|
const TapNote &tmp = args.note_data.GetTapNote(c2, tap_row);
|
||||||
|
if(tmp.type == TapNoteType_HoldHead &&
|
||||||
|
tmp.subType == TapNoteSubType_Hold)
|
||||||
|
{
|
||||||
|
hold_begins_on_this_beat = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// do the same for a roll.
|
||||||
|
bool roll_begins_on_this_beat = false;
|
||||||
|
if(DrawRollHeadForTapsOnSameRow())
|
||||||
|
{
|
||||||
|
for(int c2= 0; c2 < args.note_data.GetNumTracks(); ++c2)
|
||||||
|
{
|
||||||
|
const TapNote &tmp = args.note_data.GetTapNote(c2, tap_row);
|
||||||
|
if(tmp.type == TapNoteType_HoldHead &&
|
||||||
|
tmp.subType == TapNoteSubType_Roll)
|
||||||
|
{
|
||||||
|
roll_begins_on_this_beat = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool in_selection_range = false;
|
||||||
|
if(args.selection_begin_marker != -1 && args.selection_end_marker != -1)
|
||||||
|
{
|
||||||
|
in_selection_range = args.selection_begin_marker <= tap_row &&
|
||||||
|
tap_row < args.selection_end_marker;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_addition = (tn.source == TapNoteSource_Addition);
|
||||||
|
bool hopo_possible = (tn.bHopoPossible);
|
||||||
|
bool use_addition_coloring = is_addition || hopo_possible;
|
||||||
|
DrawTap(tn, args.column, NoteRowToVisibleBeat(m_pPlayerState, tap_row),
|
||||||
|
hold_begins_on_this_beat, roll_begins_on_this_beat,
|
||||||
|
use_addition_coloring,
|
||||||
|
in_selection_range ? args.selection_glow : args.fail_fade,
|
||||||
|
m_fYReverseOffsetPixels, args.draw_pixels_after_targets,
|
||||||
|
args.draw_pixels_before_targets, args.fade_before_targets);
|
||||||
|
|
||||||
|
any_upcoming |= NoteRowToBeat(tap_row) >
|
||||||
|
m_pPlayerState->GetDisplayedPosition().m_fSongBeat;
|
||||||
|
|
||||||
|
if(!PREFSMAN->m_FastNoteRendering)
|
||||||
|
{
|
||||||
|
DISPLAY->ClearZBuffer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return any_upcoming;
|
||||||
|
}
|
||||||
|
|
||||||
bool NoteDisplay::DrawHoldHeadForTapsOnSameRow() const
|
bool NoteDisplay::DrawHoldHeadForTapsOnSameRow() const
|
||||||
{
|
{
|
||||||
return cache->m_bDrawHoldHeadForTapsOnSameRow;
|
return cache->m_bDrawHoldHeadForTapsOnSameRow;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#ifndef NOTE_DISPLAY_H
|
#ifndef NOTE_DISPLAY_H
|
||||||
#define NOTE_DISPLAY_H
|
#define NOTE_DISPLAY_H
|
||||||
|
|
||||||
|
#include "NoteData.h"
|
||||||
#include "PlayerNumber.h"
|
#include "PlayerNumber.h"
|
||||||
#include "GameInput.h"
|
#include "GameInput.h"
|
||||||
|
|
||||||
@@ -8,6 +9,7 @@ class Actor;
|
|||||||
class Sprite;
|
class Sprite;
|
||||||
class Model;
|
class Model;
|
||||||
class PlayerState;
|
class PlayerState;
|
||||||
|
class GhostArrowRow;
|
||||||
struct TapNote;
|
struct TapNote;
|
||||||
struct HoldNoteResult;
|
struct HoldNoteResult;
|
||||||
struct NoteMetricCache_t;
|
struct NoteMetricCache_t;
|
||||||
@@ -83,6 +85,30 @@ enum ActiveType
|
|||||||
#define FOREACH_ActiveType( i ) FOREACH_ENUM( ActiveType, i )
|
#define FOREACH_ActiveType( i ) FOREACH_ENUM( ActiveType, i )
|
||||||
const RString &ActiveTypeToString( ActiveType at );
|
const RString &ActiveTypeToString( ActiveType at );
|
||||||
|
|
||||||
|
// A little pod struct to carry the data the NoteField needs to pass to the
|
||||||
|
// NoteDisplay during rendering.
|
||||||
|
struct NoteDisplayRenderArgs
|
||||||
|
{
|
||||||
|
NoteData const& note_data;
|
||||||
|
int column;
|
||||||
|
int draw_pixels_before_targets;
|
||||||
|
int draw_pixels_after_targets;
|
||||||
|
int selection_begin_marker;
|
||||||
|
int selection_end_marker;
|
||||||
|
float selection_glow;
|
||||||
|
float fail_fade;
|
||||||
|
float fade_before_targets;
|
||||||
|
GhostArrowRow& ghost_row;
|
||||||
|
NoteDisplayRenderArgs(NoteData const& nd, int dpbt, int dpat, int sbm,
|
||||||
|
int sem, float sg, float ff, float fbt, GhostArrowRow& gr)
|
||||||
|
:note_data(nd), column(0),
|
||||||
|
draw_pixels_before_targets(dpbt), draw_pixels_after_targets(dpat),
|
||||||
|
selection_begin_marker(sbm), selection_end_marker(sem),
|
||||||
|
selection_glow(sg), fail_fade(ff), fade_before_targets(fbt), ghost_row(gr)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/** @brief Draws TapNotes and HoldNotes. */
|
/** @brief Draws TapNotes and HoldNotes. */
|
||||||
class NoteDisplay
|
class NoteDisplay
|
||||||
{
|
{
|
||||||
@@ -94,6 +120,12 @@ public:
|
|||||||
|
|
||||||
static void Update( float fDeltaTime );
|
static void Update( float fDeltaTime );
|
||||||
|
|
||||||
|
bool IsOnScreen( float fBeat, int iCol, int iDrawDistanceAfterTargetsPixels, int iDrawDistanceBeforeTargetsPixels ) const;
|
||||||
|
|
||||||
|
bool DrawHoldsInRange(NoteDisplayRenderArgs const& args,
|
||||||
|
vector<NoteData::TrackMap::const_iterator> const& tap_set);
|
||||||
|
bool DrawTapsInRange(NoteDisplayRenderArgs const& args,
|
||||||
|
vector<NoteData::TrackMap::const_iterator> const& tap_set);
|
||||||
/**
|
/**
|
||||||
* @brief Draw the TapNote onto the NoteField.
|
* @brief Draw the TapNote onto the NoteField.
|
||||||
* @param tn the TapNote in question.
|
* @param tn the TapNote in question.
|
||||||
|
|||||||
+54
-158
@@ -36,11 +36,8 @@ static ThemeMetric<float> FADE_FAIL_TIME( "NoteField", "FadeFailTime" );
|
|||||||
static RString RoutineNoteSkinName( size_t i ) { return ssprintf("RoutineNoteSkinP%i",int(i+1)); }
|
static RString RoutineNoteSkinName( size_t i ) { return ssprintf("RoutineNoteSkinP%i",int(i+1)); }
|
||||||
static ThemeMetric1D<RString> ROUTINE_NOTESKIN( "NoteField", RoutineNoteSkinName, NUM_PLAYERS );
|
static ThemeMetric1D<RString> ROUTINE_NOTESKIN( "NoteField", RoutineNoteSkinName, NUM_PLAYERS );
|
||||||
|
|
||||||
static bool FAST_NOTE_RENDERING_PREF_CACHED= false;
|
|
||||||
|
|
||||||
NoteField::NoteField()
|
NoteField::NoteField()
|
||||||
{
|
{
|
||||||
FAST_NOTE_RENDERING_PREF_CACHED= PREFSMAN->m_FastNoteRendering;
|
|
||||||
m_pNoteData = NULL;
|
m_pNoteData = NULL;
|
||||||
m_pCurDisplay = NULL;
|
m_pCurDisplay = NULL;
|
||||||
|
|
||||||
@@ -801,13 +798,11 @@ float FindLastDisplayedBeat( const PlayerState* pPlayerState, int iDrawDistanceB
|
|||||||
return fLastBeatToDraw;
|
return fLastBeatToDraw;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline float NoteRowToVisibleBeat( const PlayerState *pPlayerState, int iRow )
|
|
||||||
{
|
|
||||||
return NoteRowToBeat(iRow);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NoteField::IsOnScreen( float fBeat, int iCol, int iDrawDistanceAfterTargetsPixels, int iDrawDistanceBeforeTargetsPixels ) const
|
bool NoteField::IsOnScreen( float fBeat, int iCol, int iDrawDistanceAfterTargetsPixels, int iDrawDistanceBeforeTargetsPixels ) const
|
||||||
{
|
{
|
||||||
|
// IMPORTANT: Do not modify this function without also modifying the
|
||||||
|
// version that is in NoteDisplay.cpp or coming up with a good way to
|
||||||
|
// merge them. -Kyz
|
||||||
// TRICKY: If boomerang is on, then ones in the range
|
// TRICKY: If boomerang is on, then ones in the range
|
||||||
// [iFirstRowToDraw,iLastRowToDraw] aren't necessarily visible.
|
// [iFirstRowToDraw,iLastRowToDraw] aren't necessarily visible.
|
||||||
// Test to see if this beat is visible before drawing.
|
// Test to see if this beat is visible before drawing.
|
||||||
@@ -1208,168 +1203,69 @@ void NoteField::DrawPrimitives()
|
|||||||
ssprintf("NumTracks %d != ColsPerPlayer %d",m_pNoteData->GetNumTracks(),
|
ssprintf("NumTracks %d != ColsPerPlayer %d",m_pNoteData->GetNumTracks(),
|
||||||
GAMESTATE->GetCurrentStyle()->m_iColsPerPlayer));
|
GAMESTATE->GetCurrentStyle()->m_iColsPerPlayer));
|
||||||
|
|
||||||
|
NoteDisplayRenderArgs display_args(*m_pNoteData,
|
||||||
|
iDrawDistanceBeforeTargetsPixels,
|
||||||
|
iDrawDistanceAfterTargetsPixels, m_iBeginMarker, m_iEndMarker,
|
||||||
|
fSelectedRangeGlow, m_fPercentFadeToFail, FADE_BEFORE_TARGETS_PERCENT,
|
||||||
|
m_pCurDisplay->m_GhostArrowRow);
|
||||||
for( int j=0; j<m_pNoteData->GetNumTracks(); j++ ) // for each arrow column
|
for( int j=0; j<m_pNoteData->GetNumTracks(); j++ ) // for each arrow column
|
||||||
{
|
{
|
||||||
const int c = pStyle->m_iColumnDrawOrder[j];
|
const int c = pStyle->m_iColumnDrawOrder[j];
|
||||||
|
display_args.column= c;
|
||||||
bool bAnyUpcomingInThisCol = false;
|
bool any_upcoming= false;
|
||||||
|
// Build lists of holds and taps for each player number, then pass those
|
||||||
// Draw all HoldNotes in this column (so that they appear under the tap notes)
|
// lists to the displays to draw.
|
||||||
{
|
// The vector in the NUM_PlayerNumber slot should stay empty, not worth
|
||||||
NoteData::TrackMap::const_iterator begin, end;
|
// optimizing it out. -Kyz
|
||||||
m_pNoteData->GetTapNoteRangeInclusive( c, iFirstRowToDraw, iLastRowToDraw+1, begin, end );
|
vector<vector<NoteData::TrackMap::const_iterator> > holds(PLAYER_INVALID+1);
|
||||||
|
vector<vector<NoteData::TrackMap::const_iterator> > taps(PLAYER_INVALID+1);
|
||||||
for( ; begin != end; ++begin )
|
|
||||||
{
|
|
||||||
const TapNote &tn = begin->second; //m_pNoteData->GetTapNote(c, j);
|
|
||||||
if( tn.type != TapNoteType_HoldHead )
|
|
||||||
continue; // skip
|
|
||||||
|
|
||||||
const HoldNoteResult &Result = tn.HoldResult;
|
|
||||||
if( Result.hns == HNS_Held ) // 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
|
|
||||||
// [iFirstRowToDraw,iLastRowToDraw] aren't necessarily visible.
|
|
||||||
// Test every note to make sure it's on screen before drawing
|
|
||||||
float fThrowAway;
|
|
||||||
bool bStartIsPastPeak = false;
|
|
||||||
bool bEndIsPastPeak = false;
|
|
||||||
float fStartYOffset = ArrowEffects::GetYOffset( m_pPlayerState, c, NoteRowToVisibleBeat(m_pPlayerState, iStartRow), fThrowAway, bStartIsPastPeak );
|
|
||||||
float fEndYOffset = ArrowEffects::GetYOffset( m_pPlayerState, c, NoteRowToVisibleBeat(m_pPlayerState, iEndRow), fThrowAway, bEndIsPastPeak );
|
|
||||||
|
|
||||||
bool bTailIsOnVisible = iDrawDistanceAfterTargetsPixels <= fEndYOffset && fEndYOffset <= iDrawDistanceBeforeTargetsPixels;
|
|
||||||
bool bHeadIsVisible = iDrawDistanceAfterTargetsPixels <= fStartYOffset && fStartYOffset <= iDrawDistanceBeforeTargetsPixels;
|
|
||||||
bool bStraddlingVisible = fStartYOffset <= iDrawDistanceAfterTargetsPixels && iDrawDistanceBeforeTargetsPixels <= fEndYOffset;
|
|
||||||
bool bStaddlingPeak = bStartIsPastPeak && !bEndIsPastPeak;
|
|
||||||
if( !(bTailIsOnVisible || bHeadIsVisible || bStraddlingVisible || bStaddlingPeak) )
|
|
||||||
{
|
|
||||||
//LOG->Trace( "skip drawing this hold." );
|
|
||||||
continue; // skip
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bIsAddition = (tn.source == TapNoteSource_Addition);
|
|
||||||
bool bIsHopoPossible = (tn.bHopoPossible);
|
|
||||||
bool bUseAdditionColoring = bIsAddition || bIsHopoPossible;
|
|
||||||
const bool bHoldGhostShowing = tn.HoldResult.bActive && tn.HoldResult.fLife > 0;
|
|
||||||
const bool bIsHoldingNote = tn.HoldResult.bHeld;
|
|
||||||
if( bHoldGhostShowing )
|
|
||||||
m_pCurDisplay->m_GhostArrowRow.SetHoldShowing( c, tn );
|
|
||||||
|
|
||||||
ASSERT_M( NoteRowToBeat(iStartRow) > -2000, ssprintf("%i %i %i", iStartRow, iEndRow, c) );
|
|
||||||
|
|
||||||
bool bIsInSelectionRange = false;
|
|
||||||
if( m_iBeginMarker!=-1 && m_iEndMarker!=-1 )
|
|
||||||
bIsInSelectionRange = (m_iBeginMarker <= iStartRow && iEndRow < m_iEndMarker);
|
|
||||||
|
|
||||||
NoteDisplayCols *displayCols = tn.pn == PLAYER_INVALID ? m_pCurDisplay : m_pDisplays[tn.pn];
|
|
||||||
displayCols->display[c].DrawHold( tn, c, iStartRow, bIsHoldingNote, Result, bUseAdditionColoring, bIsInSelectionRange ? fSelectedRangeGlow : m_fPercentFadeToFail,
|
|
||||||
m_fYReverseOffsetPixels, (float) iDrawDistanceAfterTargetsPixels, (float) iDrawDistanceBeforeTargetsPixels, iDrawDistanceBeforeTargetsPixels, FADE_BEFORE_TARGETS_PERCENT );
|
|
||||||
|
|
||||||
bool bNoteIsUpcoming = NoteRowToBeat(iStartRow) > m_pPlayerState->GetDisplayedPosition().m_fSongBeat;
|
|
||||||
bAnyUpcomingInThisCol |= bNoteIsUpcoming;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw all TapNotes in this column
|
|
||||||
|
|
||||||
// draw notes from furthest to closest
|
|
||||||
NoteData::TrackMap::const_iterator begin, end;
|
NoteData::TrackMap::const_iterator begin, end;
|
||||||
m_pNoteData->GetTapNoteRange( c, iFirstRowToDraw, iLastRowToDraw+1, begin, end );
|
m_pNoteData->GetTapNoteRangeInclusive(c, iFirstRowToDraw,
|
||||||
for( ; begin != end; ++begin )
|
iLastRowToDraw+1, begin, end);
|
||||||
|
for(; begin != end; ++begin)
|
||||||
{
|
{
|
||||||
int q = begin->first;
|
TapNote const& tn= begin->second;
|
||||||
const TapNote &tn = begin->second; //m_pNoteData->GetTapNote(c, q);
|
switch(tn.type)
|
||||||
|
|
||||||
// Switch modified by Wolfman2000, tested by Saturn2888
|
|
||||||
// Fixes hold head overlapping issue, but not the rolls.
|
|
||||||
switch( tn.type )
|
|
||||||
{
|
{
|
||||||
case TapNoteType_Empty: // no note here
|
case TapNoteType_Empty:
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
case TapNoteType_Tap:
|
||||||
|
case TapNoteType_HoldTail:
|
||||||
|
case TapNoteType_Mine:
|
||||||
|
case TapNoteType_Lift:
|
||||||
|
case TapNoteType_Attack:
|
||||||
|
case TapNoteType_AutoKeysound:
|
||||||
|
case TapNoteType_Fake:
|
||||||
|
if(!tn.result.bHidden)
|
||||||
|
{
|
||||||
|
taps[tn.pn].push_back(begin);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case TapNoteType_HoldHead:
|
case TapNoteType_HoldHead:
|
||||||
{
|
if(tn.HoldResult.hns != HNS_Held)
|
||||||
//if (tn.subType == TapNoteSubType_Roll)
|
|
||||||
continue; // skip
|
|
||||||
}
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't draw hidden (fully judged) steps.
|
|
||||||
if( tn.result.bHidden )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// TRICKY: If boomerang is on, then all notes in the range
|
|
||||||
// [iFirstRowToDraw,iLastRowToDraw] aren't necessarily visible.
|
|
||||||
// Test every note to make sure it's on screen before drawing.
|
|
||||||
if( !IsOnScreen( NoteRowToBeat(q), c, iDrawDistanceAfterTargetsPixels, iDrawDistanceBeforeTargetsPixels ) )
|
|
||||||
continue; // skip
|
|
||||||
|
|
||||||
ASSERT_M( NoteRowToBeat(q) > -2000, ssprintf("%i %i %i, %f %f", q, iLastRowToDraw,
|
|
||||||
iFirstRowToDraw, m_pPlayerState->GetDisplayedPosition().m_fSongBeat, m_pPlayerState->GetDisplayedPosition().m_fMusicSeconds) );
|
|
||||||
|
|
||||||
// See if there is a hold step that begins on this index.
|
|
||||||
// Only do this if the noteskin cares.
|
|
||||||
bool bHoldNoteBeginsOnThisBeat = false;
|
|
||||||
if( m_pCurDisplay->display[c].DrawHoldHeadForTapsOnSameRow() )
|
|
||||||
{
|
|
||||||
for( int c2=0; c2<m_pNoteData->GetNumTracks(); c2++ )
|
|
||||||
{
|
|
||||||
const TapNote &tmp = m_pNoteData->GetTapNote(c2, q);
|
|
||||||
if(tmp.type == TapNoteType_HoldHead &&
|
|
||||||
tmp.subType == TapNoteSubType_Hold)
|
|
||||||
{
|
{
|
||||||
bHoldNoteBeginsOnThisBeat = true;
|
holds[tn.pn].push_back(begin);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
// do the same for a roll.
|
|
||||||
bool bRollNoteBeginsOnThisBeat = false;
|
|
||||||
if (m_pCurDisplay->display[c].DrawRollHeadForTapsOnSameRow() )
|
|
||||||
{
|
|
||||||
for( int c2=0; c2<m_pNoteData->GetNumTracks(); c2++ )
|
|
||||||
{
|
|
||||||
const TapNote &tmp = m_pNoteData->GetTapNote(c2, q);
|
|
||||||
if(tmp.type == TapNoteType_HoldHead &&
|
|
||||||
tmp.subType == TapNoteSubType_Roll)
|
|
||||||
{
|
|
||||||
bRollNoteBeginsOnThisBeat = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bIsInSelectionRange = false;
|
|
||||||
if( m_iBeginMarker!=-1 && m_iEndMarker!=-1 )
|
|
||||||
bIsInSelectionRange = m_iBeginMarker<=q && q<m_iEndMarker;
|
|
||||||
|
|
||||||
bool bIsAddition = (tn.source == TapNoteSource_Addition);
|
|
||||||
bool bIsHopoPossible = (tn.bHopoPossible);
|
|
||||||
bool bUseAdditionColoring = bIsAddition || bIsHopoPossible;
|
|
||||||
NoteDisplayCols *displayCols = tn.pn == PLAYER_INVALID ? m_pCurDisplay : m_pDisplays[tn.pn];
|
|
||||||
displayCols->display[c].DrawTap(tn, c, NoteRowToVisibleBeat(m_pPlayerState, q),
|
|
||||||
bHoldNoteBeginsOnThisBeat, bRollNoteBeginsOnThisBeat,
|
|
||||||
bUseAdditionColoring, bIsInSelectionRange ? fSelectedRangeGlow : m_fPercentFadeToFail,
|
|
||||||
m_fYReverseOffsetPixels, iDrawDistanceAfterTargetsPixels, iDrawDistanceBeforeTargetsPixels,
|
|
||||||
FADE_BEFORE_TARGETS_PERCENT );
|
|
||||||
|
|
||||||
bool bNoteIsUpcoming = NoteRowToBeat(q) > m_pPlayerState->GetDisplayedPosition().m_fSongBeat;
|
|
||||||
bAnyUpcomingInThisCol |= bNoteIsUpcoming;
|
|
||||||
|
|
||||||
if(!FAST_NOTE_RENDERING_PREF_CACHED)
|
|
||||||
{
|
|
||||||
DISPLAY->ClearZBuffer();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#define DTS_INNER(pn, tap_set, draw_func, disp) \
|
||||||
cur->m_ReceptorArrowRow.SetNoteUpcoming( c, bAnyUpcomingInThisCol );
|
if(!tap_set[pn].empty()) \
|
||||||
|
{ \
|
||||||
|
any_upcoming|= disp->display[c].draw_func(display_args, tap_set[pn]); \
|
||||||
|
}
|
||||||
|
#define DRAW_TAP_SET(tap_set, draw_func) \
|
||||||
|
FOREACH_PlayerNumber(pn) \
|
||||||
|
{ \
|
||||||
|
DTS_INNER(pn, tap_set, draw_func, m_pDisplays[pn]); \
|
||||||
|
}
|
||||||
|
DRAW_TAP_SET(holds, DrawHoldsInRange);
|
||||||
|
DTS_INNER(PLAYER_INVALID, holds, DrawHoldsInRange, m_pCurDisplay);
|
||||||
|
DRAW_TAP_SET(taps, DrawTapsInRange);
|
||||||
|
DTS_INNER(PLAYER_INVALID, taps, DrawTapsInRange, m_pCurDisplay);
|
||||||
|
#undef DTS_INNER
|
||||||
|
#undef DRAW_TAP_SET
|
||||||
|
cur->m_ReceptorArrowRow.SetNoteUpcoming(c, any_upcoming);
|
||||||
}
|
}
|
||||||
|
|
||||||
cur->m_GhostArrowRow.Draw();
|
cur->m_GhostArrowRow.Draw();
|
||||||
|
|||||||
Reference in New Issue
Block a user