From 1d376f5795db0fdb74158e09f7f73d2d3ff8d1a1 Mon Sep 17 00:00:00 2001 From: Chris Danford Date: Mon, 9 Aug 2004 00:46:42 +0000 Subject: [PATCH] add support for texture coordinate animation in AnimatedTexture --- stepmania/src/Actor.h | 10 ++-- stepmania/src/Model.cpp | 77 ++++++++++++++++++--------- stepmania/src/Model.h | 7 +-- stepmania/src/ModelTypes.cpp | 87 +++++++++++++++++++++++++------ stepmania/src/ModelTypes.h | 44 +++++++--------- stepmania/src/NoteDisplay.cpp | 16 ++---- stepmania/src/RageDisplay.cpp | 23 ++++++++ stepmania/src/RageDisplay.h | 6 +++ stepmania/src/RageDisplay_D3D.cpp | 32 ++++++------ stepmania/src/RageDisplay_D3D.h | 2 + stepmania/src/RageDisplay_OGL.cpp | 2 + stepmania/src/RageDisplay_OGL.h | 1 + stepmania/src/Sprite.cpp | 14 +++++ stepmania/src/Sprite.h | 4 +- 14 files changed, 224 insertions(+), 101 deletions(-) diff --git a/stepmania/src/Actor.h b/stepmania/src/Actor.h index c920e34095..348bcbf0b7 100644 --- a/stepmania/src/Actor.h +++ b/stepmania/src/Actor.h @@ -305,9 +305,13 @@ public: virtual void HandleCommand( const ParsedCommand &command ); // derivable static float GetCommandLength( CString command ); - virtual void SetState( int iNewState ) {}; - virtual void SetSecondsIntoAnimation( float fSeconds ) {}; - virtual int GetNumStates() { return 1; }; + // + // Animation + // + virtual int GetNumStates() const { return 1; } + virtual void SetState( int iNewState ) {} + virtual float GetAnimationLengthSeconds() const { return 0; } + virtual void SetSecondsIntoAnimation( float fSeconds ) {} // // BGAnimation stuff diff --git a/stepmania/src/Model.cpp b/stepmania/src/Model.cpp index dd6ffc14b4..3ad03876f2 100644 --- a/stepmania/src/Model.cpp +++ b/stepmania/src/Model.cpp @@ -11,6 +11,7 @@ #include "ActorUtil.h" #include #include "ModelManager.h" +#include "Foreach.h" const float FRAMES_PER_SECOND = 30; const CString DEFAULT_ANIMATION_NAME = "default"; @@ -466,6 +467,8 @@ void Model::DrawPrimitives() RageMatrix &mat = m_vpBones[pMesh->nBoneIndex].mFinal; DISPLAY->PreMultMatrix( mat ); } + + DISPLAY->TexturePushMatrix(); if( pMesh->nMaterialIndex != -1 ) // has a material { @@ -482,15 +485,25 @@ void Model::DrawPrimitives() DISPLAY->SetMaterial( Emissive, Ambient, Diffuse, mat.Specular, mat.fShininess ); - // render the first pass with texture 1 - DISPLAY->SetTexture( 0, mat.diffuse.ani.GetCurrentTexture() ); - DISPLAY->SetSphereEnironmentMapping( mat.diffuse.bSphereMapped ); - - // render the second pass with texture 2 - if( mat.alpha.ani.GetCurrentTexture() ) + float fScrollX = 0; + float fScrollY = 0; + if( mat.diffuse.m_fTexVelocityX != 0 || mat.diffuse.m_fTexVelocityY != 0 ) { - DISPLAY->SetTexture( 1, mat.alpha.ani.GetCurrentTexture() ); - DISPLAY->SetSphereEnironmentMapping( mat.alpha.bSphereMapped ); + fScrollX = mat.diffuse.m_fTexVelocityX * mat.diffuse.GetSecondsIntoAnimation() / mat.diffuse.GetAnimationLengthSeconds(); + fScrollY = mat.diffuse.m_fTexVelocityY * mat.diffuse.GetSecondsIntoAnimation() / mat.diffuse.GetAnimationLengthSeconds(); + DISPLAY->SetTextureWrapping( true ); + } + DISPLAY->TextureTranslate( fScrollX, fScrollY, 0 ); + + // render the first pass with texture 1 + DISPLAY->SetTexture( 0, mat.diffuse.GetCurrentTexture() ); + DISPLAY->SetSphereEnironmentMapping( mat.diffuse.m_bSphereMapped ); + + // render the second pass with texture 2 + if( mat.alpha.GetCurrentTexture() ) + { + DISPLAY->SetTexture( 1, mat.alpha.GetCurrentTexture() ); + DISPLAY->SetSphereEnironmentMapping( mat.alpha.m_bSphereMapped ); // UGLY: This overrides the Actor's BlendMode DISPLAY->SetTextureModeAdd(); DISPLAY->SetTextureFiltering( true ); @@ -512,6 +525,8 @@ void Model::DrawPrimitives() DISPLAY->DrawCompiledGeometry( TempGeometry, i, m_pGeometry->m_Meshes ); DISPLAY->SetSphereEnironmentMapping( false ); + DISPLAY->TexturePopMatrix(); + if( pMesh->nBoneIndex != -1 ) { DISPLAY->PopMatrix(); @@ -549,7 +564,7 @@ void Model::DrawPrimitives() if( pMesh->nMaterialIndex != -1 ) { msMaterial& mat = m_Materials[ pMesh->nMaterialIndex ]; - DISPLAY->SetTexture( 0, mat.diffuse.ani.GetCurrentTexture() ); + DISPLAY->SetTexture( 0, mat.diffuse.GetCurrentTexture() ); } else { @@ -661,13 +676,6 @@ void Model::PlayAnimation( CString sAniName, float fPlayRate ) AdvanceFrame( 0.0f ); } -float Model::GetCurFrame() { return m_fCurrFrame; }; - -void Model::SetFrame( float fNewFrame ) -{ - m_fCurrFrame = fNewFrame; -} - void Model::AdvanceFrame (float dt) { if( m_pGeometry == NULL || @@ -807,8 +815,8 @@ void Model::Update( float fDelta ) for( int i=0; i<(int)m_Materials.size(); i++ ) { - m_Materials[i].diffuse.ani.Update( fDelta ); - m_Materials[i].alpha.ani.Update( fDelta ); + m_Materials[i].diffuse.Update( fDelta ); + m_Materials[i].alpha.Update( fDelta ); } // @@ -853,21 +861,38 @@ void Model::Update( float fDelta ) } } +int Model::GetNumStates() const +{ + int iMaxStates = 0; + FOREACH_CONST( msMaterial, m_Materials, m ) + iMaxStates = max( iMaxStates, m->diffuse.GetNumStates() ); + return iMaxStates; +} + void Model::SetState( int iNewState ) { - for( int i=0; i<(int)m_Materials.size(); i++ ) + FOREACH( msMaterial, m_Materials, m ) { - m_Materials[i].diffuse.ani.SetState( iNewState ); - m_Materials[i].alpha.ani.SetState( iNewState ); + m->diffuse.SetState( iNewState ); + m->alpha.SetState( iNewState ); } } -int Model::GetNumStates() +float Model::GetAnimationLengthSeconds() const { - int iMaxStates = 0; - for( int i=0; i<(int)m_Materials.size(); i++ ) - iMaxStates = max( iMaxStates, m_Materials[i].diffuse.ani.GetNumStates() ); - return iMaxStates; + float fSeconds = 0; + FOREACH_CONST( msMaterial, m_Materials, m ) + fSeconds = max( fSeconds, m->diffuse.GetAnimationLengthSeconds() ); + return fSeconds; +} + +void Model::SetSecondsIntoAnimation( float fSeconds ) +{ + FOREACH( msMaterial, m_Materials, m ) + { + m->diffuse.SetSecondsIntoAnimation( fSeconds ); + m->alpha.SetSecondsIntoAnimation( fSeconds ); + } } void Model::HandleCommand( const ParsedCommand &command ) diff --git a/stepmania/src/Model.h b/stepmania/src/Model.h index 5bde65d55b..c00b0b2428 100644 --- a/stepmania/src/Model.h +++ b/stepmania/src/Model.h @@ -37,10 +37,11 @@ public: void AdvanceFrame (float dt); void DrawCelShaded(); + virtual int GetNumStates() const; virtual void SetState( int iNewState ); - float GetCurFrame(); - void SetFrame( float fNewFrame ); - virtual int GetNumStates(); + virtual float GetAnimationLengthSeconds() const; + virtual void SetSecondsIntoAnimation( float fSeconds ); + CString GetDefaultAnimation() { return m_sDefaultAnimation; }; void SetDefaultAnimation( CString sAnimation, float fPlayRate = 1 ); bool m_bRevertToDefaultAnimation; diff --git a/stepmania/src/ModelTypes.cpp b/stepmania/src/ModelTypes.cpp index 1b7648ebdf..fd1c4d3aec 100644 --- a/stepmania/src/ModelTypes.cpp +++ b/stepmania/src/ModelTypes.cpp @@ -6,11 +6,16 @@ #include "RageTextureManager.h" #include "RageLog.h" #include "RageDisplay.h" +#include "Foreach.h" AnimatedTexture::AnimatedTexture() { - iCurState = 0; - fSecsIntoFrame = 0; + m_iCurState = 0; + m_fSecsIntoFrame = 0; + m_bSphereMapped = false; + m_fTexVelocityX = 0; + m_fTexVelocityY = 0; + m_BlendMode = BLEND_NORMAL; } AnimatedTexture::~AnimatedTexture() @@ -22,6 +27,12 @@ void AnimatedTexture::Load( CString sTexOrIniPath ) { ASSERT( vFrames.empty() ); // don't load more than once + m_bSphereMapped = sTexOrIniPath.Find("sphere") != -1; + if( sTexOrIniPath.Find("add") != -1 ) + m_BlendMode = BLEND_ADD; + else + m_BlendMode = BLEND_NORMAL; + if( GetExtension(sTexOrIniPath).CompareNoCase("ini")==0 ) { IniFile ini; @@ -30,6 +41,10 @@ void AnimatedTexture::Load( CString sTexOrIniPath ) if( !ini.GetKey("AnimatedTexture") ) RageException::Throw( "The animated texture file '%s' doesn't contain a section called 'AnimatedTexture'.", sTexOrIniPath.c_str() ); + + ini.GetValue( "AnimatedTexture", "TexVelocityX", m_fTexVelocityX ); + ini.GetValue( "AnimatedTexture", "TexVelocityY", m_fTexVelocityY ); + for( int i=0; i<1000; i++ ) { CString sFileKey = ssprintf( "Frame%04d", i ); @@ -64,7 +79,7 @@ void AnimatedTexture::Load( CString sTexOrIniPath ) ID.bMipMaps = true; // use mipmaps in Models AnimatedTextureState state = { TEXTUREMAN->LoadTexture( ID ), - 10 + 1 }; vFrames.push_back( state ); } @@ -75,12 +90,12 @@ void AnimatedTexture::Update( float fDelta ) { if( vFrames.empty() ) return; - ASSERT( iCurState < (int)vFrames.size() ); - fSecsIntoFrame += fDelta; - if( fSecsIntoFrame > vFrames[iCurState].fDelaySecs ) + ASSERT( m_iCurState < (int)vFrames.size() ); + m_fSecsIntoFrame += fDelta; + if( m_fSecsIntoFrame > vFrames[m_iCurState].fDelaySecs ) { - fSecsIntoFrame -= vFrames[iCurState].fDelaySecs; - iCurState = (iCurState+1) % vFrames.size(); + m_fSecsIntoFrame -= vFrames[m_iCurState].fDelaySecs; + m_iCurState = (m_iCurState+1) % vFrames.size(); } } @@ -88,19 +103,60 @@ RageTexture* AnimatedTexture::GetCurrentTexture() { if( vFrames.empty() ) return NULL; - ASSERT( iCurState < (int)vFrames.size() ); - return vFrames[iCurState].pTexture; + ASSERT( m_iCurState < (int)vFrames.size() ); + return vFrames[m_iCurState].pTexture; +} + +int AnimatedTexture::GetNumStates() const +{ + return vFrames.size(); } void AnimatedTexture::SetState( int iState ) { CLAMP( iState, 0, GetNumStates()-1 ); - iCurState = iState; + m_iCurState = iState; } -int AnimatedTexture::GetNumStates() +float AnimatedTexture::GetAnimationLengthSeconds() const { - return vFrames.size(); + float fTotalSeconds = 0; + FOREACH_CONST( AnimatedTextureState, vFrames, ats ) + fTotalSeconds += ats->fDelaySecs; + return fTotalSeconds; +} + +void AnimatedTexture::SetSecondsIntoAnimation( float fSeconds ) +{ + fSeconds = fmodf( fSeconds, GetAnimationLengthSeconds() ); + + m_iCurState = 0; + for( unsigned i=0; i ats.fDelaySecs ) + { + fSeconds -= ats.fDelaySecs; + m_iCurState = i+1; + } + } + m_fSecsIntoFrame = fSeconds; // remainder +} + +float AnimatedTexture::GetSecondsIntoAnimation() const +{ + float fSeconds = 0; + + for( unsigned i=0; i= m_iCurState ) + break; + + fSeconds += ats.fDelaySecs; + } + fSeconds += m_fSecsIntoFrame; + return fSeconds; } void AnimatedTexture::Unload() @@ -108,11 +164,10 @@ void AnimatedTexture::Unload() for(unsigned i = 0; i < vFrames.size(); ++i) TEXTUREMAN->UnloadTexture(vFrames[i].pTexture); vFrames.clear(); - iCurState = 0; - fSecsIntoFrame = 0; + m_iCurState = 0; + m_fSecsIntoFrame = 0; } - msMesh::msMesh() { ZERO( szName ); diff --git a/stepmania/src/ModelTypes.h b/stepmania/src/ModelTypes.h index de937f33bf..2263888896 100644 --- a/stepmania/src/ModelTypes.h +++ b/stepmania/src/ModelTypes.h @@ -71,8 +71,9 @@ typedef struct msMesh class RageTexture; // merge this into Sprite? -struct AnimatedTexture +class AnimatedTexture { +public: AnimatedTexture(); ~AnimatedTexture(); @@ -82,11 +83,21 @@ struct AnimatedTexture RageTexture* GetCurrentTexture(); - void SetState( int iState ); - int GetNumStates(); + int GetNumStates() const; + void SetState( int iNewState ); + float GetAnimationLengthSeconds() const; + void SetSecondsIntoAnimation( float fSeconds ); + float GetSecondsIntoAnimation() const; - int iCurState; - float fSecsIntoFrame; + bool m_bSphereMapped; + float m_fTexVelocityX; + float m_fTexVelocityY; + BlendMode m_BlendMode; + +private: + + int m_iCurState; + float m_fSecsIntoFrame; struct AnimatedTextureState { RageTexture* pTexture; @@ -109,27 +120,8 @@ typedef struct msMaterial char szAlphaTexture[MS_MAX_PATH]; // not used in SM. Use alpha in diffuse texture instead int nName; // not used in SM. What is this for anyway? - struct Texture - { - Texture() - { - bSphereMapped = false; - blendMode = BLEND_NORMAL; - } - - void Load( CString sFile ) - { - ani.Load( sFile ); - bSphereMapped = sFile.Find("sphere") != -1; - if( sFile.Find("add") != -1 ) - blendMode = BLEND_ADD; - else - blendMode = BLEND_NORMAL; - }; - AnimatedTexture ani; - bool bSphereMapped; // true of "sphere" appears in the material name - BlendMode blendMode; - } diffuse, alpha; + AnimatedTexture diffuse; + AnimatedTexture alpha; } msMaterial; /* msPositionKey */ diff --git a/stepmania/src/NoteDisplay.cpp b/stepmania/src/NoteDisplay.cpp index bdea8b796e..2de22b29ef 100644 --- a/stepmania/src/NoteDisplay.cpp +++ b/stepmania/src/NoteDisplay.cpp @@ -251,31 +251,25 @@ void NoteDisplay::Update( float fDeltaTime ) void NoteDisplay::SetActiveFrame( float fNoteBeat, Actor &actorToSet, float fAnimationLengthInBeats, bool bVivid, bool bNoteColor ) { - const int iNumFrames = actorToSet.GetNumStates(); - if( iNumFrames == 0 ) // Model with no textures - return; float fSongBeat = GAMESTATE->m_fSongBeat; - float fPrecentIntoAnimation = fmodf(fSongBeat,fAnimationLengthInBeats) / fAnimationLengthInBeats; + float fPercentIntoAnimation = fmodf(fSongBeat,fAnimationLengthInBeats) / fAnimationLengthInBeats; float fNoteBeatFraction = fmodf( fNoteBeat, 1.0f ); - int iFrameNo = (int)(fPrecentIntoAnimation*iNumFrames); if( bVivid ) { // changed to deal with the minor complaint that the color cycling is // one tick off in general const float fFraction = fNoteBeatFraction - 0.25f/fAnimationLengthInBeats; const float fInterval = 1.f / fAnimationLengthInBeats; - iFrameNo += int( froundf(fFraction,fInterval)*iNumFrames ); + fPercentIntoAnimation += froundf(fFraction,fInterval); } // just in case somehow we're majorly negative with the subtraction - iFrameNo += (iNumFrames * 2); - iFrameNo %= iNumFrames; + wrap( fPercentIntoAnimation, 1.f ); - ASSERT( iFrameNo>=0 && iFrameNoSetTransform( D3DTS_PROJECTION, (D3DMATRIX*)GetProjectionTop() ); \ - g_pd3dDevice->SetTransform( D3DTS_VIEW, (D3DMATRIX*)GetViewTop() ); \ - RageMatrix m; \ - /* Convert to OpenGL-style "pixel-centered" coords */ \ - RageMatrixTranslation( &m, -0.5f, -0.5f, 0 ); \ - RageMatrixMultiply( &m, &m, GetWorldTop() ); \ +void RageDisplay_D3D::SendCurrentMatrices() +{ + g_pd3dDevice->SetTransform( D3DTS_PROJECTION, (D3DMATRIX*)GetProjectionTop() ); + g_pd3dDevice->SetTransform( D3DTS_VIEW, (D3DMATRIX*)GetViewTop() ); + RageMatrix m; + /* Convert to OpenGL-style "pixel-centered" coords */ + RageMatrixTranslation( &m, -0.5f, -0.5f, 0 ); + RageMatrixMultiply( &m, &m, GetWorldTop() ); g_pd3dDevice->SetTransform( D3DTS_WORLD, (D3DMATRIX*)&m ); - + g_pd3dDevice->SetTransform( D3DTS_TEXTURE0, (D3DMATRIX*)GetTextureTop() ); +} class RageCompiledGeometrySWD3D : public RageCompiledGeometry { @@ -831,7 +833,7 @@ void RageDisplay_D3D::DrawQuadsInternal( const RageSpriteVertex v[], int iNumVer } g_pd3dDevice->SetVertexShader( D3DFVF_RageSpriteVertex ); - SEND_CURRENT_MATRICES; + SendCurrentMatrices(); g_pd3dDevice->DrawIndexedPrimitiveUP( D3DPT_TRIANGLELIST, // PrimitiveType 0, // MinIndex @@ -867,7 +869,7 @@ void RageDisplay_D3D::DrawQuadStripInternal( const RageSpriteVertex v[], int iNu } g_pd3dDevice->SetVertexShader( D3DFVF_RageSpriteVertex ); - SEND_CURRENT_MATRICES; + SendCurrentMatrices(); g_pd3dDevice->DrawIndexedPrimitiveUP( D3DPT_TRIANGLELIST, // PrimitiveType 0, // MinIndex @@ -883,7 +885,7 @@ void RageDisplay_D3D::DrawQuadStripInternal( const RageSpriteVertex v[], int iNu void RageDisplay_D3D::DrawFanInternal( const RageSpriteVertex v[], int iNumVerts ) { g_pd3dDevice->SetVertexShader( D3DFVF_RageSpriteVertex ); - SEND_CURRENT_MATRICES; + SendCurrentMatrices(); g_pd3dDevice->DrawPrimitiveUP( D3DPT_TRIANGLEFAN, // PrimitiveType iNumVerts-2, // PrimitiveCount, @@ -895,7 +897,7 @@ void RageDisplay_D3D::DrawFanInternal( const RageSpriteVertex v[], int iNumVerts void RageDisplay_D3D::DrawStripInternal( const RageSpriteVertex v[], int iNumVerts ) { g_pd3dDevice->SetVertexShader( D3DFVF_RageSpriteVertex ); - SEND_CURRENT_MATRICES; + SendCurrentMatrices(); g_pd3dDevice->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, // PrimitiveType iNumVerts-2, // PrimitiveCount, @@ -907,7 +909,7 @@ void RageDisplay_D3D::DrawStripInternal( const RageSpriteVertex v[], int iNumVer void RageDisplay_D3D::DrawTrianglesInternal( const RageSpriteVertex v[], int iNumVerts ) { g_pd3dDevice->SetVertexShader( D3DFVF_RageSpriteVertex ); - SEND_CURRENT_MATRICES; + SendCurrentMatrices(); g_pd3dDevice->DrawPrimitiveUP( D3DPT_TRIANGLELIST, // PrimitiveType iNumVerts/3, // PrimitiveCount, @@ -918,7 +920,7 @@ void RageDisplay_D3D::DrawTrianglesInternal( const RageSpriteVertex v[], int iNu void RageDisplay_D3D::DrawCompiledGeometryInternal( const RageCompiledGeometry *p, int iMeshIndex ) { - SEND_CURRENT_MATRICES; + SendCurrentMatrices(); p->Draw( iMeshIndex ); } @@ -931,7 +933,7 @@ void RageDisplay_D3D::DrawLineStrip( const RageSpriteVertex v[], int iNumVerts, ASSERT( iNumVerts >= 2 ); g_pd3dDevice->SetRenderState( D3DRS_POINTSIZE, *((DWORD*)&LineWidth) ); // funky cast. See D3DRENDERSTATETYPE doc g_pd3dDevice->SetVertexShader( D3DFVF_RageSpriteVertex ); - SEND_CURRENT_MATRICES; + SendCurrentMatrices(); g_pd3dDevice->DrawPrimitiveUP( D3DPT_LINESTRIP, // PrimitiveType iNumVerts-1, // PrimitiveCount, diff --git a/stepmania/src/RageDisplay_D3D.h b/stepmania/src/RageDisplay_D3D.h index 21916b8d2d..1c5ca6d7da 100644 --- a/stepmania/src/RageDisplay_D3D.h +++ b/stepmania/src/RageDisplay_D3D.h @@ -89,6 +89,8 @@ protected: RageSurface* CreateScreenshot(); void SetViewport(int shift_left, int shift_down); RageMatrix GetOrthoMatrix( float l, float r, float b, float t, float zn, float zf ); + + void SendCurrentMatrices(); }; #endif diff --git a/stepmania/src/RageDisplay_OGL.cpp b/stepmania/src/RageDisplay_OGL.cpp index aead938ed9..3e99dc4ac4 100644 --- a/stepmania/src/RageDisplay_OGL.cpp +++ b/stepmania/src/RageDisplay_OGL.cpp @@ -899,6 +899,8 @@ void RageDisplay_OGL::SendCurrentMatrices() RageMatrixMultiply( &modelView, &modelView, GetWorldTop() ); glMatrixMode( GL_MODELVIEW ); glLoadMatrixf( (const float*)&modelView ); + glMatrixMode( GL_TEXTURE ); + glLoadMatrixf( (const float*)GetTextureTop() ); } class RageCompiledGeometrySWOGL : public RageCompiledGeometry diff --git a/stepmania/src/RageDisplay_OGL.h b/stepmania/src/RageDisplay_OGL.h index b9815c1579..8d0967e1f5 100644 --- a/stepmania/src/RageDisplay_OGL.h +++ b/stepmania/src/RageDisplay_OGL.h @@ -86,6 +86,7 @@ protected: RageMatrix GetOrthoMatrix( float l, float r, float b, float t, float zn, float zf ); PixelFormat GetImgPixelFormat( RageSurface* &img, bool &FreeImg, int width, int height ); bool SupportsSurfaceFormat( PixelFormat pixfmt ); + void SendCurrentMatrices(); }; diff --git a/stepmania/src/Sprite.cpp b/stepmania/src/Sprite.cpp index 7b4c90f15b..7534a81619 100644 --- a/stepmania/src/Sprite.cpp +++ b/stepmania/src/Sprite.cpp @@ -11,6 +11,7 @@ #include "RageTexture.h" #include "ActorUtil.h" #include "arch/Dialog/Dialog.h" +#include "Foreach.h" Sprite::Sprite() { @@ -588,6 +589,11 @@ void Sprite::DrawPrimitives() } +int Sprite::GetNumStates() const +{ + return m_States.size(); +} + void Sprite::SetState( int iNewState ) { // This assert will likely trigger if the "missing" theme element graphic @@ -610,6 +616,14 @@ void Sprite::SetState( int iNewState ) m_fSecsIntoState = 0.0; } +float Sprite::GetAnimationLengthSeconds() const +{ + float fTotal = 0; + FOREACH_CONST( State, m_States, s ) + fTotal += s->fDelay; + return fTotal; +} + void Sprite::SetSecondsIntoAnimation( float fSeconds ) { SetState( 0 ); // rewind to the first state diff --git a/stepmania/src/Sprite.h b/stepmania/src/Sprite.h index dd0d64f1aa..37f1e57592 100644 --- a/stepmania/src/Sprite.h +++ b/stepmania/src/Sprite.h @@ -34,10 +34,12 @@ public: RageTexture* GetTexture() { return m_pTexture; }; virtual void EnableAnimation( bool bEnable ); + + virtual int GetNumStates() const; virtual void SetState( int iNewState ); + virtual float GetAnimationLengthSeconds() const; virtual void SetSecondsIntoAnimation( float fSeconds ); - virtual int GetNumStates() { return m_States.size(); }; CString GetTexturePath() const; void SetCustomTextureRect( const RectF &new_texcoord_frect );