[4.0] (AnimatedVectorImageVisual) Change renderer on stage again
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / animated-vector-image / vector-rasterize-thread.cpp
1 /*
2  * Copyright (c) 2018 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-rasterize-thread.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/adaptors/adaptor.h>
23 #include <dali/integration-api/debug.h>
24
25 // INTERNAL INCLUDES
26
27 namespace Dali
28 {
29
30 namespace Toolkit
31 {
32
33 namespace Internal
34 {
35
36 namespace
37 {
38
39 constexpr auto LOOP_FOREVER = -1;
40
41 #if defined(DEBUG_ENABLED)
42 Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_VECTOR_ANIMATION" );
43 #endif
44
45 } // unnamed namespace
46
47 VectorRasterizeThread::VectorRasterizeThread( const std::string& url )
48 : mUrl( url ),
49   mVectorRenderer(),
50   mConditionalWait(),
51   mMutex(),
52   mResourceReadyTrigger( NULL ),
53   mAnimationFinishedTrigger( NULL ),
54   mPlayRange( 0.0f, 1.0f ),
55   mPlayState( DevelImageVisual::PlayState::STOPPED ),
56   mProgress( 0.0f ),
57   mCurrentFrame( 0 ),
58   mTotalFrame( 0 ),
59   mStartFrame( 0 ),
60   mEndFrame( 0 ),
61   mWidth( 0 ),
62   mHeight( 0 ),
63   mLoopCount( LOOP_FOREVER ),
64   mCurrentLoop( 0 ),
65   mNeedRender( false ),
66   mDestroyThread( false ),
67   mResourceReady( false ),
68   mLogFactory( Dali::Adaptor::Get().GetLogFactory() )
69 {
70   mVectorRenderer = VectorAnimationRenderer::New( mUrl );
71 }
72
73 VectorRasterizeThread::~VectorRasterizeThread()
74 {
75   // Stop the thread
76   {
77     ConditionalWait::ScopedLock lock( mConditionalWait );
78     mDestroyThread = true;
79     mConditionalWait.Notify( lock );
80
81     // This should be called in the main thread to stop waiting for the dequeuable buffer.
82     mVectorRenderer.StopRender();
83   }
84
85   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::~VectorRasterizeThread: Join\n" );
86
87   Join();
88
89   delete mResourceReadyTrigger;
90   delete mAnimationFinishedTrigger;
91 }
92
93 void VectorRasterizeThread::Run()
94 {
95   mLogFactory.InstallLogFunction();
96
97   //TODO: check the return value
98   StartRender();
99
100   while( IsThreadReady() )
101   {
102     Rasterize();
103   }
104 }
105
106 void VectorRasterizeThread::SetRenderer( Renderer renderer )
107 {
108   ConditionalWait::ScopedLock lock( mConditionalWait );
109
110   mVectorRenderer.SetRenderer( renderer );
111
112   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetRenderer\n" );
113 }
114
115 void VectorRasterizeThread::SetSize( uint32_t width, uint32_t height )
116 {
117   if( mWidth != width || mHeight != height )
118   {
119     ConditionalWait::ScopedLock lock( mConditionalWait );
120     mVectorRenderer.SetSize( width, height );
121
122     mWidth = width;
123     mHeight = height;
124
125     mResourceReady = false;
126
127     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetSize: width = %d, height = %d\n", width, height );
128   }
129 }
130
131 void VectorRasterizeThread::PlayAnimation()
132 {
133   ConditionalWait::ScopedLock lock( mConditionalWait );
134   if( mPlayState != DevelImageVisual::PlayState::PLAYING )
135   {
136     if( mPlayState == DevelImageVisual::PlayState::STOPPED )
137     {
138       // Reset the current frame and the current loop
139       mCurrentFrame = mStartFrame;
140       mCurrentLoop = 0;
141     }
142
143     mPlayState = DevelImageVisual::PlayState::PLAYING;
144     mConditionalWait.Notify( lock );
145
146     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::PlayAnimation: Start\n" );
147   }
148 }
149
150 void VectorRasterizeThread::StopAnimation()
151 {
152   ConditionalWait::ScopedLock lock( mConditionalWait );
153   if( mPlayState != DevelImageVisual::PlayState::STOPPED )
154   {
155     mPlayState = DevelImageVisual::PlayState::STOPPED;
156
157     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::StopAnimation: Stop\n" );
158   }
159 }
160
161 void VectorRasterizeThread::PauseAnimation()
162 {
163   ConditionalWait::ScopedLock lock( mConditionalWait );
164   if( mPlayState == DevelImageVisual::PlayState::PLAYING )
165   {
166     mPlayState = DevelImageVisual::PlayState::PAUSED;
167
168     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::PauseAnimation: Pause\n" );
169   }
170 }
171
172 void VectorRasterizeThread::RenderFrame()
173 {
174   ConditionalWait::ScopedLock lock( mConditionalWait );
175   mNeedRender = true;
176   mConditionalWait.Notify( lock );
177
178   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::RenderFrame: Render\n" );
179 }
180
181 void VectorRasterizeThread::SetResourceReadyCallback( EventThreadCallback* callback )
182 {
183   ConditionalWait::ScopedLock lock( mConditionalWait );
184   mResourceReadyTrigger = callback;
185 }
186
187 void VectorRasterizeThread::SetAnimationFinishedCallback( EventThreadCallback* callback )
188 {
189   ConditionalWait::ScopedLock lock( mConditionalWait );
190   mAnimationFinishedTrigger = callback;
191 }
192
193 void VectorRasterizeThread::SetLoopCount( int32_t count )
194 {
195   ConditionalWait::ScopedLock lock( mConditionalWait );
196
197   mLoopCount = count;
198
199   // Reset progress
200   mCurrentLoop = 0;
201   mCurrentFrame = mStartFrame;
202 }
203
204 int32_t VectorRasterizeThread::GetLoopCount() const
205 {
206   return mLoopCount;
207 }
208
209 void VectorRasterizeThread::SetPlayRange( Vector2 range )
210 {
211   ConditionalWait::ScopedLock lock( mConditionalWait );
212
213   // Make sure the range specified is between 0.0 and 1.0
214   if( range.x >= 0.0f && range.x <= 1.0f && range.y >= 0.0f && range.y <= 1.0f )
215   {
216     Vector2 orderedRange( range );
217     // If the range is not in order swap values
218     if( range.x > range.y )
219     {
220       orderedRange = Vector2( range.y, range.x );
221     }
222
223     mPlayRange = orderedRange;
224
225     if( mTotalFrame != 0 )
226     {
227       mStartFrame = static_cast< uint32_t >( mPlayRange.x * mTotalFrame + 0.5f );
228       mEndFrame = static_cast< uint32_t >( mPlayRange.y * mTotalFrame + 0.5f );
229     }
230   }
231 }
232
233 Vector2 VectorRasterizeThread::GetPlayRange() const
234 {
235   return mPlayRange;
236 }
237
238 DevelImageVisual::PlayState VectorRasterizeThread::GetPlayState() const
239 {
240   return mPlayState;
241 }
242
243 bool VectorRasterizeThread::IsResourceReady() const
244 {
245   return mResourceReady;
246 }
247
248 bool VectorRasterizeThread::IsThreadReady()
249 {
250   ConditionalWait::ScopedLock lock( mConditionalWait );
251
252   if( mPlayState != DevelImageVisual::PlayState::PLAYING && !mNeedRender && !mDestroyThread )
253   {
254     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::IsThreadReady: Wait\n" );
255
256     mConditionalWait.Wait( lock );
257   }
258
259   // Keep the thread alive if this thread is NOT to be destroyed
260   return !mDestroyThread;
261 }
262
263 bool VectorRasterizeThread::StartRender()
264 {
265   //TODO: check the return value
266   mVectorRenderer.StartRender();
267
268   mTotalFrame = mVectorRenderer.GetTotalFrameNumber();
269
270   mStartFrame = static_cast< uint32_t >( mPlayRange.x * mTotalFrame + 0.5f );
271   mEndFrame = static_cast< uint32_t >( mPlayRange.y * mTotalFrame + 0.5f );
272
273   mCurrentFrame = mStartFrame;
274
275   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::StartRender: Renderer is started [%d (%d, %d)]\n", mTotalFrame, mStartFrame, mEndFrame );
276
277   return true;
278 }
279
280 void VectorRasterizeThread::Rasterize()
281 {
282   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: [%d]\n", mCurrentFrame );
283
284   // Rasterize
285   mVectorRenderer.Render( mCurrentFrame );
286
287   if( mPlayState == DevelImageVisual::PlayState::PLAYING )
288   {
289     if( ++mCurrentFrame >= mEndFrame )
290     {
291       if( mLoopCount < 0 )
292       {
293         // repeat forever
294         mCurrentFrame = mStartFrame;
295       }
296       else
297       {
298         mCurrentLoop++;
299         if( mCurrentLoop >= mLoopCount )
300         {
301           // Animation is finished
302           mPlayState = DevelImageVisual::PlayState::STOPPED;
303
304           mAnimationFinishedTrigger->Trigger();
305
306           DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Animation is finished\n" );
307         }
308         else
309         {
310           mCurrentFrame = mStartFrame;
311         }
312       }
313     }
314   }
315
316   mNeedRender = false;
317
318   if( !mResourceReady )
319   {
320     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Resource ready trigger\n" );
321
322     mResourceReadyTrigger->Trigger();
323     mResourceReady = true;
324   }
325 }
326
327 } // namespace Internal
328
329 } // namespace Toolkit
330
331 } // namespace Dali