Merge "Add BORDER_SIZE property to ImageVisual" into 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::DevelVisual::ANIMATED_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::DoCreateInstancePropertyMap( Property::Map& map ) const
117 {
118   // Do nothing
119 }
120
121 void AnimatedImageVisual::DoSetProperties( const Property::Map& propertyMap )
122 {
123   // url already passed in from constructor
124
125   Property::Value* pixelAreaValue = propertyMap.Find( Toolkit::ImageVisual::Property::PIXEL_AREA, PIXEL_AREA_UNIFORM_NAME );
126   if( pixelAreaValue )
127   {
128     pixelAreaValue->Get( mPixelArea );
129   }
130
131   Property::Value* wrapModeValueU = propertyMap.Find( Toolkit::ImageVisual::Property::WRAP_MODE_U, IMAGE_WRAP_MODE_U );
132   if( wrapModeValueU )
133   {
134     int value;
135     Scripting::GetEnumerationProperty( *wrapModeValueU, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, value );
136     mWrapModeU = Dali::WrapMode::Type( value );
137   }
138
139   Property::Value* wrapModeValueV = propertyMap.Find( Toolkit::ImageVisual::Property::WRAP_MODE_V, IMAGE_WRAP_MODE_V );
140   if( wrapModeValueV )
141   {
142     int value;
143     Scripting::GetEnumerationProperty( *wrapModeValueV, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, value );
144     mWrapModeV = Dali::WrapMode::Type( value );
145   }
146 }
147
148 void AnimatedImageVisual::DoSetOnStage( Actor& actor )
149 {
150   Texture texture = PrepareAnimatedImage();
151   if( texture ) // if the image loading is successful
152   {
153     bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
154     Shader shader = ImageVisual::GetImageShader( mFactoryCache, true, defaultWrapMode );
155
156     Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
157
158     TextureSet textureSet = TextureSet::New();
159     textureSet.SetTexture( 0u, texture );
160
161     mImpl->mRenderer = Renderer::New( geometry, shader );
162     mImpl->mRenderer.SetTextures( textureSet );
163
164     // Register transform properties
165     mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
166
167     if( !defaultWrapMode ) // custom wrap mode
168     {
169       Vector2 wrapMode(mWrapModeU-WrapMode::CLAMP_TO_EDGE, mWrapModeV-WrapMode::CLAMP_TO_EDGE);
170       wrapMode.Clamp( Vector2::ZERO, Vector2( 2.f, 2.f ) );
171       mImpl->mRenderer.RegisterProperty( WRAP_MODE_UNIFORM_NAME, wrapMode );
172     }
173
174     if( mPixelArea != FULL_TEXTURE_RECT )
175     {
176       mImpl->mRenderer.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, mPixelArea );
177     }
178
179     mCurrentFrameIndex = 0;
180     mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mTextureRectContainer[mCurrentFrameIndex] );
181     if( mFrameDelayContainer.Count() > 1 )
182     {
183       mFrameDelayTimer = Timer::New( mFrameDelayContainer[0] );
184       mFrameDelayTimer.TickSignal().Connect( this, &AnimatedImageVisual::DisplayNextFrame );
185       mFrameDelayTimer.Start();
186     }
187
188     actor.AddRenderer( mImpl->mRenderer );
189   }
190 }
191
192 void AnimatedImageVisual::DoSetOffStage( Actor& actor )
193 {
194   if( !mImpl->mRenderer )
195   {
196     return;
197   }
198
199   if( mFrameDelayTimer )
200   {
201     mFrameDelayTimer.Stop();
202     mFrameDelayTimer.Reset();
203   }
204
205   mTextureRectContainer.Clear();
206   mFrameDelayContainer.Clear();
207
208   actor.RemoveRenderer( mImpl->mRenderer );
209   mImpl->mRenderer.Reset();
210 }
211
212 void AnimatedImageVisual::OnSetTransform()
213 {
214   if( mImpl->mRenderer )
215   {
216     mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
217   }
218 }
219
220 Texture AnimatedImageVisual::PrepareAnimatedImage()
221 {
222   // load from image file
223   std::vector<Dali::PixelData> pixelDataList;
224   if( Dali::LoadAnimatedGifFromFile( mImageUrl.c_str() , pixelDataList, mFrameDelayContainer ) )
225   {
226     mImageSize.SetWidth( pixelDataList[0].GetWidth() );
227     mImageSize.SetHeight( pixelDataList[0].GetHeight() );
228
229     return Toolkit::ImageAtlas::PackToAtlas( pixelDataList, mTextureRectContainer );
230   }
231
232   return Texture();
233 }
234
235 bool AnimatedImageVisual::DisplayNextFrame()
236 {
237   mCurrentFrameIndex = (mCurrentFrameIndex+1) % mFrameDelayContainer.Count();
238   mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mTextureRectContainer[mCurrentFrameIndex] );
239   if( mFrameDelayTimer.GetInterval() != mFrameDelayContainer[mCurrentFrameIndex] )
240   {
241     mFrameDelayTimer.SetInterval( mFrameDelayContainer[mCurrentFrameIndex] );
242   }
243
244   return true;
245 }
246
247
248 } // namespace Internal
249
250 } // namespace Toolkit
251
252 } // namespace Dali