diff --git a/Themes/default/BGAnimations/ScreenGameplay underlay/ScreenFilter.lua b/Themes/default/BGAnimations/ScreenGameplay underlay/ScreenFilter.lua deleted file mode 100644 index bba442f8e6..0000000000 --- a/Themes/default/BGAnimations/ScreenGameplay underlay/ScreenFilter.lua +++ /dev/null @@ -1,65 +0,0 @@ ---[[ Screen Filter ]] -local numPlayers = GAMESTATE:GetNumPlayersEnabled() -local center1P = PREFSMAN:GetPreference("Center1Player") - -local padding = 8 -- 4px on each side -local arrowWidth = 64 -- until noteskin metrics are implemented... - -local filterColor = color("0.135,0.135,0.135,1") -local filterAlphas = { - PlayerNumber_P1 = 1, - PlayerNumber_P2 = 1, - Default = 0, -} - -local t = Def.ActorFrame{}; - -local style = GAMESTATE:GetCurrentStyle() -local cols = style:ColumnsPerPlayer() -local styleType = ToEnumShortString(style:GetStyleType()) -local filterWidth = (arrowWidth * cols) + padding - -if numPlayers == 1 then - local player = GAMESTATE:GetMasterPlayerNumber() - local pNum = (player == PLAYER_1) and 1 or 2 - filterAlphas[player] = tonumber(getenv("ScreenFilterP"..pNum)); - - local pos; - -- [ScreenGameplay] PlayerP#Player*Side(s)X - if center1P then - pos = SCREEN_CENTER_X - else - local metricName = string.format("PlayerP%i%sX",pNum,styleType) - pos = THEME:GetMetric("ScreenGameplay",metricName) - end - t[#t+1] = Def.Quad{ - Name="SinglePlayerFilter"; - InitCommand=cmd(x,pos;CenterY;zoomto,filterWidth,SCREEN_HEIGHT;diffusecolor,filterColor;diffusealpha,filterAlphas[player]); - }; -else - -- two players... a bit more complex. - if styleType == "TwoPlayersSharedSides" then - -- routine, just use one in the center. - local player = GAMESTATE:GetMasterPlayerNumber() - local pNum = player == PLAYER_1 and 1 or 2 - local metricName = "PlayerP".. pNum .."TwoPlayersSharedSidesX" - t[#t+1] = Def.Quad{ - Name="RoutineFilter"; - InitCommand=cmd(x,THEME:GetMetric("ScreenGameplay",metricName);CenterY;zoomto,filterWidth,SCREEN_HEIGHT;diffusecolor,filterColor;diffusealpha,filterAlphas[player]); - }; - else - -- otherwise we need two separate ones. to the pairsmobile! - for i, player in ipairs(PlayerNumber) do - local pNum = (player == PLAYER_1) and 1 or 2 - filterAlphas[player] = tonumber(getenv("ScreenFilterP"..pNum)); - local metricName = string.format("PlayerP%i%sX",pNum,styleType) - local pos = THEME:GetMetric("ScreenGameplay",metricName) - t[#t+1] = Def.Quad{ - Name="Player"..pNum.."Filter"; - InitCommand=cmd(x,pos;CenterY;zoomto,filterWidth,SCREEN_HEIGHT;diffusecolor,filterColor;diffusealpha,filterAlphas[player]); - }; - end - end -end - -return t; \ No newline at end of file diff --git a/Themes/default/BGAnimations/ScreenGameplay underlay/danger.lua b/Themes/default/BGAnimations/ScreenGameplay underlay/danger.lua deleted file mode 100644 index d5f5ccf3c8..0000000000 --- a/Themes/default/BGAnimations/ScreenGameplay underlay/danger.lua +++ /dev/null @@ -1,27 +0,0 @@ -local players = GAMESTATE:GetHumanPlayers() - -local t = Def.ActorFrame {}; - -for pn=1,#players do - t[#t+1] = Def.ActorFrame { - InitCommand=function(self) - self:y(SCREEN_CENTER_Y) - self:x( - THEME:GetMetric( - Var "LoadingScreen", - "Player" .. ToEnumShortString(players[pn]) .. ToEnumShortString(GAMESTATE:GetCurrentStyle(pn):GetStyleType()) .. "X" - ) - ) - end, - Def.Quad { - InitCommand=function(self) - (cmd('fadeleft,0.1;faderight,0.1;zoomtoheight,SCREEN_HEIGHT'))(self) - self:zoomtowidth( - Center1Player() and SCREEN_WIDTH-32 or SCREEN_CENTER_X-16 - ) - end - }; - }; -end - -return t \ No newline at end of file diff --git a/Themes/default/BGAnimations/ScreenGameplay underlay/default.lua b/Themes/default/BGAnimations/ScreenGameplay underlay/default.lua deleted file mode 100644 index 9288655856..0000000000 --- a/Themes/default/BGAnimations/ScreenGameplay underlay/default.lua +++ /dev/null @@ -1,6 +0,0 @@ -local t = Def.ActorFrame{ - --LoadActor("danger"); - LoadActor("ScreenFilter"); -}; - -return t; \ No newline at end of file diff --git a/Themes/default/Graphics/NoteField board.png b/Themes/default/Graphics/NoteField board.png deleted file mode 100644 index dc75b2a2d2..0000000000 Binary files a/Themes/default/Graphics/NoteField board.png and /dev/null differ diff --git a/Themes/default/metrics.ini b/Themes/default/metrics.ini index e203750488..33faf32866 100644 --- a/Themes/default/metrics.ini +++ b/Themes/default/metrics.ini @@ -316,7 +316,7 @@ GradeP2X=110+16 GradeP2Y=8 [NoteField] -ShowBoard=GAMESTATE:GetCurrentGame():GetName() == "kb7" +ShowBoard=true [PlayerStageStats] diff --git a/src/Background.cpp b/src/Background.cpp index e31d273708..60d39d93a9 100644 --- a/src/Background.cpp +++ b/src/Background.cpp @@ -962,7 +962,7 @@ void BrightnessOverlay::FadeToActualBrightness() SetActualBrightness(); } -Background::Background() { m_pImpl = new BackgroundImpl; this->AddChild(m_pImpl); } +Background::Background() { m_disable_draw= false; m_pImpl = new BackgroundImpl; this->AddChild(m_pImpl); } Background::~Background() { SAFE_DELETE( m_pImpl ); } void Background::Init() { m_pImpl->Init(); } void Background::LoadFromSong( const Song *pSong ) { m_pImpl->LoadFromSong(pSong); } diff --git a/src/Background.h b/src/Background.h index 9b86644750..f0785d9cfb 100644 --- a/src/Background.h +++ b/src/Background.h @@ -23,6 +23,13 @@ public: void FadeToActualBrightness(); void SetBrightness( float fBrightness ); // overrides pref and Cover + // One more piece of the puzzle that puts the notefield board above the bg + // and under everything else. m_disable_draw exists so that + // ScreenGameplay can draw the background manually, and still have it as a + // child. -Kyz + bool m_disable_draw; + virtual bool EarlyAbortDraw() const { return m_disable_draw; } + /** * @brief Retrieve whatever dancing characters are in use. * @return the dancing characters. */ diff --git a/src/NoteField.cpp b/src/NoteField.cpp index 33a3b04b94..82fb8bbdbe 100644 --- a/src/NoteField.cpp +++ b/src/NoteField.cpp @@ -40,6 +40,7 @@ NoteField::NoteField() { m_pNoteData = NULL; m_pCurDisplay = NULL; + m_drawing_board_primitive= false; m_textMeasureNumber.LoadFromFont( THEME->GetPathF("NoteField","MeasureNumber") ); m_textMeasureNumber.SetZoom( 1.0f ); @@ -194,6 +195,12 @@ void NoteField::Init( const PlayerState* pPlayerState, float fYReverseOffsetPixe { SetZoom(pPlayerState->m_NotefieldZoom); } + // Pass the player state info down to children so that they can set + // per-player things. For example, if a screen filter is in the notefield + // board, this tells it what player it's for. -Kyz + Message msg("PlayerStateSet"); + msg.SetParam("PlayerNumber", pPlayerState->m_PlayerNumber); + HandleMessage(msg); } void NoteField::Load( @@ -865,6 +872,31 @@ bool NoteField::IsOnScreen( float fBeat, int iCol, int iDrawDistanceAfterTargets return true; } +void NoteField::CalcPixelsBeforeAndAfterTargets() +{ + const PlayerOptions& curr_options= m_pPlayerState->m_PlayerOptions.GetCurrent(); + // Adjust draw range depending on some effects + m_FieldRenderArgs.draw_pixels_after_targets= m_iDrawDistanceAfterTargetsPixels; + // HACK: If boomerang and centered are on, then we want to draw much + // earlier so that the notes don't pop on screen. + float centered_times_boomerang= + curr_options.m_fScrolls[PlayerOptions::SCROLL_CENTERED] * + curr_options.m_fAccels[PlayerOptions::ACCEL_BOOMERANG]; + m_FieldRenderArgs.draw_pixels_after_targets += + int(SCALE(centered_times_boomerang, 0.f, 1.f, 0.f, -SCREEN_HEIGHT/2)); + m_FieldRenderArgs.draw_pixels_before_targets = + m_iDrawDistanceBeforeTargetsPixels; + + float draw_scale= 1; + draw_scale*= 1 + 0.5f * fabsf(curr_options.m_fPerspectiveTilt); + draw_scale*= 1 + fabsf(curr_options.m_fEffects[PlayerOptions::EFFECT_MINI]); + + m_FieldRenderArgs.draw_pixels_after_targets= + (int)(m_FieldRenderArgs.draw_pixels_after_targets * draw_scale); + m_FieldRenderArgs.draw_pixels_before_targets= + (int)(m_FieldRenderArgs.draw_pixels_before_targets * draw_scale); +} + void NoteField::DrawPrimitives() { //LOG->Trace( "NoteField::DrawPrimitives()" ); @@ -872,49 +904,36 @@ void NoteField::DrawPrimitives() // This should be filled in on the first update. ASSERT( m_pCurDisplay != NULL ); - ArrowEffects::Update(); + // ArrowEffects::Update call moved because having it happen once per + // NoteField (which means twice in two player) seemed wasteful. -Kyz + if(m_drawing_board_primitive) + { + CalcPixelsBeforeAndAfterTargets(); + DrawBoard(m_FieldRenderArgs.draw_pixels_after_targets, + m_FieldRenderArgs.draw_pixels_before_targets); + return; + } + // Some might prefer an else block, instead of returning from the if, but I + // don't want to bump the indent on the entire remaining section. -Kyz + + CalcPixelsBeforeAndAfterTargets(); NoteDisplayCols *cur = m_pCurDisplay; - - const PlayerOptions ¤t_po = m_pPlayerState->m_PlayerOptions.GetCurrent(); - - // Adjust draw range depending on some effects - m_FieldRenderArgs.draw_pixels_after_targets= m_iDrawDistanceAfterTargetsPixels; - // HACK: If boomerang and centered are on, then we want to draw much - // earlier so that the notes don't pop on screen. - float fCenteredTimesBoomerang = - current_po.m_fScrolls[PlayerOptions::SCROLL_CENTERED] * - current_po.m_fAccels[PlayerOptions::ACCEL_BOOMERANG]; - m_FieldRenderArgs.draw_pixels_after_targets += int(SCALE( fCenteredTimesBoomerang, 0.f, 1.f, 0.f, -SCREEN_HEIGHT/2 )); - m_FieldRenderArgs.draw_pixels_before_targets = m_iDrawDistanceBeforeTargetsPixels; - - float fDrawScale = 1; - fDrawScale *= 1 + 0.5f * fabsf( current_po.m_fPerspectiveTilt ); - fDrawScale *= 1 + fabsf( current_po.m_fEffects[PlayerOptions::EFFECT_MINI] ); - - m_FieldRenderArgs.draw_pixels_after_targets = (int)(m_FieldRenderArgs.draw_pixels_after_targets * fDrawScale); - m_FieldRenderArgs.draw_pixels_before_targets = (int)(m_FieldRenderArgs.draw_pixels_before_targets * fDrawScale); - - // Probe for first and last notes on the screen - float fFirstBeatToDraw = FindFirstDisplayedBeat( m_pPlayerState, m_FieldRenderArgs.draw_pixels_after_targets ); - float fLastBeatToDraw = FindLastDisplayedBeat( m_pPlayerState, m_FieldRenderArgs.draw_pixels_before_targets ); + float first_beat_to_draw= FindFirstDisplayedBeat( + m_pPlayerState, m_FieldRenderArgs.draw_pixels_after_targets); + float last_beat_to_draw= FindLastDisplayedBeat( + m_pPlayerState, m_FieldRenderArgs.draw_pixels_before_targets); - m_pPlayerState->m_fLastDrawnBeat = fLastBeatToDraw; + m_pPlayerState->m_fLastDrawnBeat = last_beat_to_draw; - m_FieldRenderArgs.first_row = BeatToNoteRow(fFirstBeatToDraw); - m_FieldRenderArgs.last_row = BeatToNoteRow(fLastBeatToDraw); + m_FieldRenderArgs.first_row = BeatToNoteRow(first_beat_to_draw); + m_FieldRenderArgs.last_row = BeatToNoteRow(last_beat_to_draw); - //LOG->Trace( "start = %f.1, end = %f.1", fFirstBeatToDraw-fSongBeat, fLastBeatToDraw-fSongBeat ); + //LOG->Trace( "start = %f.1, end = %f.1", first_beat_to_draw-fSongBeat, last_beat_to_draw-fSongBeat ); //LOG->Trace( "Drawing elements %d through %d", m_FieldRenderArgs.first_row, m_FieldRenderArgs.last_row ); -#define IS_ON_SCREEN( fBeat ) ( fFirstBeatToDraw <= (fBeat) && (fBeat) <= fLastBeatToDraw && IsOnScreen( fBeat, 0, m_FieldRenderArgs.draw_pixels_after_targets, m_FieldRenderArgs.draw_pixels_before_targets ) ) - - // Draw board - if( SHOW_BOARD ) - { - DrawBoard( m_FieldRenderArgs.draw_pixels_after_targets, m_FieldRenderArgs.draw_pixels_before_targets ); - } +#define IS_ON_SCREEN(fBeat) (first_beat_to_draw <= (fBeat) && (fBeat) <= last_beat_to_draw && IsOnScreen(fBeat, 0, m_FieldRenderArgs.draw_pixels_after_targets, m_FieldRenderArgs.draw_pixels_before_targets)) // Draw Receptors { @@ -1264,6 +1283,17 @@ void NoteField::DrawPrimitives() cur->m_GhostArrowRow.Draw(); } +void NoteField::DrawBoardPrimitive() +{ + if(!SHOW_BOARD) + { + return; + } + m_drawing_board_primitive= true; + Draw(); + m_drawing_board_primitive= false; +} + void NoteField::FadeToFail() { m_FieldRenderArgs.fail_fade = max( 0.0f, m_FieldRenderArgs.fail_fade ); // this will slowly increase every Update() diff --git a/src/NoteField.h b/src/NoteField.h index 52ec04be15..67d47ce911 100644 --- a/src/NoteField.h +++ b/src/NoteField.h @@ -21,6 +21,8 @@ public: ~NoteField(); virtual void Update( float fDeltaTime ); virtual void DrawPrimitives(); + void CalcPixelsBeforeAndAfterTargets(); + void DrawBoardPrimitive(); virtual void Init( const PlayerState* pPlayerState, float fYReverseOffsetPixels, bool use_states_zoom= true ); virtual void Load( @@ -95,6 +97,9 @@ protected: int m_iDrawDistanceBeforeTargetsPixels; // this should be a positive number float m_fYReverseOffsetPixels; + // This exists so that the board can be drawn underneath combo/judge. -Kyz + bool m_drawing_board_primitive; + // color arrows struct NoteDisplayCols { diff --git a/src/Player.cpp b/src/Player.cpp index 8c5582b1a9..ebf7fa9b50 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -214,6 +214,7 @@ float Player::GetWindowSeconds( TimingWindow tw ) Player::Player( NoteData &nd, bool bVisibleParts ) : m_NoteData(nd) { + m_drawing_notefield_board= false; m_bLoaded = false; m_pPlayerState = NULL; @@ -1510,10 +1511,30 @@ void Player::DrawPrimitives() pn != GAMESTATE->GetMasterPlayerNumber() ) return; + bool draw_notefield= m_pNoteField && !IsOniDead(); + + const PlayerOptions& curr_options= m_pPlayerState->m_PlayerOptions.GetCurrent(); + float tilt= curr_options.m_fPerspectiveTilt; + float skew= curr_options.m_fSkew; + float mini= curr_options.m_fEffects[PlayerOptions::EFFECT_MINI]; + float center_y= GetY() + (GRAY_ARROWS_Y_STANDARD + GRAY_ARROWS_Y_REVERSE) / 2; + bool reverse= curr_options.GetReversePercentForColumn(0) > .5; + + if(m_drawing_notefield_board) + { + // Ask the Notefield to draw its board primitive before everything else + // so that things drawn under the field aren't behind the opaque board. + // -Kyz + if(draw_notefield) + { + PlayerNoteFieldPositioner poser(this, GetX(), tilt, skew, mini, center_y, reverse); + m_pNoteField->DrawBoardPrimitive(); + } + return; + } + // Draw these below everything else. - // xxx: if NoteField Board is enabled and COMBO_UNDER_FIELD, we really want - // the combo under the field but over the notefield board. -aj - if( COMBO_UNDER_FIELD && m_pPlayerState->m_PlayerOptions.GetCurrent().m_fBlind == 0 ) + if( COMBO_UNDER_FIELD && curr_options.m_fBlind == 0 ) { if( m_sprCombo ) m_sprCombo->Draw(); @@ -1528,48 +1549,14 @@ void Player::DrawPrimitives() if( HOLD_JUDGMENTS_UNDER_FIELD ) DrawHoldJudgments(); - float fTilt = m_pPlayerState->m_PlayerOptions.GetCurrent().m_fPerspectiveTilt; - float fSkew = m_pPlayerState->m_PlayerOptions.GetCurrent().m_fSkew; - bool bReverse = m_pPlayerState->m_PlayerOptions.GetCurrent().GetReversePercentForColumn(0)>0.5; - - DISPLAY->CameraPushMatrix(); - DISPLAY->PushMatrix(); - - float fCenterY = this->GetY()+(GRAY_ARROWS_Y_STANDARD+GRAY_ARROWS_Y_REVERSE)/2; - - DISPLAY->LoadMenuPerspective( 45, SCREEN_WIDTH, SCREEN_HEIGHT, SCALE(fSkew,0.f,1.f,this->GetX(),SCREEN_CENTER_X), fCenterY ); - - if( m_pNoteField && !IsOniDead() ) + if(draw_notefield) { - float fOriginalY = m_pNoteField->GetY(); - - float fTiltDegrees = SCALE(fTilt,-1.f,+1.f,+30,-30) * (bReverse?-1:1); - - float fZoom = SCALE( m_pPlayerState->m_PlayerOptions.GetCurrent().m_fEffects[PlayerOptions::EFFECT_MINI], 0.f, 1.f, 1.f, 0.5f ); - if( fTilt > 0 ) - fZoom *= SCALE( fTilt, 0.f, 1.f, 1.f, 0.9f ); - else - fZoom *= SCALE( fTilt, 0.f, -1.f, 1.f, 0.9f ); - - float fYOffset; - if( fTilt > 0 ) - fYOffset = SCALE( fTilt, 0.f, 1.f, 0.f, -45.f ) * (bReverse?-1:1); - else - fYOffset = SCALE( fTilt, 0.f, -1.f, 0.f, -20.f ) * (bReverse?-1:1); - - m_pNoteField->SetY( fOriginalY + fYOffset ); - m_pNoteField->SetZoom( fZoom ); - m_pNoteField->SetRotationX( fTiltDegrees ); + PlayerNoteFieldPositioner poser(this, GetX(), tilt, skew, mini, center_y, reverse); m_pNoteField->Draw(); - - m_pNoteField->SetY( fOriginalY ); } - DISPLAY->CameraPopMatrix(); - DISPLAY->PopMatrix(); - // m_pNoteField->m_sprBoard->GetVisible() - if( !COMBO_UNDER_FIELD && m_pPlayerState->m_PlayerOptions.GetCurrent().m_fBlind == 0 ) + if( !COMBO_UNDER_FIELD && curr_options.m_fBlind == 0 ) if( m_sprCombo ) m_sprCombo->Draw(); @@ -1580,6 +1567,61 @@ void Player::DrawPrimitives() DrawHoldJudgments(); } +void Player::PushPlayerMatrix(float x, float skew, float center_y) +{ + DISPLAY->CameraPushMatrix(); + DISPLAY->PushMatrix(); + DISPLAY->LoadMenuPerspective(45, SCREEN_WIDTH, SCREEN_HEIGHT, + SCALE(skew, 0.1f, 1.0f, x, SCREEN_CENTER_X), center_y); +} + +void Player::PopPlayerMatrix() +{ + DISPLAY->CameraPopMatrix(); + DISPLAY->PopMatrix(); +} + +void Player::DrawNoteFieldBoard() +{ + m_drawing_notefield_board= true; + Draw(); + m_drawing_notefield_board= false; +} + +Player::PlayerNoteFieldPositioner::PlayerNoteFieldPositioner( + Player* p, float x, float tilt, float skew, float mini, float center_y, bool reverse) + :player(p) +{ + player->PushPlayerMatrix(x, skew, center_y); + float reverse_mult= (reverse ? -1 : 1); + original_y= player->m_pNoteField->GetY(); + float tilt_degrees= SCALE(tilt, -1.f, +1.f, +30, -30) * reverse_mult; + float zoom= SCALE(mini, 0.f, 1.f, 1.f, .5f); + // Something strange going on here. Notice that the range for tilt's + // effect on y_offset goes to -45 when positive, but -20 when negative. + // I don't know why it's done this why, simply preserving old behavior. + // -Kyz + if(tilt > 0) + { + zoom*= SCALE(tilt, 0.f, 1.f, 1.f, 0.9f); + y_offset= SCALE(tilt, 0.f, 1.f, 0.f, -45.f) * reverse_mult; + } + else + { + zoom*= SCALE(tilt, 0.f, -1.f, 1.f, 0.9f); + y_offset= SCALE(tilt, 0.f, -1.f, 0.f, -20.f) * reverse_mult; + } + player->m_pNoteField->SetY(original_y + y_offset); + player->m_pNoteField->SetZoom(zoom); + player->m_pNoteField->SetRotationX(tilt_degrees); +} + +Player::PlayerNoteFieldPositioner::~PlayerNoteFieldPositioner() +{ + player->m_pNoteField->SetY(original_y); + player->PopPlayerMatrix(); +} + void Player::DrawTapJudgments() { if( m_pPlayerState->m_PlayerOptions.GetCurrent().m_fBlind > 0 ) diff --git a/src/Player.h b/src/Player.h index acdb82bed2..a5e272ca59 100644 --- a/src/Player.h +++ b/src/Player.h @@ -46,6 +46,29 @@ public: virtual void Update( float fDeltaTime ); virtual void DrawPrimitives(); + // PushPlayerMatrix and PopPlayerMatrix are separate functions because + // they need to be used twice so that the notefield board can rendered + // underneath the combo and judgment. They're not embedded in + // PlayerMatrixPusher so that some nutjob can later decide to expose them + // to lua. -Kyz + void PushPlayerMatrix(float x, float skew, float center_y); + void PopPlayerMatrix(); + + // This exists so that the board can be drawn underneath combo/judge. -Kyz + void DrawNoteFieldBoard(); + + // Here's a fun construct for people that haven't seen it before: + // This object does some task when it's created, then cleans up when it's + // destroyed. That way, you stick it inside a block, and can't forget the + // cleanup. -Kyz + struct PlayerNoteFieldPositioner + { + PlayerNoteFieldPositioner(Player* p, float x, float tilt, float skew, float mini, float center_y, bool reverse); + ~PlayerNoteFieldPositioner(); + Player* player; + float original_y; + float y_offset; + }; struct TrackRowTapNote { @@ -232,6 +255,8 @@ protected: bool m_bSendJudgmentAndComboMessages; bool m_bTickHolds; + // This exists so that the board can be drawn underneath combo/judge. -Kyz + bool m_drawing_notefield_board; }; class PlayerPlus diff --git a/src/ScreenGameplay.cpp b/src/ScreenGameplay.cpp index 44cdebc0cc..7b307f3055 100644 --- a/src/ScreenGameplay.cpp +++ b/src/ScreenGameplay.cpp @@ -23,6 +23,7 @@ #include "ScoreKeeperRave.h" #include "LyricsLoader.h" #include "ActorUtil.h" +#include "ArrowEffects.h" #include "RageSoundManager.h" #include "RageSoundReader.h" #include "RageTextureManager.h" @@ -2009,6 +2010,35 @@ void ScreenGameplay::Update( float fDeltaTime ) if( m_bShowScoreboard && NSMAN->ChangedScoreboard(cn) && GAMESTATE->GetFirstDisabledPlayer() != PLAYER_INVALID ) m_Scoreboard[cn].SetText( NSMAN->m_Scoreboard[cn] ); } + + // ArrowEffects::Update call moved because having it happen once per + // NoteField (which means twice in two player) seemed wasteful. -Kyz + ArrowEffects::Update(); +} + +void ScreenGameplay::DrawPrimitives() +{ + // ScreenGameplay::DrawPrimitives exists so that the notefield board can be + // above the song background and underneath everything else. This way, a + // theme can put a screen filter in the notefield board and not have it + // obscure custom elements on the screen. Putting the screen filter in the + // notefield board simplifies placement because it ensures that the filter + // is in the same place as the notefield, instead of forcing the filter to + // check conditions and metrics that affect the position of the notefield. + // This also solves the problem of the ComboUnderField metric putting the + // combo underneath the opaque notefield board. + // -Kyz + if(m_pSongBackground) + { + m_pSongBackground->m_disable_draw= false; + m_pSongBackground->Draw(); + m_pSongBackground->m_disable_draw= true; + } + FOREACH_EnabledPlayerNumberInfo(m_vPlayerInfo, pi) + { + pi->m_pPlayer->DrawNoteFieldBoard(); + } + ScreenWithMenuElements::DrawPrimitives(); } void ScreenGameplay::FailFadeRemovePlayer(PlayerInfo* pi) diff --git a/src/ScreenGameplay.h b/src/ScreenGameplay.h index d67dd7a617..96aaf1a0ab 100644 --- a/src/ScreenGameplay.h +++ b/src/ScreenGameplay.h @@ -152,6 +152,8 @@ public: virtual void HandleMessage( const Message &msg ); virtual void Cancel( ScreenMessage smSendWhenDone ); + virtual void DrawPrimitives(); + /** * @brief Retrieve the current ScreenType. * @return the gameplay ScreenType. */