a650f2e0871bb4e3a6f702ca90ffc41ff4b9df7c
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / animated-vector-image / animated-vector-image-visual.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/animated-vector-image-visual.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/common/stage.h>
23 #include <dali/devel-api/common/stage-devel.h>
24 #include <dali/integration-api/debug.h>
25
26 // INTERNAL INCLUDES
27 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
28 #include <dali-toolkit/public-api/visuals/visual-properties.h>
29 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
30 #include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
31 #include <dali-toolkit/devel-api/visuals/animated-vector-image-visual-signals-devel.h>
32 #include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
33 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
34 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
35 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
36 #include <dali-toolkit/internal/visuals/animated-vector-image/vector-rasterize-thread.h>
37
38 namespace Dali
39 {
40
41 namespace Toolkit
42 {
43
44 namespace Internal
45 {
46
47 namespace
48 {
49
50 const Dali::Vector4 FULL_TEXTURE_RECT( 0.f, 0.f, 1.f, 1.f );
51 constexpr auto LOOP_FOREVER = -1;
52
53 } // unnamed namespace
54
55 AnimatedVectorImageVisualPtr AnimatedVectorImageVisual::New( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, const Property::Map& properties )
56 {
57   AnimatedVectorImageVisualPtr visual( new AnimatedVectorImageVisual( factoryCache, shaderFactory, imageUrl ) );
58   visual->SetProperties( properties );
59
60   return visual;
61 }
62
63 AnimatedVectorImageVisualPtr AnimatedVectorImageVisual::New( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl )
64 {
65   AnimatedVectorImageVisualPtr visual( new AnimatedVectorImageVisual( factoryCache, shaderFactory, imageUrl ) );
66
67   return visual;
68 }
69
70 AnimatedVectorImageVisual::AnimatedVectorImageVisual( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl )
71 : Visual::Base( factoryCache ),
72   mImageVisualShaderFactory( shaderFactory ),
73   mUrl( imageUrl ),
74   mVisualSize(),
75   mPlayRange( 0.0f, 1.0f ),
76   mPlacementActor(),
77   mVectorRasterizeThread(),
78   mLoopCount( LOOP_FOREVER ),
79   mActionStatus( DevelAnimatedVectorImageVisual::Action::STOP ),
80   mNeedToSetRenderer( true )
81 {
82   // the rasterized image is with pre-multiplied alpha format
83   mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
84 }
85
86 AnimatedVectorImageVisual::~AnimatedVectorImageVisual()
87 {
88 }
89
90 void AnimatedVectorImageVisual::GetNaturalSize( Vector2& naturalSize )
91 {
92   naturalSize = mVisualSize;
93 }
94
95 void AnimatedVectorImageVisual::DoCreatePropertyMap( Property::Map& map ) const
96 {
97   map.Clear();
98   map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::DevelVisual::ANIMATED_VECTOR_IMAGE );
99   if( mUrl.IsValid() )
100   {
101     map.Insert( Toolkit::ImageVisual::Property::URL, mUrl.GetUrl() );
102   }
103   map.Insert( Toolkit::DevelImageVisual::Property::LOOP_COUNT, static_cast< int >( mLoopCount ) );
104   map.Insert( Toolkit::DevelImageVisual::Property::PLAY_RANGE, static_cast< Vector2 >( mPlayRange ) );
105
106   if( mVectorRasterizeThread )
107   {
108     map.Insert( Toolkit::DevelImageVisual::Property::PLAY_STATE, static_cast< int >( mVectorRasterizeThread->GetPlayState() ) );
109   }
110   else
111   {
112     map.Insert( Toolkit::DevelImageVisual::Property::PLAY_STATE, static_cast< int >( DevelImageVisual::PlayState::STOPPED ) );
113   }
114 }
115
116 void AnimatedVectorImageVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
117 {
118   // Do nothing
119 }
120
121 void AnimatedVectorImageVisual::DoSetProperties( const Property::Map& propertyMap )
122 {
123   // url already passed in from constructor
124   for( Property::Map::SizeType iter = 0; iter < propertyMap.Count(); ++iter )
125   {
126     KeyValuePair keyValue = propertyMap.GetKeyValue( iter );
127     if( keyValue.first.type == Property::Key::INDEX )
128     {
129       DoSetProperty( keyValue.first.indexKey, keyValue.second );
130     }
131     else
132     {
133        if( keyValue.first == LOOP_COUNT_NAME )
134        {
135           DoSetProperty( Toolkit::DevelImageVisual::Property::LOOP_COUNT, keyValue.second );
136        }
137        else if( keyValue.first == PLAY_RANGE_NAME )
138        {
139           DoSetProperty( Toolkit::DevelImageVisual::Property::PLAY_RANGE, keyValue.second );
140        }
141     }
142   }
143 }
144
145 void AnimatedVectorImageVisual::DoSetProperty( Property::Index index, const Property::Value& value )
146 {
147   switch(index)
148   {
149     case Toolkit::DevelImageVisual::Property::LOOP_COUNT:
150     {
151       int32_t loopCount;
152       if( value.Get( loopCount ) )
153       {
154         mLoopCount = loopCount;
155         if( mVectorRasterizeThread )
156         {
157           mVectorRasterizeThread->SetLoopCount( loopCount );
158         }
159       }
160       break;
161     }
162     case Toolkit::DevelImageVisual::Property::PLAY_RANGE:
163     {
164       Vector2 range;
165       if( value.Get( range ) )
166       {
167         // Make sure the range specified is between 0.0 and 1.0
168         if( range.x >= 0.0f && range.x <= 1.0f && range.y >= 0.0f && range.y <= 1.0f )
169         {
170           Vector2 orderedRange( range );
171           // If the range is not in order swap values
172           if( range.x > range.y )
173           {
174             orderedRange = Vector2( range.y, range.x );
175           }
176
177           mPlayRange = orderedRange;
178
179           if( mVectorRasterizeThread )
180           {
181             mVectorRasterizeThread->SetPlayRange( mPlayRange );
182           }
183         }
184       }
185       break;
186     }
187   }
188 }
189
190 void AnimatedVectorImageVisual::DoSetOnStage( Actor& actor )
191 {
192   Shader shader;
193
194   if( mImpl->mCustomShader )
195   {
196     shader = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? mImageVisualShaderFactory.GetVertexShaderSource() : mImpl->mCustomShader->mVertexShader,
197                           mImpl->mCustomShader->mFragmentShader.empty() ? mImageVisualShaderFactory.GetFragmentShaderSource() : mImpl->mCustomShader->mFragmentShader,
198                           mImpl->mCustomShader->mHints );
199
200     shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
201   }
202   else
203   {
204     shader = mImageVisualShaderFactory.GetShader( mFactoryCache, false, true );
205   }
206
207   Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
208
209   mNeedToSetRenderer = true;
210
211   mImpl->mRenderer = Renderer::New( geometry, shader );
212
213   TextureSet textureSet = TextureSet::New();
214   mImpl->mRenderer.SetTextures( textureSet );
215
216   // Register transform properties
217   mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
218
219   // Defer the rasterisation task until we get given a size (by Size Negotiation algorithm)
220
221   // Hold the weak handle of the placement actor and delay the adding of renderer until the rasterization is finished.
222   mPlacementActor = actor;
223
224   // This visual needs it's size set before it can be rasterized hence set ResourceReady once on stage
225   ResourceReady( Toolkit::Visual::ResourceStatus::READY );
226 }
227
228 void AnimatedVectorImageVisual::DoSetOffStage( Actor& actor )
229 {
230   if( mVectorRasterizeThread )
231   {
232     mVectorRasterizeThread->PauseAnimation();
233     DevelStage::SetRenderingBehavior( Stage::GetCurrent(), DevelStage::Rendering::IF_REQUIRED );
234     mActionStatus = DevelAnimatedVectorImageVisual::Action::PAUSE;
235   }
236
237   if( mImpl->mRenderer )
238   {
239     actor.RemoveRenderer( mImpl->mRenderer );
240     mImpl->mRenderer.Reset();
241   }
242
243   mPlacementActor.Reset();
244
245   // Reset the visual size to zero so that when adding the actor back to stage the rasterization is forced
246   mVisualSize = Vector2::ZERO;
247 }
248
249 void AnimatedVectorImageVisual::OnSetTransform()
250 {
251   Vector2 visualSize = mImpl->mTransform.GetVisualSize( mImpl->mControlSize );
252
253   if( IsOnStage() )
254   {
255     if( visualSize != mVisualSize )
256     {
257       mVisualSize = visualSize;
258
259       if( !mVectorRasterizeThread )
260       {
261         uint32_t width = static_cast< uint32_t >( visualSize.width );
262         uint32_t height = static_cast< uint32_t >( visualSize.height );
263
264         mVectorRasterizeThread = std::unique_ptr< VectorRasterizeThread >( new VectorRasterizeThread( mUrl.GetUrl() ) );
265
266         mVectorRasterizeThread->SetRenderer( mImpl->mRenderer );
267         mVectorRasterizeThread->SetSize( width, height );
268         mVectorRasterizeThread->SetResourceReadyCallback( new EventThreadCallback( MakeCallback( this, &AnimatedVectorImageVisual::OnResourceReady ) ) );
269         mVectorRasterizeThread->SetAnimationFinishedCallback( new EventThreadCallback( MakeCallback( this, &AnimatedVectorImageVisual::OnAnimationFinished ) ) );
270         mVectorRasterizeThread->SetLoopCount( mLoopCount );
271         mVectorRasterizeThread->SetPlayRange( mPlayRange );
272
273         mVectorRasterizeThread->Start();
274       }
275       else
276       {
277         uint32_t width = static_cast< uint32_t >( visualSize.width );
278         uint32_t height = static_cast< uint32_t >( visualSize.height );
279
280         mVectorRasterizeThread->SetRenderer( mImpl->mRenderer );
281         mVectorRasterizeThread->SetSize( width, height );
282       }
283
284       mNeedToSetRenderer = false;
285
286       if( mActionStatus == DevelAnimatedVectorImageVisual::Action::PLAY )
287       {
288         mVectorRasterizeThread->StartAnimation();
289         DevelStage::SetRenderingBehavior( Stage::GetCurrent(), DevelStage::Rendering::CONTINUOUSLY );
290       }
291       else
292       {
293         // Render one frame
294         mVectorRasterizeThread->RenderFrame();
295       }
296     }
297   }
298 }
299
300 void AnimatedVectorImageVisual::OnDoAction( const Property::Index actionId, const Property::Value& attributes )
301 {
302   // Check if action is valid for this visual type and perform action if possible
303   switch( actionId )
304   {
305     case DevelAnimatedVectorImageVisual::Action::PLAY:
306     {
307       if( IsOnStage())
308       {
309         // When renderer has changed, do not StartAnimation before SetRenderer(newOne)
310         if( mVectorRasterizeThread && !mNeedToSetRenderer )
311         {
312           mVectorRasterizeThread->StartAnimation();
313           DevelStage::SetRenderingBehavior( Stage::GetCurrent(), DevelStage::Rendering::CONTINUOUSLY );   //TODO: Should manage this globally
314         }
315       }
316       mActionStatus = DevelAnimatedVectorImageVisual::Action::PLAY;
317       break;
318     }
319     case DevelAnimatedVectorImageVisual::Action::PAUSE:
320     {
321       if( mVectorRasterizeThread )
322       {
323         mVectorRasterizeThread->PauseAnimation();
324         DevelStage::SetRenderingBehavior( Stage::GetCurrent(), DevelStage::Rendering::IF_REQUIRED );
325       }
326       mActionStatus = DevelAnimatedVectorImageVisual::Action::PAUSE;
327       break;
328     }
329     case DevelAnimatedVectorImageVisual::Action::STOP:
330     {
331       if( mVectorRasterizeThread )
332       {
333         bool emitSignal = false;
334         if( mVectorRasterizeThread->GetPlayState() != DevelImageVisual::PlayState::STOPPED )
335         {
336           emitSignal = true;
337         }
338
339         mVectorRasterizeThread->StopAnimation();
340         DevelStage::SetRenderingBehavior( Stage::GetCurrent(), DevelStage::Rendering::IF_REQUIRED );
341
342         if( emitSignal )
343         {
344           OnAnimationFinished();
345         }
346       }
347       mActionStatus = DevelAnimatedVectorImageVisual::Action::STOP;
348       break;
349     }
350   }
351 }
352
353 void AnimatedVectorImageVisual::OnResourceReady()
354 {
355   // If weak handle is holding a placement actor, it is the time to add the renderer to actor.
356   Actor actor = mPlacementActor.GetHandle();
357   if( actor )
358   {
359     actor.AddRenderer( mImpl->mRenderer );
360     // reset the weak handle so that the renderer only get added to actor once
361     mPlacementActor.Reset();
362
363     Stage::GetCurrent().KeepRendering( 0.0f );
364   }
365 }
366
367 void AnimatedVectorImageVisual::OnAnimationFinished()
368 {
369   if( mImpl->mEventObserver )
370   {
371     mImpl->mEventObserver->NotifyVisualEvent( *this, DevelAnimatedVectorImageVisual::Signal::ANIMATION_FINISHED );
372   }
373 }
374
375 } // namespace Internal
376
377 } // namespace Toolkit
378
379 } // namespace Dali