[Tizen](Vector) Ensure that all animation data is applied at once
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / animated-vector-image / vector-animation-task.cpp
1 /*
2  * Copyright (c) 2019 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <dali/public-api/object/property-array.h>
24 #include <dali/public-api/math/math-utils.h>
25
26 // INTERNAL INCLUDES
27 #include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
28 #include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.h>
29
30 namespace Dali
31 {
32
33 namespace Toolkit
34 {
35
36 namespace Internal
37 {
38
39 namespace
40 {
41
42 constexpr auto LOOP_FOREVER = -1;
43 constexpr auto NANOSECONDS_PER_SECOND( 1e+9 );
44
45 #if defined(DEBUG_ENABLED)
46 Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_VECTOR_ANIMATION" );
47 #endif
48
49 template< typename T >
50 inline void ResetValue( bool& updated, T& value, T newValue, ConditionalWait& conditionalWait )
51 {
52   ConditionalWait::ScopedLock lock( conditionalWait );
53   if( !updated )
54   {
55     value = newValue;
56     updated = true;
57   }
58 }
59
60 } // unnamed namespace
61
62 VectorAnimationTask::VectorAnimationTask( VisualFactoryCache& factoryCache, const std::string& url )
63 : mUrl( url ),
64   mVectorRenderer(),
65   mVectorAnimationThread( factoryCache.GetVectorAnimationThread() ),
66   mConditionalWait(),
67   mAnimationFinishedTrigger(),
68   mPlayState( PlayState::STOPPED ),
69   mStopBehavior( DevelImageVisual::StopBehavior::CURRENT_FRAME ),
70   mLoopingMode( DevelImageVisual::LoopingMode::RESTART ),
71   mNextFrameStartTime(),
72   mFrameDurationNanoSeconds( 0 ),
73   mFrameRate( 60.0f ),
74   mCurrentFrame( 0 ),
75   mTotalFrame( 0 ),
76   mStartFrame( 0 ),
77   mEndFrame( 0 ),
78   mWidth( 0 ),
79   mHeight( 0 ),
80   mLoopCount( LOOP_FOREVER ),
81   mCurrentLoop( 0 ),
82   mResourceReady( false ),
83   mCurrentFrameUpdated( false ),
84   mCurrentLoopUpdated( false ),
85   mForward( true ),
86   mUpdateFrameNumber( false ),
87   mNeedAnimationFinishedTrigger( true )
88 {
89   Initialize();
90 }
91
92 VectorAnimationTask::~VectorAnimationTask()
93 {
94   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::~VectorAnimationTask: destructor [%p]\n", this );
95 }
96
97 void VectorAnimationTask::Finalize()
98 {
99   ConditionalWait::ScopedLock lock( mConditionalWait );
100
101   // Release some objects in the main thread
102   if( mAnimationFinishedTrigger )
103   {
104     mAnimationFinishedTrigger.reset();
105   }
106
107   mVectorRenderer.Finalize();
108 }
109
110 void VectorAnimationTask::SetRenderer( Renderer renderer )
111 {
112   ConditionalWait::ScopedLock lock( mConditionalWait );
113
114   mVectorRenderer.SetRenderer( renderer );
115
116   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetRenderer [%p]\n", this );
117 }
118
119 void VectorAnimationTask::SetAnimationData( const AnimationData& data )
120 {
121   ConditionalWait::ScopedLock lock( mConditionalWait );
122
123   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetAnimationData [%p]\n", this );
124
125   if( data.resendFlag & VectorAnimationTask::RESEND_LOOP_COUNT )
126   {
127     SetLoopCount( data.loopCount );
128   }
129
130   if( data.resendFlag & VectorAnimationTask::RESEND_PLAY_RANGE )
131   {
132     SetPlayRange( data.playRange );
133   }
134
135   if( data.resendFlag & VectorAnimationTask::RESEND_STOP_BEHAVIOR )
136   {
137     SetStopBehavior( data.stopBehavior );
138   }
139
140   if( data.resendFlag & VectorAnimationTask::RESEND_LOOPING_MODE )
141   {
142     SetLoopingMode( data.loopingMode );
143   }
144
145   if( data.resendFlag & VectorAnimationTask::RESEND_CURRENT_FRAME )
146   {
147     SetCurrentFrameNumber( data.currentFrame );
148   }
149
150   if( data.resendFlag & VectorAnimationTask::RESEND_SIZE )
151   {
152     SetSize( data.width, data.height );
153   }
154
155   if( data.resendFlag & VectorAnimationTask::RESEND_PLAY_STATE )
156   {
157     if( data.playState == DevelImageVisual::PlayState::PLAYING )
158     {
159       PlayAnimation();
160     }
161     else if( data.playState == DevelImageVisual::PlayState::PAUSED )
162     {
163       PauseAnimation();
164       RenderFrame();
165     }
166     else if( data.playState == DevelImageVisual::PlayState::STOPPED )
167     {
168       StopAnimation();
169     }
170   }
171   else
172   {
173     if( mPlayState == PlayState::PAUSED || mPlayState == PlayState::STOPPED )
174     {
175       RenderFrame();
176     }
177   }
178 }
179
180 void VectorAnimationTask::SetSize( uint32_t width, uint32_t height )
181 {
182   if( mWidth != width || mHeight != height )
183   {
184     mVectorRenderer.SetSize( width, height );
185
186     mWidth = width;
187     mHeight = height;
188
189     mResourceReady = false;
190
191     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetSize: width = %d, height = %d [%p]\n", width, height, this );
192   }
193 }
194
195 void VectorAnimationTask::PlayAnimation()
196 {
197   if( mPlayState != PlayState::PLAYING )
198   {
199     mUpdateFrameNumber = false;
200     mPlayState = PlayState::PLAYING;
201
202     mVectorAnimationThread.AddTask( this );
203
204     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PlayAnimation: Play [%p]\n", this );
205   }
206 }
207
208 void VectorAnimationTask::StopAnimation()
209 {
210   if( mPlayState != PlayState::STOPPED && mPlayState != PlayState::STOPPING )
211   {
212     mNeedAnimationFinishedTrigger = false;
213     mPlayState = PlayState::STOPPING;
214
215     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::StopAnimation: Stop [%p]\n", this );
216   }
217 }
218
219 void VectorAnimationTask::PauseAnimation()
220 {
221   if( mPlayState == PlayState::PLAYING )
222   {
223     mPlayState = PlayState::PAUSED;
224
225     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PauseAnimation: Pause [%p]\n", this );
226   }
227 }
228
229 void VectorAnimationTask::RenderFrame()
230 {
231   if( !mResourceReady )
232   {
233     mVectorAnimationThread.AddTask( this );
234
235     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::RenderFrame: Render [%p]\n", this );
236   }
237 }
238
239 void VectorAnimationTask::SetAnimationFinishedCallback( EventThreadCallback* callback )
240 {
241   ConditionalWait::ScopedLock lock( mConditionalWait );
242   if( callback )
243   {
244     mAnimationFinishedTrigger = std::unique_ptr< EventThreadCallback >( callback );
245   }
246 }
247
248 void VectorAnimationTask::SetLoopCount( int32_t count )
249 {
250   if( mLoopCount != count )
251   {
252     mLoopCount = count;
253     mCurrentLoop = 0;
254     mCurrentLoopUpdated = true;
255
256     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetLoopCount: [%d] [%p]\n", count, this );
257   }
258 }
259
260 void VectorAnimationTask::SetPlayRange( const Property::Array& playRange )
261 {
262   bool valid = false;
263   uint32_t startFrame = 0, endFrame = 0;
264   size_t count = playRange.Count();
265
266   if( count >= 2 )
267   {
268     int32_t start = 0, end = 0;
269     if( playRange.GetElementAt( 0 ).Get( start ) && playRange.GetElementAt( 1 ).Get( end ) )
270     {
271       startFrame = static_cast< uint32_t >( start );
272       endFrame = static_cast< uint32_t >( end );
273       valid = true;
274     }
275     else
276     {
277       std::string startMarker, endMarker;
278       if( playRange.GetElementAt( 0 ).Get( startMarker ) && playRange.GetElementAt( 1 ).Get( endMarker ) )
279       {
280         if( mVectorRenderer )
281         {
282           uint32_t frame;   // We don't use this later
283           if( mVectorRenderer.GetMarkerInfo( startMarker, startFrame, frame ) && mVectorRenderer.GetMarkerInfo( endMarker, frame, endFrame ) )
284           {
285             valid = true;
286           }
287         }
288       }
289     }
290   }
291   else if( count == 1 )
292   {
293     std::string marker;
294     if( playRange.GetElementAt( 0 ).Get( marker ) )
295     {
296       if( mVectorRenderer )
297       {
298         mVectorRenderer.GetMarkerInfo( marker, startFrame, endFrame );
299         valid = true;
300       }
301     }
302   }
303
304   if( !valid )
305   {
306     DALI_LOG_ERROR( "VectorAnimationTask::SetPlayRange: Invalid range [%p]\n", this );
307     return;
308   }
309
310   // Make sure the range specified is between 0 and the total frame number
311   if( startFrame >= 0 && startFrame < mTotalFrame && endFrame >= 0 && endFrame < mTotalFrame )
312   {
313     // If the range is not in order swap values
314     if( startFrame > endFrame )
315     {
316       uint32_t temp = startFrame;
317       startFrame = endFrame;
318       endFrame = temp;
319     }
320
321     if( startFrame != mStartFrame || endFrame != mEndFrame )
322     {
323       mStartFrame = startFrame;
324       mEndFrame = endFrame;
325
326       // If the current frame is out of the range, change the current frame also.
327       if( mStartFrame > mCurrentFrame )
328       {
329         mCurrentFrame = mStartFrame;
330
331         mCurrentFrameUpdated = true;
332         mResourceReady = false;
333       }
334       else if( mEndFrame < mCurrentFrame )
335       {
336         mCurrentFrame = mEndFrame;
337
338         mCurrentFrameUpdated = true;
339         mResourceReady = false;
340       }
341
342       DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetPlayRange: [%d, %d] [%p]\n", mStartFrame, mEndFrame, this );
343     }
344   }
345   else
346   {
347     DALI_LOG_ERROR( "VectorAnimationTask::SetPlayRange: Invalid range (%d, %d) [%p]\n", startFrame, endFrame, this );
348     return;
349   }
350 }
351
352 void VectorAnimationTask::GetPlayRange( uint32_t& startFrame, uint32_t& endFrame )
353 {
354   startFrame = mStartFrame;
355   endFrame = mEndFrame;
356 }
357
358 DevelImageVisual::PlayState::Type VectorAnimationTask::GetPlayState() const
359 {
360   DevelImageVisual::PlayState::Type state = DevelImageVisual::PlayState::STOPPED;
361
362   switch( mPlayState )
363   {
364     case PlayState::PLAYING:
365     {
366       state = DevelImageVisual::PlayState::PLAYING;
367       break;
368     }
369     case PlayState::PAUSED:
370     {
371       state = DevelImageVisual::PlayState::PAUSED;
372       break;
373     }
374     case PlayState::STOPPING:
375     case PlayState::STOPPED:
376     {
377       state = DevelImageVisual::PlayState::STOPPED;
378       break;
379     }
380   }
381
382   return state;
383 }
384
385 void VectorAnimationTask::SetCurrentFrameNumber( uint32_t frameNumber )
386 {
387   if( mCurrentFrame == frameNumber )
388   {
389     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: Set same frame [%d] [%p]\n", frameNumber, this );
390     return;
391   }
392
393   if( frameNumber >= mStartFrame && frameNumber <= mEndFrame )
394   {
395     mCurrentFrame = frameNumber;
396     mCurrentFrameUpdated = true;
397
398     mUpdateFrameNumber = false;
399     mResourceReady = false;
400
401     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: frame number = %d [%p]\n", mCurrentFrame, this );
402   }
403   else
404   {
405     DALI_LOG_ERROR( "Invalid frame number [%d (%d, %d)]\n", frameNumber, mStartFrame, mEndFrame );
406   }
407 }
408
409 uint32_t VectorAnimationTask::GetCurrentFrameNumber() const
410 {
411   return mCurrentFrame;
412 }
413
414 uint32_t VectorAnimationTask::GetTotalFrameNumber() const
415 {
416   return mTotalFrame;
417 }
418
419 void VectorAnimationTask::GetDefaultSize( uint32_t& width, uint32_t& height ) const
420 {
421   mVectorRenderer.GetDefaultSize( width, height );
422 }
423
424 void VectorAnimationTask::SetStopBehavior( DevelImageVisual::StopBehavior::Type stopBehavior )
425 {
426   mStopBehavior = stopBehavior;
427
428   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetStopBehavior: stop behavor = %d [%p]\n", mStopBehavior, this );
429 }
430
431 void VectorAnimationTask::SetLoopingMode( DevelImageVisual::LoopingMode::Type loopingMode )
432 {
433   mLoopingMode = loopingMode;
434
435   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetLoopingMode: looping mode = %d [%p]\n", mLoopingMode, this );
436 }
437
438 void VectorAnimationTask::GetLayerInfo( Property::Map& map ) const
439 {
440   mVectorRenderer.GetLayerInfo( map );
441 }
442
443 VectorAnimationTask::UploadCompletedSignalType& VectorAnimationTask::UploadCompletedSignal()
444 {
445   return mVectorRenderer.UploadCompletedSignal();
446 }
447
448 void VectorAnimationTask::Initialize()
449 {
450   mVectorRenderer = VectorAnimationRenderer::New( mUrl );
451
452   mTotalFrame = mVectorRenderer.GetTotalFrameNumber();
453
454   mEndFrame = mTotalFrame - 1;
455
456   mFrameRate = mVectorRenderer.GetFrameRate();
457   mFrameDurationNanoSeconds = NANOSECONDS_PER_SECOND / mFrameRate;
458
459   uint32_t width, height;
460   mVectorRenderer.GetDefaultSize( width, height );
461
462   SetSize( width, height );
463
464   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Initialize: file = %s [%d frames, %f fps] [%p]\n", mUrl.c_str(), mTotalFrame, mFrameRate, this );
465 }
466
467 bool VectorAnimationTask::Rasterize()
468 {
469   bool stopped = false, needAnimationFinishedTrigger, resourceReady;
470   uint32_t currentFrame, startFrame, endFrame;
471   int32_t loopCount, currentLoopCount;
472   PlayState playState;
473
474   {
475     ConditionalWait::ScopedLock lock( mConditionalWait );
476
477     if( mPlayState == PlayState::PLAYING && mUpdateFrameNumber )
478     {
479       mCurrentFrame = mForward ? mCurrentFrame + 1 : mCurrentFrame - 1;
480       Dali::ClampInPlace( mCurrentFrame, mStartFrame, mEndFrame );
481     }
482
483     currentFrame = mCurrentFrame;
484     startFrame = mStartFrame;
485     endFrame = mEndFrame;
486     loopCount = mLoopCount;
487     currentLoopCount = mCurrentLoop;
488     needAnimationFinishedTrigger = mNeedAnimationFinishedTrigger;
489     playState = mPlayState;
490     resourceReady = mResourceReady;
491
492     mResourceReady = true;
493     mCurrentFrameUpdated = false;
494     mCurrentLoopUpdated = false;
495     mUpdateFrameNumber = true;
496     mNeedAnimationFinishedTrigger = true;
497   }
498
499   if( playState == PlayState::STOPPING )
500   {
501     currentFrame = GetStoppedFrame( startFrame, endFrame, currentFrame );
502     ResetValue( mCurrentFrameUpdated, mCurrentFrame, currentFrame, mConditionalWait );
503
504     stopped = true;
505   }
506   else if( playState == PlayState::PLAYING )
507   {
508     bool animationFinished = false;
509
510     if( currentFrame >= endFrame )  // last frame
511     {
512       if( mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE )
513       {
514         mForward = false;
515       }
516       else
517       {
518         if( loopCount < 0 || ++currentLoopCount < loopCount )   // repeat forever or before the last loop
519         {
520           ResetValue( mCurrentFrameUpdated, mCurrentFrame, startFrame, mConditionalWait );  // If the current frame is changed in the event thread, don't overwrite it.
521           mUpdateFrameNumber = false;
522         }
523         else
524         {
525           animationFinished = true;   // end of animation
526         }
527         ResetValue( mCurrentLoopUpdated, mCurrentLoop, currentLoopCount, mConditionalWait );
528       }
529     }
530     else if( currentFrame == startFrame && !mForward )  // first frame
531     {
532       if( loopCount < 0 || ++currentLoopCount < loopCount )   // repeat forever or before the last loop
533       {
534         mForward = true;
535       }
536       else
537       {
538         animationFinished = true;   // end of animation
539       }
540       ResetValue( mCurrentLoopUpdated, mCurrentLoop, currentLoopCount, mConditionalWait );
541     }
542
543     if( animationFinished )
544     {
545       if( mStopBehavior == DevelImageVisual::StopBehavior::CURRENT_FRAME )
546       {
547         stopped = true;
548       }
549       else
550       {
551         mPlayState = PlayState::STOPPING;
552       }
553     }
554   }
555
556   // Rasterize
557   bool renderSuccess = false;
558   if( mVectorRenderer )
559   {
560     renderSuccess = mVectorRenderer.Render( currentFrame );
561     if( !renderSuccess )
562     {
563       DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Rendering failed. Try again later.[%d] [%p]\n", currentFrame, this );
564       mUpdateFrameNumber = false;
565
566       if( !resourceReady )
567       {
568         ConditionalWait::ScopedLock lock( mConditionalWait );
569         mResourceReady = false;
570       }
571     }
572   }
573
574   if( stopped && renderSuccess )
575   {
576     ConditionalWait::ScopedLock lock( mConditionalWait );
577
578     mPlayState = PlayState::STOPPED;
579     mForward = true;
580     mCurrentLoop = 0;
581
582     // Animation is finished
583     if( needAnimationFinishedTrigger && mAnimationFinishedTrigger )
584     {
585       mAnimationFinishedTrigger->Trigger();
586     }
587
588     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Animation is finished [current = %d] [%p]\n", currentFrame, this );
589   }
590
591   bool keepAnimation = true;
592   if( playState == PlayState::PAUSED || playState == PlayState::STOPPED )
593   {
594     keepAnimation = false;
595   }
596
597   return keepAnimation;
598 }
599
600 uint32_t VectorAnimationTask::GetStoppedFrame( uint32_t startFrame, uint32_t endFrame, uint32_t currentFrame )
601 {
602   uint32_t frame = currentFrame;
603
604   switch( mStopBehavior )
605   {
606     case DevelImageVisual::StopBehavior::FIRST_FRAME:
607     {
608       frame = startFrame;
609       break;
610     }
611     case DevelImageVisual::StopBehavior::LAST_FRAME:
612     {
613       if( mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE )
614       {
615         frame = startFrame;
616       }
617       else
618       {
619         frame = endFrame;
620       }
621       break;
622     }
623     case DevelImageVisual::StopBehavior::CURRENT_FRAME:
624     {
625       frame = currentFrame;
626       break;
627     }
628   }
629
630   return frame;
631 }
632
633 std::chrono::time_point< std::chrono::system_clock > VectorAnimationTask::CalculateNextFrameTime( bool renderNow )
634 {
635   // std::chrono::time_point template has second parameter duration which defaults to the std::chrono::system_clock supported
636   // duration. In some C++11 implementations it is a milliseconds duration, so it fails to compile unless mNextFrameStartTime
637   // is casted to use the default duration.
638   mNextFrameStartTime =  std::chrono::time_point_cast< std::chrono::time_point< std::chrono::system_clock >::duration >(
639       mNextFrameStartTime + std::chrono::nanoseconds( mFrameDurationNanoSeconds ) );
640   auto current = std::chrono::system_clock::now();
641   if( renderNow || mNextFrameStartTime < current )
642   {
643     mNextFrameStartTime = current;
644   }
645   return mNextFrameStartTime;
646 }
647
648 std::chrono::time_point< std::chrono::system_clock > VectorAnimationTask::GetNextFrameTime()
649 {
650   return mNextFrameStartTime;
651 }
652
653 } // namespace Internal
654
655 } // namespace Toolkit
656
657 } // namespace Dali