diff --git a/stepmania/src/NoteDisplay.cpp b/stepmania/src/NoteDisplay.cpp index 2de22b29ef..266fc57119 100644 --- a/stepmania/src/NoteDisplay.cpp +++ b/stepmania/src/NoteDisplay.cpp @@ -92,6 +92,93 @@ void NoteMetricCache_t::Load(CString skin, const CString &name) m_bFlipHeadAndTailWhenReverse = NOTESKIN->GetMetricB(skin,name,"FlipHeadAndTailWhenReverse"); } + +struct NoteResource +{ + NoteResource( CString sPath ): m_sPath(sPath) + { + m_iRefCount = 0; + m_pActor = NULL; + } + + ~NoteResource() + { + delete m_pActor; + } + + const CString m_sPath; /* should be refcounted along with g_NoteResource[] */ + int m_iRefCount; + Actor *m_pActor; +}; + +static map g_NoteResource; + +static NoteResource *MakeNoteResource( const CString &sPath, bool bSpriteOnly ) +{ + map::iterator it = g_NoteResource.find( sPath ); + if( it == g_NoteResource.end() ) + { + NoteResource *pRes = new NoteResource( sPath ); + if( bSpriteOnly ) + { + Sprite *pSprite = new Sprite; + pSprite->Load( sPath ); + pRes->m_pActor = pSprite; + } + else + pRes->m_pActor = MakeActor( sPath ); + + g_NoteResource[sPath] = pRes; + it = g_NoteResource.find( sPath ); + } + + NoteResource *pRet = it->second; + ++pRet->m_iRefCount; + return pRet; +} + +static NoteResource *FindNoteResource( const Actor *pActor ) +{ + map::iterator it; + for( it = g_NoteResource.begin(); it != g_NoteResource.end(); ++it ) + { + NoteResource *pRes = it->second; + if( pRes->m_pActor == pActor ) + return pRes; + } + + return NULL; +} + +static void DeleteNoteResource( const Actor *pActor ) +{ + if( pActor == NULL ) + return; + + NoteResource *pRes = FindNoteResource( pActor ); + ASSERT( pRes != NULL ); + + ASSERT_M( pRes->m_iRefCount > 0, ssprintf("%i", pRes->m_iRefCount) ); + --pRes->m_iRefCount; + if( pRes->m_iRefCount ) + return; + + g_NoteResource.erase( pRes->m_sPath ); + delete pRes; +} + +Actor *MakeRefcountedActor( const CString &sPath ) +{ + NoteResource *pRes = MakeNoteResource( sPath, false ); + return pRes->m_pActor; +} + +Sprite *MakeRefcountedSprite( const CString &sPath ) +{ + NoteResource *pRes = MakeNoteResource( sPath, true ); + return (Sprite *) pRes->m_pActor; /* XXX ick */ +} + NoteDisplay::NoteDisplay() { for( int i=0; im_bAnimationIsNoteColor[PART_TAP] ) { for( int i=0; iGetPathToFromNoteSkinAndButton(NoteSkin, Button, "tap note "+sNoteType[i]) ); + m_pTapNote[i] = MakeRefcountedActor( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "tap note "+sNoteType[i]) ); } else { - m_pTapNote[0] = MakeActor( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "tap note") ); + m_pTapNote[0] = MakeRefcountedActor( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "tap note") ); } if( cache->m_bAnimationIsNoteColor[PART_ADDITION] ) { for( int i=0; iGetPathToFromNoteSkinAndButton(NoteSkin, Button, "tap addition "+sNoteType[i]) ); + m_pTapAddition[i] = MakeRefcountedActor( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "tap addition "+sNoteType[i]) ); } else { - m_pTapAddition[0] = MakeActor( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "tap addition") ); + m_pTapAddition[0] = MakeRefcountedActor( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "tap addition") ); } - m_pTapMine = MakeActor( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "tap mine") ); + m_pTapMine = MakeRefcountedActor( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "tap mine") ); if( cache->m_bAnimationIsNoteColor[PART_HOLD_HEAD] ) { for( int i=0; iGetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold head active "+sNoteType[i]) ); - m_pHoldHeadInactive[i] = MakeActor( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold head inactive "+sNoteType[i]) ); + m_pHoldHeadActive[i] = MakeRefcountedActor( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold head active "+sNoteType[i]) ); + m_pHoldHeadInactive[i] = MakeRefcountedActor( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold head inactive "+sNoteType[i]) ); } } else { - m_pHoldHeadActive[0] = MakeActor( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold head active") ); - m_pHoldHeadInactive[0] = MakeActor( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold head inactive") ); + m_pHoldHeadActive[0] = MakeRefcountedActor( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold head active") ); + m_pHoldHeadInactive[0] = MakeRefcountedActor( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold head inactive") ); } if( cache->m_bAnimationIsNoteColor[PART_HOLD_TOP_CAP] ) { for( int i=0; iGetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold topcap active "+sNoteType[i]) ); - m_sprHoldTopCapInactive[i].Load( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold topcap inactive "+sNoteType[i]) ); + m_pHoldTopCapActive[i] = MakeRefcountedSprite( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold topcap active "+sNoteType[i]) ); + m_pHoldTopCapInactive[i] = MakeRefcountedSprite( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold topcap inactive "+sNoteType[i]) ); } } else { - m_sprHoldTopCapActive[0].Load( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold topcap active") ); - m_sprHoldTopCapInactive[0].Load( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold topcap inactive") ); + m_pHoldTopCapActive[0] = MakeRefcountedSprite( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold topcap active") ); + m_pHoldTopCapInactive[0] = MakeRefcountedSprite( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold topcap inactive") ); } if( cache->m_bAnimationIsNoteColor[PART_HOLD_BODY] ) { for( int i=0; iGetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold body active "+sNoteType[i]) ); - m_sprHoldBodyInactive[i].Load( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold body inactive "+sNoteType[i]) ); + m_pHoldBodyActive[i] = MakeRefcountedSprite( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold body active "+sNoteType[i]) ); + m_pHoldBodyInactive[i] = MakeRefcountedSprite( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold body inactive "+sNoteType[i]) ); } } else { - m_sprHoldBodyActive[0].Load( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold body active") ); - m_sprHoldBodyInactive[0].Load( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold body inactive") ); + m_pHoldBodyActive[0] = MakeRefcountedSprite( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold body active") ); + m_pHoldBodyInactive[0] = MakeRefcountedSprite( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold body inactive") ); } if( cache->m_bAnimationIsNoteColor[PART_HOLD_BOTTOM_CAP] ) { for( int i=0; iGetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold bottomcap active "+sNoteType[i]) ); - m_sprHoldBottomCapInactive[i].Load( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold bottomcap inactive "+sNoteType[i]) ); + m_pHoldBottomCapActive[i] = MakeRefcountedSprite( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold bottomcap active "+sNoteType[i]) ); + m_pHoldBottomCapInactive[i] = MakeRefcountedSprite( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold bottomcap inactive "+sNoteType[i]) ); } } else { - m_sprHoldBottomCapActive[0].Load( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold bottomcap active") ); - m_sprHoldBottomCapInactive[0].Load( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold bottomcap inactive") ); + m_pHoldBottomCapActive[0] = MakeRefcountedSprite( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold bottomcap active") ); + m_pHoldBottomCapInactive[0] = MakeRefcountedSprite( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold bottomcap inactive") ); } if( cache->m_bAnimationIsNoteColor[PART_HOLD_TAIL] ) { for( int i=0; iGetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold tail active "+sNoteType[i]) ); - m_pHoldTailInactive[i] = MakeActor( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold tail inactive "+sNoteType[i]) ); + m_pHoldTailActive[i] = MakeRefcountedActor( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold tail active "+sNoteType[i]) ); + m_pHoldTailInactive[i] = MakeRefcountedActor( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold tail inactive "+sNoteType[i]) ); } } else { - m_pHoldTailActive[0] = MakeActor( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold tail active") ); - m_pHoldTailInactive[0] = MakeActor( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold tail inactive") ); + m_pHoldTailActive[0] = MakeRefcountedActor( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold tail active") ); + m_pHoldTailInactive[0] = MakeRefcountedActor( NOTESKIN->GetPathToFromNoteSkinAndButton(NoteSkin, Button, "hold tail inactive") ); } } void NoteDisplay::Update( float fDeltaTime ) { - int i; - - for( i=0; iUpdate(fDeltaTime); - for( i=0; iUpdate(fDeltaTime); - m_pTapMine->Update(fDeltaTime); - for( i=0; iUpdate(fDeltaTime); - for( i=0; iUpdate(fDeltaTime); - for( i=0; iUpdate(fDeltaTime); - for( i=0; iUpdate(fDeltaTime); + /* This function is static: it's called once per game loop, not once per + * NoteDisplay. Update each cached item exactly once. */ + map::iterator it; + for( it = g_NoteResource.begin(); it != g_NoteResource.end(); ++it ) + { + NoteResource *pRes = it->second; + pRes->m_pActor->Update( fDeltaTime ); + } } void NoteDisplay::SetActiveFrame( float fNoteBeat, Actor &actorToSet, float fAnimationLengthInBeats, bool bVivid, bool bNoteColor ) @@ -338,7 +436,7 @@ Sprite * NoteDisplay::GetHoldTopCapSprite( float fNoteBeat, bool bIsBeingHeld ) nt = NOTE_TYPE_192ND; nt = min( nt, (NoteType) (NOTE_COLOR_IMAGES-1) ); - Sprite *pSpriteOut = bIsBeingHeld ? &m_sprHoldTopCapActive[nt] : &m_sprHoldTopCapInactive[nt]; + Sprite *pSpriteOut = bIsBeingHeld ? m_pHoldTopCapActive[nt] : m_pHoldTopCapInactive[nt]; SetActiveFrame( fNoteBeat, @@ -360,7 +458,7 @@ Sprite * NoteDisplay::GetHoldBottomCapSprite( float fNoteBeat, bool bIsBeingHeld nt = NOTE_TYPE_192ND; nt = min( nt, (NoteType) (NOTE_COLOR_IMAGES-1) ); - Sprite *pSpriteOut = bIsBeingHeld ? &m_sprHoldBottomCapActive[nt] : &m_sprHoldBottomCapInactive[nt]; + Sprite *pSpriteOut = bIsBeingHeld ? m_pHoldBottomCapActive[nt] : m_pHoldBottomCapInactive[nt]; SetActiveFrame( fNoteBeat, @@ -405,7 +503,7 @@ Sprite *NoteDisplay::GetHoldBodySprite( float fNoteBeat, bool bIsBeingHeld ) nt = NOTE_TYPE_192ND; nt = min( nt, (NoteType) (NOTE_COLOR_IMAGES-1) ); - Sprite *pSpriteOut = bIsBeingHeld ? &m_sprHoldBodyActive[nt] : &m_sprHoldBodyInactive[nt]; + Sprite *pSpriteOut = bIsBeingHeld ? m_pHoldBodyActive[nt] : m_pHoldBodyInactive[nt]; SetActiveFrame( fNoteBeat, diff --git a/stepmania/src/NoteDisplay.h b/stepmania/src/NoteDisplay.h index 83d3b39ee8..22a840e22a 100644 --- a/stepmania/src/NoteDisplay.h +++ b/stepmania/src/NoteDisplay.h @@ -19,7 +19,7 @@ public: void Load( int iColNum, PlayerNumber pn, CString NoteSkin, float fYReverseOffsetPixels ); - void Update( float fDeltaTime ); + static void Update( float fDeltaTime ); void DrawActor( Actor* pActor, int iCol, float fBeat, float fPercentFadeToFail, float fLife, float fReverseOffsetPixels, bool bUseLighting ); void DrawTap( int iCol, float fBeat, bool bOnSameRowAsHoldStart, bool bIsAddition, bool bIsMine, float fPercentFadeToFail, float fLife, float fReverseOffsetPixels ); @@ -53,12 +53,12 @@ protected: Actor* m_pTapMine; Actor* m_pHoldHeadActive[NOTE_COLOR_IMAGES]; Actor* m_pHoldHeadInactive[NOTE_COLOR_IMAGES]; - Sprite m_sprHoldTopCapActive[NOTE_COLOR_IMAGES]; - Sprite m_sprHoldTopCapInactive[NOTE_COLOR_IMAGES]; - Sprite m_sprHoldBodyActive[NOTE_COLOR_IMAGES]; - Sprite m_sprHoldBodyInactive[NOTE_COLOR_IMAGES]; - Sprite m_sprHoldBottomCapActive[NOTE_COLOR_IMAGES]; - Sprite m_sprHoldBottomCapInactive[NOTE_COLOR_IMAGES]; + Sprite* m_pHoldTopCapActive[NOTE_COLOR_IMAGES]; + Sprite* m_pHoldTopCapInactive[NOTE_COLOR_IMAGES]; + Sprite* m_pHoldBodyActive[NOTE_COLOR_IMAGES]; + Sprite* m_pHoldBodyInactive[NOTE_COLOR_IMAGES]; + Sprite* m_pHoldBottomCapActive[NOTE_COLOR_IMAGES]; + Sprite* m_pHoldBottomCapInactive[NOTE_COLOR_IMAGES]; Actor* m_pHoldTailActive[NOTE_COLOR_IMAGES]; Actor* m_pHoldTailInactive[NOTE_COLOR_IMAGES]; float m_fYReverseOffsetPixels; diff --git a/stepmania/src/NoteField.cpp b/stepmania/src/NoteField.cpp index dcccc0d2dd..6854c13e96 100644 --- a/stepmania/src/NoteField.cpp +++ b/stepmania/src/NoteField.cpp @@ -161,20 +161,15 @@ void NoteField::Update( float fDeltaTime ) // - // update all NoteDisplayCols. NoteDisplay's may contain BGAnimations - // that need to be updated. + // update all NoteDisplays // - for( NDMap::iterator iter = m_BeatToNoteDisplays.begin(); - iter != m_BeatToNoteDisplays.end(); - iter++ ) - { - NoteDisplayCols *nd = iter->second; - for( int c=0; cdisplay[c].Update(fDeltaTime); -// nd->m_ReceptorArrowRow.Update(fDeltaTime); -// nd->m_GhostArrowRow.Update(fDeltaTime); - } + /* + * Update all NoteDisplays. Hack: We need to call this once per frame, not + * once per player. + */ + if( m_PlayerNumber == GAMESTATE->m_MasterPlayerNumber ) + NoteDisplay::Update( fDeltaTime ); } float NoteField::GetWidth()