[dali_1.2.29] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / animated-image / animated-image-visual.cpp
1 /*
2  * Copyright (c) 2016 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 "animated-image-visual.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/adaptor-framework/gif-loading.h>
23
24 // INTERNAL INCLUDES
25 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
26 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
27 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
28 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
29 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
30 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
31 #include <dali-toolkit/internal/visuals/image/image-visual.h>
32 #include <dali-toolkit/devel-api/image-loader/image-atlas.h>
33
34 namespace Dali
35 {
36
37 namespace Toolkit
38 {
39
40 namespace Internal
41 {
42
43 namespace
44 {
45 // wrap modes
46 DALI_ENUM_TO_STRING_TABLE_BEGIN( WRAP_MODE )
47 DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, DEFAULT )
48 DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, CLAMP_TO_EDGE )
49 DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, REPEAT )
50 DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, MIRRORED_REPEAT )
51 DALI_ENUM_TO_STRING_TABLE_END( WRAP_MODE )
52
53 const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
54
55 }
56
57 AnimatedImageVisualPtr AnimatedImageVisual::New( VisualFactoryCache& factoryCache, const std::string& imageUrl, const Property::Map& properties )
58 {
59   AnimatedImageVisual* visual = new AnimatedImageVisual( factoryCache );
60   visual->mImageUrl = imageUrl;
61   visual->SetProperties( properties );
62
63   return visual;
64 }
65
66 AnimatedImageVisualPtr AnimatedImageVisual::New( VisualFactoryCache& factoryCache, const std::string& imageUrl )
67 {
68   AnimatedImageVisual* visual = new AnimatedImageVisual( factoryCache );
69   visual->mImageUrl = imageUrl;
70
71   return visual;
72 }
73
74 AnimatedImageVisual::AnimatedImageVisual( VisualFactoryCache& factoryCache )
75 : Visual::Base( factoryCache ),
76   mFrameDelayTimer(),
77   mPixelArea( FULL_TEXTURE_RECT ),
78   mImageUrl(),
79   mImageSize(),
80   mCurrentFrameIndex( 0 ),
81   mWrapModeU( WrapMode::DEFAULT ),
82   mWrapModeV( WrapMode::DEFAULT )
83 {}
84
85 AnimatedImageVisual::~AnimatedImageVisual()
86 {
87 }
88
89 void AnimatedImageVisual::GetNaturalSize( Vector2& naturalSize )
90 {
91   if( mImageSize.GetWidth() == 0 &&  mImageSize.GetHeight() == 0)
92   {
93     mImageSize = Dali::GetGifImageSize( mImageUrl );
94   }
95
96   naturalSize.width = mImageSize.GetWidth();
97   naturalSize.height = mImageSize.GetHeight();
98 }
99
100 void AnimatedImageVisual::DoCreatePropertyMap( Property::Map& map ) const
101 {
102   map.Clear();
103
104   map.Insert( Toolkit::DevelVisual::Property::TYPE, Toolkit::Visual::IMAGE );
105
106   if( !mImageUrl.empty() )
107   {
108     map.Insert( Toolkit::ImageVisual::Property::URL, mImageUrl );
109   }
110
111   map.Insert( Toolkit::ImageVisual::Property::PIXEL_AREA, mPixelArea );
112   map.Insert( Toolkit::ImageVisual::Property::WRAP_MODE_U, mWrapModeU );
113   map.Insert( Toolkit::ImageVisual::Property::WRAP_MODE_V, mWrapModeV );
114 }
115
116 void AnimatedImageVisual::DoSetProperties( const Property::Map& propertyMap )
117 {
118   // url already passed in from constructor
119
120   Property::Value* pixelAreaValue = propertyMap.Find( Toolkit::ImageVisual::Property::PIXEL_AREA, PIXEL_AREA_UNIFORM_NAME );
121   if( pixelAreaValue )
122   {
123     pixelAreaValue->Get( mPixelArea );
124   }
125
126   Property::Value* wrapModeValueU = propertyMap.Find( Toolkit::ImageVisual::Property::WRAP_MODE_U, IMAGE_WRAP_MODE_U );
127   if( wrapModeValueU )
128   {
129     int value;
130     Scripting::GetEnumerationProperty( *wrapModeValueU, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, value );
131     mWrapModeU = Dali::WrapMode::Type( value );
132   }
133
134   Property::Value* wrapModeValueV = propertyMap.Find( Toolkit::ImageVisual::Property::WRAP_MODE_V, IMAGE_WRAP_MODE_V );
135   if( wrapModeValueV )
136   {
137     int value;
138     Scripting::GetEnumerationProperty( *wrapModeValueV, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, value );
139     mWrapModeV = Dali::WrapMode::Type( value );
140   }
141 }
142
143 void AnimatedImageVisual::DoSetOnStage( Actor& actor )
144 {
145   Texture texture = PrepareAnimatedImage();
146   if( texture ) // if the image loading is successful
147   {
148     bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
149     Shader shader = ImageVisual::GetImageShader( mFactoryCache, true, defaultWrapMode );
150
151     Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
152
153     TextureSet textureSet = TextureSet::New();
154     textureSet.SetTexture( 0u, texture );
155
156     mImpl->mRenderer = Renderer::New( geometry, shader );
157     mImpl->mRenderer.SetTextures( textureSet );
158
159     // Register transform properties
160     mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
161
162     if( !defaultWrapMode ) // custom wrap mode
163     {
164       Vector2 wrapMode(mWrapModeU-WrapMode::CLAMP_TO_EDGE, mWrapModeV-WrapMode::CLAMP_TO_EDGE);
165       wrapMode.Clamp( Vector2::ZERO, Vector2( 2.f, 2.f ) );
166       mImpl->mRenderer.RegisterProperty( WRAP_MODE_UNIFORM_NAME, wrapMode );
167     }
168
169     if( mPixelArea != FULL_TEXTURE_RECT )
170     {
171       mImpl->mRenderer.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, mPixelArea );
172     }
173
174     mCurrentFrameIndex = 0;
175     mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mTextureRectContainer[mCurrentFrameIndex] );
176     if( mFrameDelayContainer.Count() > 1 )
177     {
178       mFrameDelayTimer = Timer::New( mFrameDelayContainer[0] );
179       mFrameDelayTimer.TickSignal().Connect( this, &AnimatedImageVisual::DisplayNextFrame );
180       mFrameDelayTimer.Start();
181     }
182
183     actor.AddRenderer( mImpl->mRenderer );
184   }
185 }
186
187 void AnimatedImageVisual::DoSetOffStage( Actor& actor )
188 {
189   if( !mImpl->mRenderer )
190   {
191     return;
192   }
193
194   if( mFrameDelayTimer )
195   {
196     mFrameDelayTimer.Stop();
197     mFrameDelayTimer.Reset();
198   }
199
200   mTextureRectContainer.Clear();
201   mFrameDelayContainer.Clear();
202
203   actor.RemoveRenderer( mImpl->mRenderer );
204   mImpl->mRenderer.Reset();
205 }
206
207 void AnimatedImageVisual::OnSetTransform()
208 {
209   if( mImpl->mRenderer )
210   {
211     mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
212   }
213 }
214
215 Texture AnimatedImageVisual::PrepareAnimatedImage()
216 {
217   // load from image file
218   std::vector<Dali::PixelData> pixelDataList;
219   if( Dali::LoadAnimatedGifFromFile( mImageUrl.c_str() , pixelDataList, mFrameDelayContainer ) )
220   {
221     mImageSize.SetWidth( pixelDataList[0].GetWidth() );
222     mImageSize.SetHeight( pixelDataList[0].GetHeight() );
223
224     return Toolkit::ImageAtlas::PackToAtlas( pixelDataList, mTextureRectContainer );
225   }
226
227   return Texture();
228 }
229
230 bool AnimatedImageVisual::DisplayNextFrame()
231 {
232   mCurrentFrameIndex = (mCurrentFrameIndex+1) % mFrameDelayContainer.Count();
233   mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mTextureRectContainer[mCurrentFrameIndex] );
234   if( mFrameDelayTimer.GetInterval() != mFrameDelayContainer[mCurrentFrameIndex] )
235   {
236     mFrameDelayTimer.SetInterval( mFrameDelayContainer[mCurrentFrameIndex] );
237   }
238
239   return true;
240 }
241
242
243 } // namespace Internal
244
245 } // namespace Toolkit
246
247 } // namespace Dali