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