9e0645bb8b1c3c7ffebf9869e5d3c0a257a7993f
[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   mCurrentFrame( 0 ),
57   mTotalFrame( 0 ),
58   mStartFrame( 0 ),
59   mEndFrame( 0 ),
60   mWidth( 0 ),
61   mHeight( 0 ),
62   mLoopCount( LOOP_FOREVER ),
63   mCurrentLoop( 0 ),
64   mNeedRender( false ),
65   mDestroyThread( false ),
66   mResourceReady( false ),
67   mLogFactory( Dali::Adaptor::Get().GetLogFactory() )
68 {
69   mVectorRenderer = VectorAnimationRenderer::New( mUrl );
70 }
71
72 VectorRasterizeThread::~VectorRasterizeThread()
73 {
74   // Stop the thread
75   {
76     ConditionalWait::ScopedLock lock( mConditionalWait );
77     mDestroyThread = true;
78     mConditionalWait.Notify( lock );
79
80     // This should be called in the main thread to stop waiting for the dequeuable buffer.
81     mVectorRenderer.StopRender();
82   }
83
84   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::~VectorRasterizeThread: Join\n" );
85
86   Join();
87
88   delete mResourceReadyTrigger;
89   delete mAnimationFinishedTrigger;
90 }
91
92 void VectorRasterizeThread::Run()
93 {
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   // Need to trigger resource ready again
112   mResourceReady = false;
113
114   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetRenderer\n" );
115 }
116
117 void VectorRasterizeThread::SetSize( uint32_t width, uint32_t height )
118 {
119   ConditionalWait::ScopedLock lock( mConditionalWait );
120   mVectorRenderer.SetSize( width, height );
121
122   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetSize: width = %d, height = %d\n", width, height );
123 }
124
125 void VectorRasterizeThread::StartAnimation()
126 {
127   ConditionalWait::ScopedLock lock( mConditionalWait );
128   if( mPlayState != DevelImageVisual::PlayState::PLAYING )
129   {
130     if( mPlayState == DevelImageVisual::PlayState::STOPPED )
131     {
132       // Reset the current frame and the current loop
133       mCurrentFrame = mStartFrame;
134       mCurrentLoop = 0;
135     }
136
137     mPlayState = DevelImageVisual::PlayState::PLAYING;
138     mConditionalWait.Notify( lock );
139
140     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::StartAnimation: Start\n" );
141   }
142 }
143
144 void VectorRasterizeThread::StopAnimation()
145 {
146   ConditionalWait::ScopedLock lock( mConditionalWait );
147   if( mPlayState != DevelImageVisual::PlayState::STOPPED )
148   {
149     mPlayState = DevelImageVisual::PlayState::STOPPED;
150
151     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::StopAnimation: Stop\n" );
152   }
153 }
154
155 void VectorRasterizeThread::PauseAnimation()
156 {
157   ConditionalWait::ScopedLock lock( mConditionalWait );
158   if( mPlayState == DevelImageVisual::PlayState::PLAYING )
159   {
160     mPlayState = DevelImageVisual::PlayState::PAUSED;
161
162     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::PauseAnimation: Pause\n" );
163   }
164 }
165
166 void VectorRasterizeThread::RenderFrame()
167 {
168   ConditionalWait::ScopedLock lock( mConditionalWait );
169   mNeedRender = true;
170   mConditionalWait.Notify( lock );
171
172   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::RenderFrame: Render\n" );
173 }
174
175 void VectorRasterizeThread::SetResourceReadyCallback( EventThreadCallback* callback )
176 {
177   ConditionalWait::ScopedLock lock( mConditionalWait );
178   mResourceReadyTrigger = callback;
179 }
180
181 void VectorRasterizeThread::SetAnimationFinishedCallback( EventThreadCallback* callback )
182 {
183   ConditionalWait::ScopedLock lock( mConditionalWait );
184   mAnimationFinishedTrigger = callback;
185 }
186
187 void VectorRasterizeThread::SetLoopCount( int16_t count )
188 {
189   ConditionalWait::ScopedLock lock( mConditionalWait );
190
191   mLoopCount = count;
192
193   // Reset progress
194   mCurrentLoop = 0;
195   mCurrentFrame = mStartFrame;
196 }
197
198 void VectorRasterizeThread::SetPlayRange( Vector2 range )
199 {
200   ConditionalWait::ScopedLock lock( mConditionalWait );
201
202   mPlayRange = range;
203
204   if( mTotalFrame != 0 )
205   {
206     mStartFrame = static_cast< uint32_t >( mPlayRange.x * mTotalFrame + 0.5f );
207     mEndFrame = static_cast< uint32_t >( mPlayRange.y * mTotalFrame + 0.5f );
208   }
209 }
210
211 DevelImageVisual::PlayState VectorRasterizeThread::GetPlayState()
212 {
213   return mPlayState;
214 }
215
216 bool VectorRasterizeThread::IsThreadReady()
217 {
218   ConditionalWait::ScopedLock lock( mConditionalWait );
219
220   if( mPlayState != DevelImageVisual::PlayState::PLAYING && !mNeedRender && !mDestroyThread )
221   {
222     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::IsThreadReady: Wait\n" );
223
224     mConditionalWait.Wait( lock );
225   }
226
227   // Keep the thread alive if this thread is NOT to be destroyed
228   return !mDestroyThread;
229 }
230
231 bool VectorRasterizeThread::StartRender()
232 {
233   //TODO: check the return value
234   mVectorRenderer.StartRender();
235
236   mTotalFrame = mVectorRenderer.GetTotalFrameNumber();
237
238   mStartFrame = static_cast< uint32_t >( mPlayRange.x * mTotalFrame + 0.5f );
239   mEndFrame = static_cast< uint32_t >( mPlayRange.y * mTotalFrame + 0.5f );
240
241   mCurrentFrame = mStartFrame;
242
243   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::StartRender: Renderer is started [%d (%d, %d)]\n", mTotalFrame, mStartFrame, mEndFrame );
244
245   return true;
246 }
247
248 void VectorRasterizeThread::Rasterize()
249 {
250   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: [%d]\n", mCurrentFrame );
251
252   // Rasterize
253   mVectorRenderer.Render( mCurrentFrame );
254
255   if( mPlayState == DevelImageVisual::PlayState::PLAYING )
256   {
257     if( ++mCurrentFrame >= mEndFrame )
258     {
259       if( mLoopCount < 0 )
260       {
261         // repeat forever
262         mCurrentFrame = mStartFrame;
263       }
264       else
265       {
266         mCurrentLoop++;
267         if( mCurrentLoop >= mLoopCount )
268         {
269           // Animation is finished
270           mPlayState = DevelImageVisual::PlayState::STOPPED;
271
272           mAnimationFinishedTrigger->Trigger();
273
274           DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Animation is finished\n" );
275         }
276         else
277         {
278           mCurrentFrame = mStartFrame;
279         }
280       }
281     }
282   }
283
284   mNeedRender = false;
285
286   if( !mResourceReady )
287   {
288     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Resource ready trigger\n" );
289
290     mResourceReadyTrigger->Trigger();
291     mResourceReady = true;
292   }
293 }
294
295 } // namespace Internal
296
297 } // namespace Toolkit
298
299 } // namespace Dali