|
@@ -0,0 +1,586 @@
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+// Copyright (c) 2013 GarageGames, LLC
|
|
|
+//
|
|
|
+// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
+// of this software and associated documentation files (the "Software"), to
|
|
|
+// deal in the Software without restriction, including without limitation the
|
|
|
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
|
+// sell copies of the Software, and to permit persons to whom the Software is
|
|
|
+// furnished to do so, subject to the following conditions:
|
|
|
+//
|
|
|
+// The above copyright notice and this permission notice shall be included in
|
|
|
+// all copies or substantial portions of the Software.
|
|
|
+//
|
|
|
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
|
+// IN THE SOFTWARE.
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+
|
|
|
+#include "2d/core/imageFrameProviderCore.h"
|
|
|
+
|
|
|
+#ifndef _SCENE_OBJECT_H_
|
|
|
+#include "2d/sceneobject/SceneObject.h"
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifndef _DGL_H_
|
|
|
+#include "graphics/dgl.h"
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifndef _CONSOLETYPES_H_
|
|
|
+#include "console/consoleTypes.h"
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifndef _STRINGBUFFER_H_
|
|
|
+#include "string/stringBuffer.h"
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifndef _RENDER_PROXY_H_
|
|
|
+#include "2d/core/renderProxy.h"
|
|
|
+#endif
|
|
|
+
|
|
|
+// Debug Profiling.
|
|
|
+#include "debug/profiler.h"
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+
|
|
|
+ImageFrameProviderCore::ImageFrameProviderCore() : mpImageAsset(NULL), mpAnimationAsset(NULL)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+
|
|
|
+ImageFrameProviderCore::~ImageFrameProviderCore()
|
|
|
+{
|
|
|
+ // Reset the state.
|
|
|
+ resetState();
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+
|
|
|
+void ImageFrameProviderCore::allocateAssets( AssetPtr<ImageAsset>* pImageAssetPtr, AssetPtr<AnimationAsset>* pAnimationAssetPtr )
|
|
|
+{
|
|
|
+ // Sanity!
|
|
|
+ AssertFatal( mpImageAsset == NULL && mpAnimationAsset == NULL, "ImageFrameProviderCore: Assets already allocated." );
|
|
|
+ AssertFatal( pImageAssetPtr != NULL, "ImageFrameProviderCore: Image-Asset pointer cannot be NULL." );
|
|
|
+ AssertFatal( pAnimationAssetPtr != NULL, "ImageFrameProviderCore: Animation-Asset pointer cannot be NULL." );
|
|
|
+
|
|
|
+ // Reset the state.
|
|
|
+ resetState();
|
|
|
+
|
|
|
+ // Set asset pointers.
|
|
|
+ mpImageAsset = pImageAssetPtr;
|
|
|
+ mpAnimationAsset = pAnimationAssetPtr;
|
|
|
+
|
|
|
+ // Set static/animation frame provider.
|
|
|
+ mStaticProvider = mpImageAsset->notNull();
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+
|
|
|
+void ImageFrameProviderCore::resetState( void )
|
|
|
+{
|
|
|
+ mSelfTick = false;
|
|
|
+
|
|
|
+ mCurrentFrameIndex = 0;
|
|
|
+ mLastFrameIndex = 0;
|
|
|
+ mMaxFrameIndex = 0;
|
|
|
+ mCurrentTime = 0.0f;
|
|
|
+ mPausedTime = 0.0f;
|
|
|
+ mAnimationTimeScale = 1.0f;
|
|
|
+ mTotalIntegrationTime = 0.0f;
|
|
|
+ mFrameIntegrationTime = 0.0f;
|
|
|
+ mAnimationPaused = false;
|
|
|
+ mAnimationFinished = true;
|
|
|
+
|
|
|
+ clearAssets();
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+
|
|
|
+void ImageFrameProviderCore::copyTo( ImageFrameProviderCore* pImageFrameProviderCore ) const
|
|
|
+{
|
|
|
+ // Sanity!
|
|
|
+ AssertFatal(pImageFrameProviderCore != NULL, "ImageFrameProviderCore::copyTo - Copy object cannot be NULL.");
|
|
|
+
|
|
|
+ // Set self ticking.
|
|
|
+ pImageFrameProviderCore->mSelfTick = mSelfTick;
|
|
|
+
|
|
|
+ // Static provider?
|
|
|
+ if ( isStaticFrameProvider() )
|
|
|
+ {
|
|
|
+ // Yes, so use the image/frame if we have an asset.
|
|
|
+ if ( mpImageAsset->notNull() )
|
|
|
+ pImageFrameProviderCore->setImage( getImage(), getImageFrame() );
|
|
|
+ }
|
|
|
+ else if ( mpAnimationAsset->notNull() )
|
|
|
+ {
|
|
|
+ // No, so use current animation if we have an asset.
|
|
|
+ if ( mpAnimationAsset->notNull() )
|
|
|
+ pImageFrameProviderCore->setAnimation(getAnimation() );
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//------------------------------------------------------------------------------
|
|
|
+
|
|
|
+bool ImageFrameProviderCore::update( const F32 elapsedTime )
|
|
|
+{
|
|
|
+ // Static provider?
|
|
|
+ if ( isStaticFrameProvider() )
|
|
|
+ {
|
|
|
+ // Yes, so turn-off tick processing.
|
|
|
+ setProcessTicks( false );
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Finish if the animation has finished.
|
|
|
+ if ( isAnimationFinished() )
|
|
|
+ return false;
|
|
|
+
|
|
|
+ // Finish if animation is paused.
|
|
|
+ if ( isAnimationPaused() )
|
|
|
+ return true;
|
|
|
+
|
|
|
+ // Update the animation.
|
|
|
+ updateAnimation( Tickable::smTickSec );
|
|
|
+
|
|
|
+ // Finish if the animation has NOT finished.
|
|
|
+ if ( !isAnimationFinished() )
|
|
|
+ return false;
|
|
|
+
|
|
|
+ // Turn-off tick processing.
|
|
|
+ setProcessTicks( false );
|
|
|
+
|
|
|
+ // Perform callback.
|
|
|
+ onAnimationEnd();
|
|
|
+
|
|
|
+ // Flag animation as just finished.
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+//------------------------------------------------------------------------------
|
|
|
+
|
|
|
+void ImageFrameProviderCore::processTick( void )
|
|
|
+{
|
|
|
+ // Update using tick period.
|
|
|
+ update( Tickable::smTickSec );
|
|
|
+}
|
|
|
+
|
|
|
+//------------------------------------------------------------------------------
|
|
|
+
|
|
|
+bool ImageFrameProviderCore::validRender( void ) const
|
|
|
+{
|
|
|
+ // Are we in static mode?
|
|
|
+ if ( isStaticFrameProvider() )
|
|
|
+ {
|
|
|
+ // Yes, so we must have an image asset and the frame must be in bounds.
|
|
|
+ return mpImageAsset->notNull() && ( getImageFrame() < (*mpImageAsset)->getFrameCount() );
|
|
|
+ }
|
|
|
+
|
|
|
+ // No, so if the animation must be valid.
|
|
|
+ return isAnimationValid();
|
|
|
+}
|
|
|
+
|
|
|
+//------------------------------------------------------------------------------
|
|
|
+
|
|
|
+void ImageFrameProviderCore::render(
|
|
|
+ const bool flipX,
|
|
|
+ const bool flipY,
|
|
|
+ const Vector2& vertexPos0,
|
|
|
+ const Vector2& vertexPos1,
|
|
|
+ const Vector2& vertexPos2,
|
|
|
+ const Vector2& vertexPos3,
|
|
|
+ BatchRender* pBatchRenderer ) const
|
|
|
+{
|
|
|
+ // Finish if we can't render.
|
|
|
+ if ( !validRender() )
|
|
|
+ return;
|
|
|
+
|
|
|
+ // Fetch texel area.
|
|
|
+ ImageAsset::FrameArea::TexelArea texelArea = getProviderImageFrameArea().mTexelArea;
|
|
|
+
|
|
|
+ // Flip texture coordinates appropriately.
|
|
|
+ texelArea.setFlip( flipX, flipY );
|
|
|
+
|
|
|
+ // Fetch lower/upper texture coordinates.
|
|
|
+ const Vector2& texLower = texelArea.mTexelLower;
|
|
|
+ const Vector2& texUpper = texelArea.mTexelUpper;
|
|
|
+
|
|
|
+ // Submit batched quad.
|
|
|
+ pBatchRenderer->SubmitQuad(
|
|
|
+ vertexPos0,
|
|
|
+ vertexPos1,
|
|
|
+ vertexPos2,
|
|
|
+ vertexPos3,
|
|
|
+ Vector2( texLower.x, texUpper.y ),
|
|
|
+ Vector2( texUpper.x, texUpper.y ),
|
|
|
+ Vector2( texUpper.x, texLower.y ),
|
|
|
+ Vector2( texLower.x, texLower.y ),
|
|
|
+ getProviderTexture() );
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+
|
|
|
+void ImageFrameProviderCore::renderGui( GuiControl& owner, Point2I offset, const RectI &updateRect ) const
|
|
|
+{
|
|
|
+ // Validate frame provider.
|
|
|
+ if ( ( isStaticFrameProvider() && (mpImageAsset->isNull() || mImageFrame >= (*mpImageAsset)->getFrameCount()) ) ||
|
|
|
+ ( !isStaticFrameProvider() && (mpAnimationAsset->isNull() ) ) )
|
|
|
+ {
|
|
|
+ // Invalid so fetch the 'cannot render' proxy.
|
|
|
+ RenderProxy* pNoImageRenderProxy = Sim::findObject<RenderProxy>( CANNOT_RENDER_PROXY_NAME );
|
|
|
+
|
|
|
+ // Check that the render proxy can render.
|
|
|
+ if ( pNoImageRenderProxy != NULL && pNoImageRenderProxy->validRender() )
|
|
|
+ {
|
|
|
+ // Render using render-proxy.
|
|
|
+ pNoImageRenderProxy->renderGui( owner, offset, updateRect );
|
|
|
+ }
|
|
|
+
|
|
|
+ // Update control.
|
|
|
+ owner.setUpdate();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // Valid, so calculate source region.
|
|
|
+ const ImageAsset::FrameArea& frameArea = getProviderImageFrameArea();
|
|
|
+ RectI sourceRegion( frameArea.mPixelArea.mPixelOffset, Point2I(frameArea.mPixelArea.mPixelWidth, frameArea.mPixelArea.mPixelHeight) );
|
|
|
+
|
|
|
+ // Calculate destination region.
|
|
|
+ RectI destinationRegion(offset, owner.mBounds.extent);
|
|
|
+
|
|
|
+ // Render image.
|
|
|
+ dglSetBitmapModulation( owner.mProfile->mFillColor );
|
|
|
+ dglDrawBitmapStretchSR( getProviderTexture(), destinationRegion, sourceRegion );
|
|
|
+ dglClearBitmapModulation();
|
|
|
+ }
|
|
|
+
|
|
|
+ // Render child controls.
|
|
|
+ owner.renderChildControls(offset, updateRect);
|
|
|
+}
|
|
|
+
|
|
|
+//------------------------------------------------------------------------------
|
|
|
+
|
|
|
+bool ImageFrameProviderCore::setImage( const char* pImageAssetId, const U32 frame )
|
|
|
+{
|
|
|
+ // Finish if invalid image asset.
|
|
|
+ if ( pImageAssetId == NULL )
|
|
|
+ return false;
|
|
|
+
|
|
|
+ // Set asset.
|
|
|
+ mpImageAsset->setAssetId( pImageAssetId );
|
|
|
+
|
|
|
+ // Set the image frame if the image asset was set.
|
|
|
+ if ( mpImageAsset->notNull() )
|
|
|
+ setImageFrame( frame );
|
|
|
+
|
|
|
+ // Set Frame.
|
|
|
+ mImageFrame = frame;
|
|
|
+
|
|
|
+ // Set as static provider.
|
|
|
+ mStaticProvider = true;
|
|
|
+
|
|
|
+ // Turn-off tick processing.
|
|
|
+ setProcessTicks( false );
|
|
|
+
|
|
|
+ // Return Okay.
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+//------------------------------------------------------------------------------
|
|
|
+
|
|
|
+bool ImageFrameProviderCore::setImageFrame( const U32 frame )
|
|
|
+{
|
|
|
+ // Check Existing Image.
|
|
|
+ if ( mpImageAsset->isNull() )
|
|
|
+ {
|
|
|
+ // Warn.
|
|
|
+ Con::warnf("ImageFrameProviderCore::setImageFrame() - Cannot set Frame without existing asset Id.");
|
|
|
+
|
|
|
+ // Return Here.
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check Frame Validity.
|
|
|
+ if ( frame >= (*mpImageAsset)->getFrameCount() )
|
|
|
+ {
|
|
|
+ // Warn.
|
|
|
+ Con::warnf( "ImageFrameProviderCore::setImageFrame() - Invalid Frame #%d for asset Id '%s'.", frame, mpImageAsset->getAssetId() );
|
|
|
+ // Return Here.
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Set Frame.
|
|
|
+ mImageFrame = frame;
|
|
|
+
|
|
|
+ // Return Okay.
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+
|
|
|
+const U32 ImageFrameProviderCore::getCurrentAnimationFrame( void ) const
|
|
|
+{
|
|
|
+ // Sanity!
|
|
|
+ AssertFatal( mpAnimationAsset->notNull(), "Animation controller requested current image frame but no animation asset assigned." );
|
|
|
+
|
|
|
+ // Fetch validated frames.
|
|
|
+ const Vector<S32>& validatedFrames = (*mpAnimationAsset)->getValidatedAnimationFrames();
|
|
|
+
|
|
|
+ // Sanity!
|
|
|
+ AssertFatal( mCurrentFrameIndex < validatedFrames.size(), "Animation controller requested the current frame but it is out of bounds of the validated frames." );
|
|
|
+
|
|
|
+ return validatedFrames[mCurrentFrameIndex];
|
|
|
+};
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+
|
|
|
+bool ImageFrameProviderCore::isAnimationValid( void ) const
|
|
|
+{
|
|
|
+ // Not valid if no animation asset.
|
|
|
+ if ( mpAnimationAsset->isNull() )
|
|
|
+ return false;
|
|
|
+
|
|
|
+ // Fetch validated frames.
|
|
|
+ const Vector<S32>& validatedFrames = (*mpAnimationAsset)->getValidatedAnimationFrames();
|
|
|
+
|
|
|
+ // Not valid if current frame index is out of bounds of the validated frames.
|
|
|
+ if ( mCurrentFrameIndex >= validatedFrames.size() )
|
|
|
+ return false;
|
|
|
+
|
|
|
+ // Fetch image asset.
|
|
|
+ const AssetPtr<ImageAsset>& imageAsset = (*mpAnimationAsset)->getImage();
|
|
|
+
|
|
|
+ // Not valid if no image asset.
|
|
|
+ if ( imageAsset.isNull() )
|
|
|
+ return false;
|
|
|
+
|
|
|
+ // Fetch current frame.
|
|
|
+ const U32 currentFrame = getCurrentAnimationFrame();
|
|
|
+
|
|
|
+ // Not valid if current frame is out of bounds of the image asset.
|
|
|
+ if ( currentFrame >= imageAsset->getFrameCount() )
|
|
|
+ return false;
|
|
|
+
|
|
|
+ // Valid.
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+
|
|
|
+bool ImageFrameProviderCore::setAnimation( const char* pAnimationAssetId )
|
|
|
+{
|
|
|
+ // Set as dynamic provider.
|
|
|
+ mStaticProvider = false;
|
|
|
+
|
|
|
+ // Ensure animation is un-paused.
|
|
|
+ mAnimationPaused = false;
|
|
|
+
|
|
|
+ // Reset static asset.
|
|
|
+ mpImageAsset->clear();
|
|
|
+
|
|
|
+ // Fetch animation asset.
|
|
|
+ mpAnimationAsset->setAssetId( pAnimationAssetId );
|
|
|
+
|
|
|
+ // Finish if we didn't get an animation.
|
|
|
+ if ( mpAnimationAsset->isNull() )
|
|
|
+ return false;
|
|
|
+
|
|
|
+ // Play Animation.
|
|
|
+ if ( !playAnimation( *mpAnimationAsset ) )
|
|
|
+ return false;
|
|
|
+
|
|
|
+ // Turn-on tick processing.
|
|
|
+ setProcessTicks( true );
|
|
|
+
|
|
|
+ // Return Okay.
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+
|
|
|
+bool ImageFrameProviderCore::playAnimation( const AssetPtr<AnimationAsset>& animationAsset )
|
|
|
+{
|
|
|
+ // Debug Profiling.
|
|
|
+ PROFILE_SCOPE(AnimationController_PlayAnimation);
|
|
|
+
|
|
|
+ // Stop animation.
|
|
|
+ stopAnimation();
|
|
|
+
|
|
|
+ // Finish if no animation asset.
|
|
|
+ if ( animationAsset.isNull() )
|
|
|
+ return true;
|
|
|
+
|
|
|
+ // Set as dynamic provider.
|
|
|
+ mStaticProvider = false;
|
|
|
+
|
|
|
+ // Fetch validated frames.
|
|
|
+ const Vector<S32>& validatedFrames = animationAsset->getValidatedAnimationFrames();
|
|
|
+
|
|
|
+ // Check we've got some frames.
|
|
|
+ if ( validatedFrames.size() == 0 )
|
|
|
+ {
|
|
|
+ Con::warnf( "ImageFrameProviderCore::playAnimation() - Cannot play AnimationAsset '%s' - Animation has no validated frames!", mpAnimationAsset->getAssetId() );
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Set animation asset.
|
|
|
+ mpAnimationAsset->setAssetId( animationAsset.getAssetId() );
|
|
|
+
|
|
|
+ // Set Maximum Frame Index.
|
|
|
+ mMaxFrameIndex = validatedFrames.size()-1;
|
|
|
+
|
|
|
+ // Calculate Total Integration Time.
|
|
|
+ mTotalIntegrationTime = (*mpAnimationAsset)->getAnimationTime();
|
|
|
+
|
|
|
+ // Calculate Frame Integration Time.
|
|
|
+ mFrameIntegrationTime = mTotalIntegrationTime / validatedFrames.size();
|
|
|
+
|
|
|
+ // No, so random Start?
|
|
|
+ if ( (*mpAnimationAsset)->getRandomStart() )
|
|
|
+ {
|
|
|
+ // Yes, so calculate start time.
|
|
|
+ mCurrentTime = CoreMath::mGetRandomF(0.0f, mTotalIntegrationTime*0.999f);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // No, so set first frame.
|
|
|
+ mCurrentTime = 0.0f;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Reset animation finished flag.
|
|
|
+ mAnimationFinished = false;
|
|
|
+
|
|
|
+ // Do an initial animation update.
|
|
|
+ updateAnimation(0.0f);
|
|
|
+
|
|
|
+ // Return Okay.
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+
|
|
|
+bool ImageFrameProviderCore::updateAnimation( const F32 elapsedTime )
|
|
|
+{
|
|
|
+ // Debug Profiling.
|
|
|
+ PROFILE_SCOPE(AnimationController_UpdateAnimation);
|
|
|
+
|
|
|
+ // Finish if animation asset is not valid.
|
|
|
+ if ( mpAnimationAsset->isNull() || (*mpAnimationAsset)->getImage().isNull() )
|
|
|
+ return false;
|
|
|
+
|
|
|
+ // Finish if animation has finished.
|
|
|
+ if ( mAnimationFinished )
|
|
|
+ return false;
|
|
|
+
|
|
|
+ // Fetch validated frames.
|
|
|
+ const Vector<S32>& validatedFrames = (*mpAnimationAsset)->getValidatedAnimationFrames();
|
|
|
+
|
|
|
+ // Finish if there are no validated frames.
|
|
|
+ if ( validatedFrames.size() == 0 )
|
|
|
+ return false;
|
|
|
+
|
|
|
+ // Calculate scaled time.
|
|
|
+ const F32 scaledTime = elapsedTime * mAnimationTimeScale;
|
|
|
+
|
|
|
+ // Update Current Time.
|
|
|
+ mCurrentTime += scaledTime;
|
|
|
+
|
|
|
+ // Check if the animation has finished.
|
|
|
+ if ( !(*mpAnimationAsset)->getAnimationCycle() && mGreaterThanOrEqual(mCurrentTime, mTotalIntegrationTime) )
|
|
|
+ {
|
|
|
+ // Animation has finished.
|
|
|
+ mAnimationFinished = true;
|
|
|
+
|
|
|
+ // Fix Animation at end of frames.
|
|
|
+ mCurrentTime = mTotalIntegrationTime - (mFrameIntegrationTime * 0.5f);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Update Current Mod Time.
|
|
|
+ mCurrentModTime = mFmod( mCurrentTime, mTotalIntegrationTime );
|
|
|
+
|
|
|
+ // Calculate Current Frame.
|
|
|
+ mCurrentFrameIndex = (S32)(mCurrentModTime / mFrameIntegrationTime);
|
|
|
+
|
|
|
+ // Fetch frame.
|
|
|
+ S32 frame = validatedFrames[mCurrentFrameIndex];
|
|
|
+
|
|
|
+ // Fetch image frame count.
|
|
|
+ const S32 imageFrameCount = (*mpAnimationAsset)->getImage()->getFrameCount();
|
|
|
+
|
|
|
+ // Clamp frames.
|
|
|
+ if ( frame < 0 )
|
|
|
+ frame = 0;
|
|
|
+ else if (frame >= imageFrameCount )
|
|
|
+ frame = imageFrameCount-1;
|
|
|
+
|
|
|
+ // Calculate if frame has changed.
|
|
|
+ bool frameChanged = (mCurrentFrameIndex != mLastFrameIndex);
|
|
|
+
|
|
|
+ // Reset Last Frame.
|
|
|
+ mLastFrameIndex = mCurrentFrameIndex;
|
|
|
+
|
|
|
+ // Return Frame-Changed Flag.
|
|
|
+ return frameChanged;
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+
|
|
|
+void ImageFrameProviderCore::setAnimationFrame( const U32 frameIndex )
|
|
|
+{
|
|
|
+ // Do we have a valid animation asset?
|
|
|
+ if ( mpAnimationAsset->isNull() )
|
|
|
+ {
|
|
|
+ // No, so warn.
|
|
|
+ Con::warnf("ImageFrameProviderCore::setAnimationFrame() - Cannot set frame; animation is finished or is invalid!");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Validate Frame Index?
|
|
|
+ if ( (S32)frameIndex < 0 || frameIndex > mMaxFrameIndex )
|
|
|
+ {
|
|
|
+ // No, so warn.
|
|
|
+ Con::warnf("ImageFrameProviderCore::setAnimationFrame() - Animation Frame-Index Invalid (frame#%d of %d in %s)", frameIndex, mMaxFrameIndex, mpAnimationAsset->getAssetId() );
|
|
|
+ // Finish here.
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Calculate current time.
|
|
|
+ mCurrentTime = frameIndex*mFrameIntegrationTime;
|
|
|
+
|
|
|
+ // Do an immediate animation update.
|
|
|
+ updateAnimation(0.0f);
|
|
|
+}
|
|
|
+
|
|
|
+//------------------------------------------------------------------------------
|
|
|
+
|
|
|
+void ImageFrameProviderCore::clearAssets( void )
|
|
|
+{
|
|
|
+ // Clear assets.
|
|
|
+ if ( mpAnimationAsset != NULL )
|
|
|
+ mpAnimationAsset->clear();
|
|
|
+
|
|
|
+ if ( mpImageAsset != NULL )
|
|
|
+ mpImageAsset->clear();
|
|
|
+
|
|
|
+ // Reset remaining state.
|
|
|
+ mImageFrame = 0;
|
|
|
+ mStaticProvider = true;
|
|
|
+ setProcessTicks( false );
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+
|
|
|
+void ImageFrameProviderCore::onAssetRefreshed( AssetPtrBase* pAssetPtrBase )
|
|
|
+{
|
|
|
+ // Don't perform any action if the animation is not already playing.
|
|
|
+ if ( mAnimationFinished )
|
|
|
+ return;
|
|
|
+
|
|
|
+ // Attempt to restart the animation.
|
|
|
+ playAnimation( *mpAnimationAsset );
|
|
|
+}
|