Add animated vector image visual
[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/internal/visuals/image-visual-shader-factory.h>
30 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
31 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
32 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
33 #include <dali-toolkit/internal/visuals/animated-vector-image/vector-image-rasterize-thread.h>
34
35 namespace Dali
36 {
37
38 namespace Toolkit
39 {
40
41 namespace Internal
42 {
43
44 namespace
45 {
46
47 const Dali::Vector4 FULL_TEXTURE_RECT( 0.f, 0.f, 1.f, 1.f );
48
49 } // unnamed namespace
50
51 AnimatedVectorImageVisualPtr AnimatedVectorImageVisual::New( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, const Property::Map& properties )
52 {
53   AnimatedVectorImageVisualPtr visual( new AnimatedVectorImageVisual( factoryCache, shaderFactory, imageUrl ) );
54   visual->SetProperties( properties );
55
56   return visual;
57 }
58
59 AnimatedVectorImageVisualPtr AnimatedVectorImageVisual::New( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl )
60 {
61   AnimatedVectorImageVisualPtr visual( new AnimatedVectorImageVisual( factoryCache, shaderFactory, imageUrl ) );
62
63   return visual;
64 }
65
66 AnimatedVectorImageVisual::AnimatedVectorImageVisual( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl )
67 : Visual::Base( factoryCache, Visual::FittingMode::FILL ),
68   mImageVisualShaderFactory( shaderFactory ),
69   mUrl( imageUrl ),
70   mVisualSize(),
71   mPlacementActor(),
72   mVectorRasterizeThread(),
73   mActionStatus( DevelAnimatedVectorImageVisual::Action::STOP )
74 {
75   // the rasterized image is with pre-multiplied alpha format
76   mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
77 }
78
79 AnimatedVectorImageVisual::~AnimatedVectorImageVisual()
80 {
81 }
82
83 void AnimatedVectorImageVisual::GetNaturalSize( Vector2& naturalSize )
84 {
85   naturalSize = mVisualSize;
86 }
87
88 void AnimatedVectorImageVisual::DoCreatePropertyMap( Property::Map& map ) const
89 {
90   map.Clear();
91   map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::DevelVisual::ANIMATED_VECTOR_IMAGE );
92   if( mUrl.IsValid() )
93   {
94     map.Insert( Toolkit::ImageVisual::Property::URL, mUrl.GetUrl() );
95   }
96 }
97
98 void AnimatedVectorImageVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
99 {
100   // Do nothing
101 }
102
103 void AnimatedVectorImageVisual::DoSetProperties( const Property::Map& propertyMap )
104 {
105   // url already passed in from constructor
106   for( Property::Map::SizeType iter = 0; iter < propertyMap.Count(); ++iter )
107   {
108     KeyValuePair keyValue = propertyMap.GetKeyValue( iter );
109     if( keyValue.first.type == Property::Key::INDEX )
110     {
111       DoSetProperty( keyValue.first.indexKey, keyValue.second );
112     }
113   }
114 }
115
116 void AnimatedVectorImageVisual::DoSetProperty( Property::Index index, const Property::Value& value )
117 {
118 }
119
120 void AnimatedVectorImageVisual::DoSetOnStage( Actor& actor )
121 {
122   Shader shader;
123
124   if( mImpl->mCustomShader )
125   {
126     shader = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? mImageVisualShaderFactory.GetVertexShaderSource() : mImpl->mCustomShader->mVertexShader,
127                           mImpl->mCustomShader->mFragmentShader.empty() ? mImageVisualShaderFactory.GetFragmentShaderSource() : mImpl->mCustomShader->mFragmentShader,
128                           mImpl->mCustomShader->mHints );
129
130     shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
131   }
132   else
133   {
134     shader = mImageVisualShaderFactory.GetShader( mFactoryCache, false, true );
135   }
136
137   Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
138
139   mImpl->mRenderer = Renderer::New( geometry, shader );
140
141   TextureSet textureSet = TextureSet::New();
142   mImpl->mRenderer.SetTextures( textureSet );
143
144   // Register transform properties
145   mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
146
147   // Defer the rasterisation task until we get given a size (by Size Negotiation algorithm)
148
149   // Hold the weak handle of the placement actor and delay the adding of renderer until the rasterization is finished.
150   mPlacementActor = actor;
151
152   // This visual needs it's size set before it can be rasterized hence set ResourceReady once on stage
153   ResourceReady( Toolkit::Visual::ResourceStatus::READY );
154 }
155
156 void AnimatedVectorImageVisual::DoSetOffStage( Actor& actor )
157 {
158   if( mVectorRasterizeThread )
159   {
160     mVectorRasterizeThread->PauseAnimation();
161     DevelStage::SetRenderingBehavior( Stage::GetCurrent(), DevelStage::Rendering::IF_REQUIRED );
162     mActionStatus = DevelAnimatedVectorImageVisual::Action::PAUSE;
163   }
164
165   if( mImpl->mRenderer )
166   {
167     actor.RemoveRenderer( mImpl->mRenderer );
168     mImpl->mRenderer.Reset();
169   }
170
171   mPlacementActor.Reset();
172
173   // Reset the visual size to zero so that when adding the actor back to stage the rasterization is forced
174   mVisualSize = Vector2::ZERO;
175 }
176
177 void AnimatedVectorImageVisual::OnSetTransform()
178 {
179   Vector2 visualSize = mImpl->mTransform.GetVisualSize( mImpl->mControlSize );
180
181   if( IsOnStage() )
182   {
183     if( visualSize != mVisualSize )
184     {
185       mVisualSize = visualSize;
186
187       if( !mVectorRasterizeThread )
188       {
189         uint32_t width = static_cast< uint32_t >( visualSize.width );
190         uint32_t height = static_cast< uint32_t >( visualSize.height );
191
192         mVectorRasterizeThread = std::unique_ptr< VectorRasterizeThread >( new VectorRasterizeThread( mUrl.GetUrl(), mImpl->mRenderer, width, height ) );
193
194         mVectorRasterizeThread->SetResourceReadyCallback( new EventThreadCallback( MakeCallback( this, &AnimatedVectorImageVisual::OnResourceReady ) ) );
195         mVectorRasterizeThread->Start();
196
197         if( mActionStatus == DevelAnimatedVectorImageVisual::Action::PLAY )
198         {
199           mVectorRasterizeThread->StartAnimation();
200           DevelStage::SetRenderingBehavior( Stage::GetCurrent(), DevelStage::Rendering::CONTINUOUSLY );
201         }
202         else
203         {
204           // Render one frame
205           mVectorRasterizeThread->RenderFrame();
206         }
207       }
208       else
209       {
210         // TODO: change size
211       }
212     }
213   }
214 }
215
216 void AnimatedVectorImageVisual::OnDoAction( const Property::Index actionId, const Property::Value& attributes )
217 {
218   if( actionId == mActionStatus )
219   {
220     return;
221   }
222
223   // Check if action is valid for this visual type and perform action if possible
224   switch( actionId )
225   {
226     case DevelAnimatedVectorImageVisual::Action::PLAY:
227     {
228       if( IsOnStage())
229       {
230         if( mVectorRasterizeThread )
231         {
232           mVectorRasterizeThread->StartAnimation();
233           DevelStage::SetRenderingBehavior( Stage::GetCurrent(), DevelStage::Rendering::CONTINUOUSLY );   //TODO: Should manage this globally
234         }
235       }
236       mActionStatus = DevelAnimatedVectorImageVisual::Action::PLAY;
237       break;
238     }
239     case DevelAnimatedVectorImageVisual::Action::PAUSE:
240     {
241       if( mVectorRasterizeThread )
242       {
243         mVectorRasterizeThread->PauseAnimation();
244         DevelStage::SetRenderingBehavior( Stage::GetCurrent(), DevelStage::Rendering::IF_REQUIRED );
245       }
246       mActionStatus = DevelAnimatedVectorImageVisual::Action::PAUSE;
247       break;
248     }
249     case DevelAnimatedVectorImageVisual::Action::RESUME:
250     {
251       if( mVectorRasterizeThread )
252       {
253         mVectorRasterizeThread->ResumeAnimation();
254         DevelStage::SetRenderingBehavior( Stage::GetCurrent(), DevelStage::Rendering::CONTINUOUSLY );
255       }
256       mActionStatus = DevelAnimatedVectorImageVisual::Action::RESUME;
257       break;
258     }
259     case DevelAnimatedVectorImageVisual::Action::STOP:
260     {
261       if( mVectorRasterizeThread )
262       {
263         mVectorRasterizeThread->StopAnimation();
264         DevelStage::SetRenderingBehavior( Stage::GetCurrent(), DevelStage::Rendering::IF_REQUIRED );
265       }
266       mActionStatus = DevelAnimatedVectorImageVisual::Action::STOP;
267       break;
268     }
269   }
270 }
271
272 void AnimatedVectorImageVisual::OnResourceReady()
273 {
274   // If weak handle is holding a placement actor, it is the time to add the renderer to actor.
275   Actor actor = mPlacementActor.GetHandle();
276   if( actor )
277   {
278     actor.AddRenderer( mImpl->mRenderer );
279     // reset the weak handle so that the renderer only get added to actor once
280     mPlacementActor.Reset();
281
282     Stage::GetCurrent().KeepRendering( 0.0f );
283   }
284 }
285
286 } // namespace Internal
287
288 } // namespace Toolkit
289
290 } // namespace Dali