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