Fix SVACE issue
[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/rendering/renderer-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/image-visual-properties-devel.h>
30 #include <dali-toolkit/devel-api/visuals/animated-vector-image-visual-signals-devel.h>
31 #include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
32 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
33 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
34 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
35
36 namespace Dali
37 {
38
39 namespace Toolkit
40 {
41
42 namespace Internal
43 {
44
45 namespace
46 {
47
48 constexpr auto LOOP_FOREVER = -1;
49
50 const Dali::Vector4 FULL_TEXTURE_RECT( 0.f, 0.f, 1.f, 1.f );
51
52 // Flags for re-sending data to the rasterize thread
53 enum Flags
54 {
55   RESEND_PLAY_RANGE  = 1 << 0,
56   RESEND_LOOP_COUNT  = 1 << 1
57 };
58
59 #if defined(DEBUG_ENABLED)
60 Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_VECTOR_ANIMATION" );
61 #endif
62
63 } // unnamed namespace
64
65 AnimatedVectorImageVisualPtr AnimatedVectorImageVisual::New( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, const Property::Map& properties )
66 {
67   AnimatedVectorImageVisualPtr visual( new AnimatedVectorImageVisual( factoryCache, shaderFactory, imageUrl ) );
68   visual->SetProperties( properties );
69
70   return visual;
71 }
72
73 AnimatedVectorImageVisualPtr AnimatedVectorImageVisual::New( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl )
74 {
75   AnimatedVectorImageVisualPtr visual( new AnimatedVectorImageVisual( factoryCache, shaderFactory, imageUrl ) );
76
77   return visual;
78 }
79
80 AnimatedVectorImageVisual::AnimatedVectorImageVisual( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl )
81 : Visual::Base( factoryCache, Visual::FittingMode::FILL ),
82   mImageVisualShaderFactory( shaderFactory ),
83   mUrl( imageUrl ),
84   mVectorRasterizeThread( imageUrl.GetUrl() ),
85   mVisualSize(),
86   mPlacementActor(),
87   mLoopCount( LOOP_FOREVER ),
88   mStartFrame( 0 ),
89   mEndFrame( 0 ),
90   mResendFlag( 0 ),
91   mActionStatus( DevelAnimatedVectorImageVisual::Action::STOP )
92 {
93   // the rasterized image is with pre-multiplied alpha format
94   mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
95
96   mVectorRasterizeThread.SetResourceReadyCallback( new EventThreadCallback( MakeCallback( this, &AnimatedVectorImageVisual::OnResourceReady ) ) );
97   mVectorRasterizeThread.SetAnimationFinishedCallback( new EventThreadCallback( MakeCallback( this, &AnimatedVectorImageVisual::OnAnimationFinished ) ) );
98
99   mVectorRasterizeThread.Start();
100 }
101
102 AnimatedVectorImageVisual::~AnimatedVectorImageVisual()
103 {
104 }
105
106 void AnimatedVectorImageVisual::GetNaturalSize( Vector2& naturalSize )
107 {
108   if( mImpl->mRenderer ) // Check if we have a rendered image
109   {
110     auto textureSet = mImpl->mRenderer.GetTextures();
111     if( textureSet )
112     {
113       if( textureSet.GetTextureCount() > 0 )
114       {
115         auto texture = textureSet.GetTexture( 0 );
116         naturalSize.x = texture.GetWidth();
117         naturalSize.y = texture.GetHeight();
118         return;
119       }
120     }
121   }
122
123   uint32_t width, height;
124   mVectorRasterizeThread.GetDefaultSize( width, height );
125   naturalSize.x = width;
126   naturalSize.y = height;
127 }
128
129 void AnimatedVectorImageVisual::DoCreatePropertyMap( Property::Map& map ) const
130 {
131   map.Clear();
132   map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::DevelVisual::ANIMATED_VECTOR_IMAGE );
133   if( mUrl.IsValid() )
134   {
135     map.Insert( Toolkit::ImageVisual::Property::URL, mUrl.GetUrl() );
136   }
137   map.Insert( Toolkit::DevelImageVisual::Property::LOOP_COUNT, mLoopCount );
138
139   Property::Array playRange;
140   playRange.PushBack( mStartFrame );
141   playRange.PushBack( mEndFrame );
142   map.Insert( Toolkit::DevelImageVisual::Property::PLAY_RANGE, playRange );
143
144   map.Insert( Toolkit::DevelImageVisual::Property::PLAY_STATE, static_cast< int >( mVectorRasterizeThread.GetPlayState() ) );
145   map.Insert( Toolkit::DevelImageVisual::Property::CURRENT_FRAME_NUMBER, static_cast< int32_t >( mVectorRasterizeThread.GetCurrentFrameNumber() ) );
146   map.Insert( Toolkit::DevelImageVisual::Property::TOTAL_FRAME_NUMBER, static_cast< int32_t >( mVectorRasterizeThread.GetTotalFrameNumber() ) );
147 }
148
149 void AnimatedVectorImageVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
150 {
151   // Do nothing
152 }
153
154 void AnimatedVectorImageVisual::DoSetProperties( const Property::Map& propertyMap )
155 {
156   // url already passed in from constructor
157   for( Property::Map::SizeType iter = 0; iter < propertyMap.Count(); ++iter )
158   {
159     KeyValuePair keyValue = propertyMap.GetKeyValue( iter );
160     if( keyValue.first.type == Property::Key::INDEX )
161     {
162       DoSetProperty( keyValue.first.indexKey, keyValue.second );
163     }
164     else
165     {
166        if( keyValue.first == LOOP_COUNT_NAME )
167        {
168           DoSetProperty( Toolkit::DevelImageVisual::Property::LOOP_COUNT, keyValue.second );
169        }
170        else if( keyValue.first == PLAY_RANGE_NAME )
171        {
172           DoSetProperty( Toolkit::DevelImageVisual::Property::PLAY_RANGE, keyValue.second );
173        }
174     }
175   }
176 }
177
178 void AnimatedVectorImageVisual::DoSetProperty( Property::Index index, const Property::Value& value )
179 {
180   switch(index)
181   {
182     case Toolkit::DevelImageVisual::Property::LOOP_COUNT:
183     {
184       int32_t loopCount;
185       if( value.Get( loopCount ) )
186       {
187         mLoopCount = loopCount;
188         mResendFlag |= RESEND_LOOP_COUNT;
189       }
190       break;
191     }
192     case Toolkit::DevelImageVisual::Property::PLAY_RANGE:
193     {
194       Property::Array* array = value.GetArray();
195       if( array )
196       {
197         size_t count = array->Count();
198         if( count >= 2 )
199         {
200           int startFrame, endFrame;
201           int totalFrame = mVectorRasterizeThread.GetTotalFrameNumber();
202           array->GetElementAt( 0 ).Get( startFrame );
203           array->GetElementAt( 1 ).Get( endFrame );
204
205           if( startFrame >= 0 && startFrame < totalFrame && endFrame >= 0 && endFrame < totalFrame )
206           {
207             mStartFrame = startFrame;
208             mEndFrame = endFrame;
209             mResendFlag |= RESEND_PLAY_RANGE;
210           }
211           else
212           {
213             DALI_LOG_ERROR( "Invalid play range [%d, %d / %d]\n", startFrame, endFrame, totalFrame );
214           }
215         }
216       }
217       break;
218     }
219   }
220 }
221
222 void AnimatedVectorImageVisual::DoSetOnStage( Actor& actor )
223 {
224   Shader shader;
225
226   if( mImpl->mCustomShader )
227   {
228     shader = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? mImageVisualShaderFactory.GetVertexShaderSource() : mImpl->mCustomShader->mVertexShader,
229                           mImpl->mCustomShader->mFragmentShader.empty() ? mImageVisualShaderFactory.GetFragmentShaderSource() : mImpl->mCustomShader->mFragmentShader,
230                           mImpl->mCustomShader->mHints );
231
232     shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
233   }
234   else
235   {
236     shader = mImageVisualShaderFactory.GetShader( mFactoryCache, false, true );
237   }
238
239   Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
240
241   mImpl->mRenderer = Renderer::New( geometry, shader );
242
243   TextureSet textureSet = TextureSet::New();
244   mImpl->mRenderer.SetTextures( textureSet );
245
246   // Register transform properties
247   mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
248
249   // Defer the rasterisation task until we get given a size (by Size Negotiation algorithm)
250
251   // Hold the weak handle of the placement actor and delay the adding of renderer until the rasterization is finished.
252   mPlacementActor = actor;
253
254   mVectorRasterizeThread.SetRenderer( mImpl->mRenderer );
255 }
256
257 void AnimatedVectorImageVisual::DoSetOffStage( Actor& actor )
258 {
259   mVectorRasterizeThread.PauseAnimation();
260
261   mActionStatus = DevelAnimatedVectorImageVisual::Action::PAUSE;
262
263   if( mImpl->mRenderer )
264   {
265     mImpl->mRenderer.SetProperty( DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::IF_REQUIRED );
266
267     actor.RemoveRenderer( mImpl->mRenderer );
268     mImpl->mRenderer.Reset();
269   }
270
271   mPlacementActor.Reset();
272
273   // Reset the visual size to zero so that when adding the actor back to stage the rasterization is forced
274   mVisualSize = Vector2::ZERO;
275 }
276
277 void AnimatedVectorImageVisual::OnSetTransform()
278 {
279   Vector2 visualSize = mImpl->mTransform.GetVisualSize( mImpl->mControlSize );
280
281   if( IsOnStage() )
282   {
283     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "AnimatedVectorImageVisual::OnSetTransform: width = %f, height = %f\n", visualSize.width, visualSize.height );
284
285     if( visualSize != mVisualSize )
286     {
287       mVisualSize = visualSize;
288
289       uint32_t width = static_cast< uint32_t >( visualSize.width );
290       uint32_t height = static_cast< uint32_t >( visualSize.height );
291
292       mVectorRasterizeThread.SetSize( width, height );
293     }
294
295     SendAnimationData();
296
297     if( mActionStatus == DevelAnimatedVectorImageVisual::Action::PLAY )
298     {
299       mVectorRasterizeThread.PlayAnimation();
300
301       mImpl->mRenderer.SetProperty( DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::CONTINUOUSLY );
302     }
303     else
304     {
305       // Render one frame
306       mVectorRasterizeThread.RenderFrame();
307     }
308
309     if( mVectorRasterizeThread.IsResourceReady() )
310     {
311       Actor actor = mPlacementActor.GetHandle();
312       if( actor )
313       {
314         actor.AddRenderer( mImpl->mRenderer );
315         mPlacementActor.Reset();
316       }
317
318       ResourceReady( Toolkit::Visual::ResourceStatus::READY );
319     }
320   }
321 }
322
323 void AnimatedVectorImageVisual::OnDoAction( const Property::Index actionId, const Property::Value& attributes )
324 {
325   // Check if action is valid for this visual type and perform action if possible
326   switch( actionId )
327   {
328     case DevelAnimatedVectorImageVisual::Action::PLAY:
329     {
330       if( IsOnStage() && mVisualSize != Vector2::ZERO )
331       {
332         mVectorRasterizeThread.PlayAnimation();
333
334         mImpl->mRenderer.SetProperty( DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::CONTINUOUSLY );
335       }
336       mActionStatus = DevelAnimatedVectorImageVisual::Action::PLAY;
337       break;
338     }
339     case DevelAnimatedVectorImageVisual::Action::PAUSE:
340     {
341       mVectorRasterizeThread.PauseAnimation();
342
343       if( mImpl->mRenderer )
344       {
345         mImpl->mRenderer.SetProperty( DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::IF_REQUIRED );
346       }
347
348       mActionStatus = DevelAnimatedVectorImageVisual::Action::PAUSE;
349       break;
350     }
351     case DevelAnimatedVectorImageVisual::Action::STOP:
352     {
353       if( mVectorRasterizeThread.GetPlayState() != DevelImageVisual::PlayState::STOPPED )
354       {
355         mVectorRasterizeThread.StopAnimation();
356
357         OnAnimationFinished();
358       }
359       mActionStatus = DevelAnimatedVectorImageVisual::Action::STOP;
360       break;
361     }
362     case DevelAnimatedVectorImageVisual::Action::JUMP_TO:
363     {
364       int32_t frameNumber;
365       if( attributes.Get( frameNumber ) )
366       {
367         mVectorRasterizeThread.SetCurrentFrameNumber( frameNumber );
368
369         if( IsOnStage() && mVectorRasterizeThread.GetPlayState() != DevelImageVisual::PlayState::PLAYING )
370         {
371           mVectorRasterizeThread.RenderFrame();
372           Stage::GetCurrent().KeepRendering( 0.0f );    // Trigger rendering
373         }
374       }
375       break;
376     }
377     case DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY:
378     {
379       Property::Map* map = attributes.GetMap();
380       if( map )
381       {
382         DoSetProperties( *map );
383
384         SendAnimationData();
385       }
386       break;
387     }
388   }
389 }
390
391 void AnimatedVectorImageVisual::OnResourceReady()
392 {
393   // If weak handle is holding a placement actor, it is the time to add the renderer to actor.
394   Actor actor = mPlacementActor.GetHandle();
395   if( actor )
396   {
397     actor.AddRenderer( mImpl->mRenderer );
398     // reset the weak handle so that the renderer only get added to actor once
399     mPlacementActor.Reset();
400
401     ResourceReady( Toolkit::Visual::ResourceStatus::READY );
402   }
403 }
404
405 void AnimatedVectorImageVisual::OnAnimationFinished()
406 {
407   if( mImpl->mEventObserver )
408   {
409     mImpl->mEventObserver->NotifyVisualEvent( *this, DevelAnimatedVectorImageVisual::Signal::ANIMATION_FINISHED );
410   }
411
412   mActionStatus = DevelAnimatedVectorImageVisual::Action::STOP;
413
414   if( mImpl->mRenderer )
415   {
416     mImpl->mRenderer.SetProperty( DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::IF_REQUIRED );
417   }
418 }
419
420 void AnimatedVectorImageVisual::SendAnimationData()
421 {
422   if( mResendFlag )
423   {
424     bool isPlaying = false;
425     if( mVectorRasterizeThread.GetPlayState() == DevelImageVisual::PlayState::PLAYING )
426     {
427       mVectorRasterizeThread.PauseAnimation();
428       isPlaying = true;
429     }
430
431     if( mResendFlag & RESEND_LOOP_COUNT )
432     {
433       mVectorRasterizeThread.SetLoopCount( mLoopCount );
434     }
435
436     if( mResendFlag & RESEND_PLAY_RANGE )
437     {
438       mVectorRasterizeThread.SetPlayRange( mStartFrame, mEndFrame );
439     }
440
441     if( IsOnStage() )
442     {
443       if( isPlaying )
444       {
445         mVectorRasterizeThread.PlayAnimation();
446       }
447       else
448       {
449         mVectorRasterizeThread.RenderFrame();
450         Stage::GetCurrent().KeepRendering( 0.0f );
451       }
452     }
453
454     mResendFlag = 0;
455   }
456 }
457
458 } // namespace Internal
459
460 } // namespace Toolkit
461
462 } // namespace Dali