[dali_1.9.17] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / animated-vector-image / vector-animation-task.cpp
1 /*
2  * Copyright (c) 2020 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 } // unnamed namespace
50
51 VectorAnimationTask::VectorAnimationTask( VisualFactoryCache& factoryCache, const std::string& url )
52 : mUrl( url ),
53   mVectorRenderer(),
54   mAnimationData(),
55   mVectorAnimationThread( factoryCache.GetVectorAnimationThread() ),
56   mConditionalWait(),
57   mAnimationFinishedTrigger(),
58   mPlayState( PlayState::STOPPED ),
59   mStopBehavior( DevelImageVisual::StopBehavior::CURRENT_FRAME ),
60   mLoopingMode( DevelImageVisual::LoopingMode::RESTART ),
61   mNextFrameStartTime(),
62   mFrameDurationNanoSeconds( 0 ),
63   mFrameRate( 60.0f ),
64   mCurrentFrame( 0 ),
65   mTotalFrame( 0 ),
66   mStartFrame( 0 ),
67   mEndFrame( 0 ),
68   mWidth( 0 ),
69   mHeight( 0 ),
70   mAnimationDataIndex( 0 ),
71   mLoopCount( LOOP_FOREVER ),
72   mCurrentLoop( 0 ),
73   mResourceReady( false ),
74   mForward( true ),
75   mUpdateFrameNumber( false ),
76   mNeedAnimationFinishedTrigger( true ),
77   mAnimationDataUpdated( false ),
78   mDestroyTask( false )
79 {
80   Initialize();
81 }
82
83 VectorAnimationTask::~VectorAnimationTask()
84 {
85   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::~VectorAnimationTask: destructor [%p]\n", this );
86 }
87
88 void VectorAnimationTask::Finalize()
89 {
90   ConditionalWait::ScopedLock lock( mConditionalWait );
91
92   // Release some objects in the main thread
93   if( mAnimationFinishedTrigger )
94   {
95     mAnimationFinishedTrigger.reset();
96   }
97
98   mVectorRenderer.Finalize();
99
100   mDestroyTask = true;
101 }
102
103 void VectorAnimationTask::SetRenderer( Renderer renderer )
104 {
105   ConditionalWait::ScopedLock lock( mConditionalWait );
106
107   mVectorRenderer.SetRenderer( renderer );
108
109   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetRenderer [%p]\n", this );
110 }
111
112 void VectorAnimationTask::SetAnimationData( const AnimationData& data )
113 {
114   ConditionalWait::ScopedLock lock( mConditionalWait );
115
116   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetAnimationData [%p]\n", this );
117
118   uint32_t index = mAnimationDataIndex == 0 ? 1 : 0;  // Use the other buffer
119
120   mAnimationData[index] = data;
121   mAnimationDataUpdated = true;
122
123   if( data.resendFlag & VectorAnimationTask::RESEND_SIZE )
124   {
125     // The size should be changed in the main thread.
126     SetSize( data.width, data.height );
127   }
128
129   mVectorAnimationThread.AddTask( this );
130 }
131
132 void VectorAnimationTask::SetSize( uint32_t width, uint32_t height )
133 {
134   if( mWidth != width || mHeight != height )
135   {
136     mVectorRenderer.SetSize( width, height );
137
138     mWidth = width;
139     mHeight = height;
140
141     mResourceReady = false;
142
143     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetSize: width = %d, height = %d [%p]\n", width, height, this );
144   }
145 }
146
147 void VectorAnimationTask::PlayAnimation()
148 {
149   if( mPlayState != PlayState::PLAYING )
150   {
151     mUpdateFrameNumber = false;
152     mPlayState = PlayState::PLAYING;
153
154     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PlayAnimation: Play [%p]\n", this );
155   }
156 }
157
158 void VectorAnimationTask::StopAnimation()
159 {
160   if( mPlayState != PlayState::STOPPING )
161   {
162     mNeedAnimationFinishedTrigger = false;
163     mPlayState = PlayState::STOPPING;
164
165     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::StopAnimation: Stop [%p]\n", this );
166   }
167 }
168
169 void VectorAnimationTask::PauseAnimation()
170 {
171   if( mPlayState == PlayState::PLAYING )
172   {
173     mPlayState = PlayState::PAUSED;
174
175     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PauseAnimation: Pause [%p]\n", this );
176   }
177 }
178
179 void VectorAnimationTask::SetAnimationFinishedCallback( EventThreadCallback* callback )
180 {
181   ConditionalWait::ScopedLock lock( mConditionalWait );
182   if( callback )
183   {
184     mAnimationFinishedTrigger = std::unique_ptr< EventThreadCallback >( callback );
185   }
186 }
187
188 void VectorAnimationTask::SetLoopCount( int32_t count )
189 {
190   if( mLoopCount != count )
191   {
192     mLoopCount = count;
193     mCurrentLoop = 0;
194
195     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetLoopCount: [%d] [%p]\n", count, this );
196   }
197 }
198
199 void VectorAnimationTask::SetPlayRange( const Property::Array& playRange )
200 {
201   bool valid = false;
202   uint32_t startFrame = 0, endFrame = 0;
203   size_t count = playRange.Count();
204
205   if( count >= 2 )
206   {
207     int32_t start = 0, end = 0;
208     if( playRange.GetElementAt( 0 ).Get( start ) && playRange.GetElementAt( 1 ).Get( end ) )
209     {
210       startFrame = static_cast< uint32_t >( start );
211       endFrame = static_cast< uint32_t >( end );
212       valid = true;
213     }
214     else
215     {
216       std::string startMarker, endMarker;
217       if( playRange.GetElementAt( 0 ).Get( startMarker ) && playRange.GetElementAt( 1 ).Get( endMarker ) )
218       {
219         if( mVectorRenderer )
220         {
221           uint32_t frame;   // We don't use this later
222           if( mVectorRenderer.GetMarkerInfo( startMarker, startFrame, frame ) && mVectorRenderer.GetMarkerInfo( endMarker, frame, endFrame ) )
223           {
224             valid = true;
225           }
226         }
227       }
228     }
229   }
230   else if( count == 1 )
231   {
232     std::string marker;
233     if( playRange.GetElementAt( 0 ).Get( marker ) )
234     {
235       if( mVectorRenderer )
236       {
237         mVectorRenderer.GetMarkerInfo( marker, startFrame, endFrame );
238         valid = true;
239       }
240     }
241   }
242
243   if( !valid )
244   {
245     DALI_LOG_ERROR( "VectorAnimationTask::SetPlayRange: Invalid range [%p]\n", this );
246     return;
247   }
248
249   // Make sure the range specified is between 0 and the total frame number
250   if( startFrame < mTotalFrame && endFrame < mTotalFrame )
251   {
252     // If the range is not in order swap values
253     if( startFrame > endFrame )
254     {
255       uint32_t temp = startFrame;
256       startFrame = endFrame;
257       endFrame = temp;
258     }
259
260     if( startFrame != mStartFrame || endFrame != mEndFrame )
261     {
262       mStartFrame = startFrame;
263       mEndFrame = endFrame;
264
265       // If the current frame is out of the range, change the current frame also.
266       if( mStartFrame > mCurrentFrame )
267       {
268         mCurrentFrame = mStartFrame;
269         mResourceReady = false;
270       }
271       else if( mEndFrame < mCurrentFrame )
272       {
273         mCurrentFrame = mEndFrame;
274         mResourceReady = false;
275       }
276
277       DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetPlayRange: [%d, %d] [%p]\n", mStartFrame, mEndFrame, this );
278     }
279   }
280   else
281   {
282     DALI_LOG_ERROR( "VectorAnimationTask::SetPlayRange: Invalid range (%d, %d) [%p]\n", startFrame, endFrame, this );
283     return;
284   }
285 }
286
287 void VectorAnimationTask::GetPlayRange( uint32_t& startFrame, uint32_t& endFrame )
288 {
289   startFrame = mStartFrame;
290   endFrame = mEndFrame;
291 }
292
293 void VectorAnimationTask::SetCurrentFrameNumber( uint32_t frameNumber )
294 {
295   if( mCurrentFrame == frameNumber )
296   {
297     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: Set same frame [%d] [%p]\n", frameNumber, this );
298     return;
299   }
300
301   if( frameNumber >= mStartFrame && frameNumber <= mEndFrame )
302   {
303     mCurrentFrame = frameNumber;
304     mUpdateFrameNumber = false;
305     mResourceReady = false;
306
307     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: frame number = %d [%p]\n", mCurrentFrame, this );
308   }
309   else
310   {
311     DALI_LOG_ERROR( "Invalid frame number [%d (%d, %d)]\n", frameNumber, mStartFrame, mEndFrame );
312   }
313 }
314
315 uint32_t VectorAnimationTask::GetCurrentFrameNumber() const
316 {
317   return mCurrentFrame;
318 }
319
320 uint32_t VectorAnimationTask::GetTotalFrameNumber() const
321 {
322   return mTotalFrame;
323 }
324
325 void VectorAnimationTask::GetDefaultSize( uint32_t& width, uint32_t& height ) const
326 {
327   mVectorRenderer.GetDefaultSize( width, height );
328 }
329
330 void VectorAnimationTask::SetStopBehavior( DevelImageVisual::StopBehavior::Type stopBehavior )
331 {
332   mStopBehavior = stopBehavior;
333
334   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetStopBehavior: stop behavor = %d [%p]\n", mStopBehavior, this );
335 }
336
337 void VectorAnimationTask::SetLoopingMode( DevelImageVisual::LoopingMode::Type loopingMode )
338 {
339   mLoopingMode = loopingMode;
340
341   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetLoopingMode: looping mode = %d [%p]\n", mLoopingMode, this );
342 }
343
344 void VectorAnimationTask::GetLayerInfo( Property::Map& map ) const
345 {
346   mVectorRenderer.GetLayerInfo( map );
347 }
348
349 VectorAnimationTask::UploadCompletedSignalType& VectorAnimationTask::UploadCompletedSignal()
350 {
351   return mVectorRenderer.UploadCompletedSignal();
352 }
353
354 void VectorAnimationTask::Initialize()
355 {
356   mVectorRenderer = VectorAnimationRenderer::New( mUrl );
357
358   mTotalFrame = mVectorRenderer.GetTotalFrameNumber();
359
360   mEndFrame = mTotalFrame - 1;
361
362   mFrameRate = mVectorRenderer.GetFrameRate();
363   mFrameDurationNanoSeconds = NANOSECONDS_PER_SECOND / mFrameRate;
364
365   uint32_t width, height;
366   mVectorRenderer.GetDefaultSize( width, height );
367
368   SetSize( width, height );
369
370   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Initialize: file = %s [%d frames, %f fps] [%p]\n", mUrl.c_str(), mTotalFrame, mFrameRate, this );
371 }
372
373 bool VectorAnimationTask::Rasterize()
374 {
375   bool stopped = false;
376   uint32_t currentFrame;
377
378   {
379     ConditionalWait::ScopedLock lock( mConditionalWait );
380     if( mDestroyTask )
381     {
382       // The task will be destroyed. We don't need rasterization.
383       return false;
384     }
385   }
386
387   ApplyAnimationData();
388
389   if( mPlayState == PlayState::PLAYING && mUpdateFrameNumber )
390   {
391     mCurrentFrame = mForward ? mCurrentFrame + 1 : mCurrentFrame - 1;
392     Dali::ClampInPlace( mCurrentFrame, mStartFrame, mEndFrame );
393   }
394
395   currentFrame = mCurrentFrame;
396
397   // Reset values
398   mResourceReady = true;
399   mUpdateFrameNumber = true;
400   mNeedAnimationFinishedTrigger = true;
401
402   if( mPlayState == PlayState::STOPPING )
403   {
404     mCurrentFrame = GetStoppedFrame( mStartFrame, mEndFrame, mCurrentFrame );
405     currentFrame = mCurrentFrame;
406     stopped = true;
407   }
408   else if( mPlayState == PlayState::PLAYING )
409   {
410     bool animationFinished = false;
411
412     if( currentFrame >= mEndFrame )  // last frame
413     {
414       if( mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE )
415       {
416         mForward = false;
417       }
418       else
419       {
420         if( mLoopCount < 0 || ++mCurrentLoop < mLoopCount )   // repeat forever or before the last loop
421         {
422           mCurrentFrame = mStartFrame;
423           mUpdateFrameNumber = false;
424         }
425         else
426         {
427           animationFinished = true;   // end of animation
428         }
429       }
430     }
431     else if( currentFrame == mStartFrame && !mForward )  // first frame
432     {
433       if( mLoopCount < 0 || ++mCurrentLoop < mLoopCount )   // repeat forever or before the last loop
434       {
435         mForward = true;
436       }
437       else
438       {
439         animationFinished = true;   // end of animation
440       }
441     }
442
443     if( animationFinished )
444     {
445       if( mStopBehavior == DevelImageVisual::StopBehavior::CURRENT_FRAME )
446       {
447         stopped = true;
448       }
449       else
450       {
451         mPlayState = PlayState::STOPPING;
452       }
453     }
454   }
455
456   // Rasterize
457   bool renderSuccess = false;
458   if( mVectorRenderer )
459   {
460     renderSuccess = mVectorRenderer.Render( currentFrame );
461     if( !renderSuccess )
462     {
463       DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Rendering failed. Try again later.[%d] [%p]\n", currentFrame, this );
464       mUpdateFrameNumber = false;
465
466       if( !mResourceReady )
467       {
468         mResourceReady = false;
469       }
470     }
471   }
472
473   if( stopped && renderSuccess )
474   {
475     mPlayState = PlayState::STOPPED;
476     mForward = true;
477     mCurrentLoop = 0;
478
479     // Animation is finished
480     {
481       ConditionalWait::ScopedLock lock( mConditionalWait );
482       if( mNeedAnimationFinishedTrigger && mAnimationFinishedTrigger )
483       {
484         mAnimationFinishedTrigger->Trigger();
485       }
486     }
487
488     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Animation is finished [current = %d] [%p]\n", currentFrame, this );
489   }
490
491   bool keepAnimation = true;
492   if( mPlayState == PlayState::PAUSED || mPlayState == PlayState::STOPPED )
493   {
494     keepAnimation = false;
495   }
496
497   return keepAnimation;
498 }
499
500 uint32_t VectorAnimationTask::GetStoppedFrame( uint32_t startFrame, uint32_t endFrame, uint32_t currentFrame )
501 {
502   uint32_t frame = currentFrame;
503
504   switch( mStopBehavior )
505   {
506     case DevelImageVisual::StopBehavior::FIRST_FRAME:
507     {
508       frame = startFrame;
509       break;
510     }
511     case DevelImageVisual::StopBehavior::LAST_FRAME:
512     {
513       if( mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE )
514       {
515         frame = startFrame;
516       }
517       else
518       {
519         frame = endFrame;
520       }
521       break;
522     }
523     case DevelImageVisual::StopBehavior::CURRENT_FRAME:
524     {
525       frame = currentFrame;
526       break;
527     }
528   }
529
530   return frame;
531 }
532
533 std::chrono::time_point< std::chrono::system_clock > VectorAnimationTask::CalculateNextFrameTime( bool renderNow )
534 {
535   // std::chrono::time_point template has second parameter duration which defaults to the std::chrono::system_clock supported
536   // duration. In some C++11 implementations it is a milliseconds duration, so it fails to compile unless mNextFrameStartTime
537   // is casted to use the default duration.
538   mNextFrameStartTime =  std::chrono::time_point_cast< std::chrono::time_point< std::chrono::system_clock >::duration >(
539       mNextFrameStartTime + std::chrono::nanoseconds( mFrameDurationNanoSeconds ) );
540   auto current = std::chrono::system_clock::now();
541   if( renderNow || mNextFrameStartTime < current )
542   {
543     mNextFrameStartTime = current;
544   }
545   return mNextFrameStartTime;
546 }
547
548 std::chrono::time_point< std::chrono::system_clock > VectorAnimationTask::GetNextFrameTime()
549 {
550   return mNextFrameStartTime;
551 }
552
553 void VectorAnimationTask::ApplyAnimationData()
554 {
555   uint32_t index;
556
557   {
558     ConditionalWait::ScopedLock lock( mConditionalWait );
559
560     if( !mAnimationDataUpdated || mAnimationData[mAnimationDataIndex].resendFlag != 0 )
561     {
562       // Data is not updated or the previous data is not applied yet.
563       return;
564     }
565
566     mAnimationDataIndex = mAnimationDataIndex == 0 ? 1 : 0;  // Swap index
567     mAnimationDataUpdated = false;
568
569     index = mAnimationDataIndex;
570   }
571
572   if( mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_LOOP_COUNT )
573   {
574     SetLoopCount( mAnimationData[index].loopCount );
575   }
576
577   if( mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_PLAY_RANGE )
578   {
579     SetPlayRange( mAnimationData[index].playRange );
580   }
581
582   if( mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_STOP_BEHAVIOR )
583   {
584     SetStopBehavior( mAnimationData[index].stopBehavior );
585   }
586
587   if( mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_LOOPING_MODE )
588   {
589     SetLoopingMode( mAnimationData[index].loopingMode );
590   }
591
592   if( mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_CURRENT_FRAME )
593   {
594     SetCurrentFrameNumber( mAnimationData[index].currentFrame );
595   }
596
597   if( mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_PLAY_STATE )
598   {
599     if( mAnimationData[index].playState == DevelImageVisual::PlayState::PLAYING )
600     {
601       PlayAnimation();
602     }
603     else if( mAnimationData[index].playState == DevelImageVisual::PlayState::PAUSED )
604     {
605       PauseAnimation();
606     }
607     else if( mAnimationData[index].playState == DevelImageVisual::PlayState::STOPPED )
608     {
609       StopAnimation();
610     }
611   }
612
613   mAnimationData[index].resendFlag = 0;
614 }
615
616 } // namespace Internal
617
618 } // namespace Toolkit
619
620 } // namespace Dali