[4.0] Add animated vector image visual
[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, Renderer renderer, uint32_t width, uint32_t height )
48 : mUrl( url ),
49   mVectorRenderer(),
50   mConditionalWait(),
51   mMutex(),
52   mResourceReadyTrigger( NULL ),
53   mPlayRange( 0.0f, 1.0f ),
54   mCurrentFrame( 0 ),
55   mTotalFrame( 0 ),
56   mStartFrame( 0 ),
57   mEndFrame( 0 ),
58   mWidth( width ),
59   mHeight( height ),
60   mLoopCount( LOOP_FOREVER ),
61   mCurrentLoop( 0 ),
62   mNeedRender( false ),
63   mPlaying( false ),
64   mPaused( false ),
65   mDestroyThread( false ),
66   mResourceReady( false ),
67   mLogFactory( Dali::Adaptor::Get().GetLogFactory() )
68 {
69   mVectorRenderer = VectorAnimationRenderer::New( mUrl, renderer, width, height );
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 }
90
91 void VectorRasterizeThread::Run()
92 {
93   mLogFactory.InstallLogFunction();
94
95   //TODO: check the return value
96   StartRender();
97
98   while( IsThreadReady() )
99   {
100     Rasterize();
101   }
102 }
103
104 void VectorRasterizeThread::SetSize( uint32_t width, uint32_t height )
105 {
106   ConditionalWait::ScopedLock lock( mConditionalWait );
107   mVectorRenderer.SetSize( width, height );
108
109   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetSize: width = %d, height = %d\n", width, height );
110 }
111
112 void VectorRasterizeThread::StartAnimation()
113 {
114   ConditionalWait::ScopedLock lock( mConditionalWait );
115   if( !mPlaying )
116   {
117     mPlaying = true;
118     mPaused = false;
119     mConditionalWait.Notify( lock );
120
121     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::StartAnimation: Start\n" );
122   }
123 }
124
125 void VectorRasterizeThread::StopAnimation()
126 {
127   ConditionalWait::ScopedLock lock( mConditionalWait );
128   if( mPlaying )
129   {
130     mPlaying = false;
131     mPaused = false;
132
133     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::StopAnimation: Stop\n" );
134   }
135 }
136
137 void VectorRasterizeThread::PauseAnimation()
138 {
139   ConditionalWait::ScopedLock lock( mConditionalWait );
140   if( mPlaying && !mPaused )
141   {
142     mPaused = true;
143
144     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::PauseAnimation: Pause\n" );
145   }
146 }
147
148 void VectorRasterizeThread::ResumeAnimation()
149 {
150   ConditionalWait::ScopedLock lock( mConditionalWait );
151   if( mPlaying && mPaused )
152   {
153     mPaused = false;
154     mConditionalWait.Notify( lock );
155
156     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::ResumeAnimation: Resume\n" );
157   }
158 }
159
160 void VectorRasterizeThread::RenderFrame()
161 {
162   ConditionalWait::ScopedLock lock( mConditionalWait );
163   mNeedRender = true;
164   mConditionalWait.Notify( lock );
165
166   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::RenderFrame: Render\n" );
167 }
168
169 void VectorRasterizeThread::SetResourceReadyCallback( EventThreadCallback* callback )
170 {
171   ConditionalWait::ScopedLock lock( mConditionalWait );
172   mResourceReadyTrigger = callback;
173 }
174
175 void VectorRasterizeThread::SetLoopCount( int16_t count )
176 {
177   ConditionalWait::ScopedLock lock( mConditionalWait );
178
179   mLoopCount = count;
180
181   // Reset progress
182   mCurrentLoop = 0;
183   mCurrentFrame = mStartFrame;
184 }
185
186 void VectorRasterizeThread::SetPlayRange( Vector2 range )
187 {
188   ConditionalWait::ScopedLock lock( mConditionalWait );
189
190   mPlayRange = range;
191
192   if( mTotalFrame != 0 )
193   {
194     mStartFrame = static_cast< uint32_t >( mPlayRange.x * mTotalFrame + 0.5f );
195     mEndFrame = static_cast< uint32_t >( mPlayRange.y * mTotalFrame + 0.5f );
196   }
197 }
198
199 bool VectorRasterizeThread::IsThreadReady()
200 {
201   ConditionalWait::ScopedLock lock( mConditionalWait );
202
203   if( ( !mPlaying || mPaused ) && !mNeedRender && !mDestroyThread )
204   {
205     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::IsThreadReady: Wait\n" );
206
207     if( !mPlaying )
208     {
209       mCurrentFrame = mStartFrame;
210       mCurrentLoop = 0;
211     }
212
213     mConditionalWait.Wait( lock );
214   }
215
216   // Keep the thread alive if this thread is NOT to be destroyed
217   return !mDestroyThread;
218 }
219
220 bool VectorRasterizeThread::StartRender()
221 {
222   //TODO: check the return value
223   mVectorRenderer.StartRender();
224
225   mTotalFrame = mVectorRenderer.GetTotalFrameNumber();
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   mCurrentFrame = mStartFrame;
231
232   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::StartRender: Renderer is started [%d (%d, %d)]\n", mTotalFrame, mStartFrame, mEndFrame );
233
234   return true;
235 }
236
237 void VectorRasterizeThread::Rasterize()
238 {
239   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: [%d]\n", mCurrentFrame );
240
241   // Rasterize
242   mVectorRenderer.Render( mCurrentFrame );
243
244   if( mPlaying && !mPaused )
245   {
246     if( ++mCurrentFrame >= mEndFrame )
247     {
248       if( mLoopCount < 0 )
249       {
250         // repeat forever
251         mCurrentFrame = mStartFrame;
252       }
253       else
254       {
255         mCurrentLoop++;
256         if( mCurrentLoop >= mLoopCount )
257         {
258           // Animation is finished
259           mPlaying = false;
260         }
261         else
262         {
263           mCurrentFrame = mStartFrame;
264         }
265       }
266     }
267   }
268
269   mNeedRender = false;
270
271   if( !mResourceReady )
272   {
273     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Resource ready trigger\n" );
274
275     mResourceReadyTrigger->Trigger();
276     mResourceReady = true;
277   }
278 }
279
280 } // namespace Internal
281
282 } // namespace Toolkit
283
284 } // namespace Dali