Add SetProperty and GetProperty to Visuals.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / image / batch-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 "batch-image-visual.h"
20
21 // EXTERNAL HEADER
22 #include <cstring> // for strncasecmp
23 #include <dali/public-api/images/resource-image.h>
24 #include <dali/public-api/images/native-image.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/devel-api/adaptor-framework/bitmap-loader.h>
27 #include <dali/public-api/images/pixel-data.h>
28 #include <dali/public-api/rendering/texture.h>
29 #include <dali/public-api/rendering/texture-set.h>
30 #include <dali/public-api/rendering/texture-set.h>
31
32 // INTERNAL HEADER
33 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
34 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
35 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
36 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
37 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
38 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
39 #include <dali-toolkit/internal/visuals/image-atlas-manager.h>
40
41 namespace Dali
42 {
43
44 namespace Toolkit
45 {
46
47 namespace Internal
48 {
49
50 namespace
51 {
52 const char HTTP_URL[] = "http://";
53 const char HTTPS_URL[] = "https://";
54
55 // Properties:
56 const char * const DESIRED_WIDTH( "desiredWidth" );
57 const char * const DESIRED_HEIGHT( "desiredHeight" );
58
59 const Vector4 FULL_TEXTURE_RECT( 0.f, 0.f, 1.f, 1.f );
60
61 // The shader used for batched rendering. It uses interleaved data for
62 // attributes. Limitation is that all batched renderers will share same set of uniforms.
63 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
64   attribute mediump vec2 aPosition;\n
65   attribute mediump vec2 aTexCoord;\n
66   uniform mediump mat4 uMvpMatrix;\n
67   varying mediump vec2 vTexCoord;\n
68   \n
69   void main()\n
70   {\n
71     vTexCoord = aTexCoord;\n
72     gl_Position = uMvpMatrix * vec4( aPosition, 0.0, 1.0 );\n
73   }\n
74 );
75
76 const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
77   varying mediump vec2 vTexCoord;\n
78   uniform sampler2D sTexture;\n
79   uniform lowp vec4 uColor;\n
80   uniform lowp float uAlphaBlending; // Set to 1.0 for conventional alpha blending; if pre-multiplied alpha blending, set to 0.0
81   \n
82   void main()\n
83   {\n
84     gl_FragColor = texture2D( sTexture, vTexCoord ) * vec4( uColor.rgb*max( uAlphaBlending, uColor.a ), uColor.a );\n
85   }\n
86 );
87
88 } //unnamed namespace
89
90 BatchImageVisual::BatchImageVisual( VisualFactoryCache& factoryCache )
91   : Visual::Base( factoryCache ),
92     mDesiredSize()
93 {
94 }
95
96 BatchImageVisual::~BatchImageVisual()
97 {
98 }
99
100 void BatchImageVisual::DoInitialize( Actor& actor, const Property::Map& propertyMap )
101 {
102   std::string oldImageUrl = mImageUrl;
103   Property::Value* imageURLValue = propertyMap.Find( Dali::Toolkit::ImageVisual::Property::URL, Dali::Toolkit::Internal::IMAGE_URL_NAME );
104
105   if( imageURLValue )
106   {
107     imageURLValue->Get( mImageUrl );
108
109     int desiredWidth = 0;
110     Property::Value* desiredWidthValue = propertyMap.Find( Dali::Toolkit::ImageVisual::Property::DESIRED_WIDTH, DESIRED_WIDTH );
111     if( desiredWidthValue )
112     {
113       desiredWidthValue->Get( desiredWidth );
114     }
115
116     int desiredHeight = 0;
117     Property::Value* desiredHeightValue = propertyMap.Find( Dali::Toolkit::ImageVisual::Property::DESIRED_HEIGHT, DESIRED_HEIGHT );
118     if( desiredHeightValue )
119     {
120       desiredHeightValue->Get( desiredHeight );
121     }
122
123     mDesiredSize = ImageDimensions( desiredWidth, desiredHeight );
124   }
125
126   // Remove old renderer if exit.
127   if( mImpl->mRenderer )
128   {
129     if( actor ) // Remove old renderer from actor.
130     {
131       actor.RemoveRenderer( mImpl->mRenderer );
132     }
133     if( !oldImageUrl.empty() ) // Clean old renderer from cache.
134     {
135       CleanCache( oldImageUrl );
136     }
137   }
138
139   // If actor is on stage, create new renderer and apply to actor.
140   if( actor && actor.OnStage() )
141   {
142     SetOnStage( actor );
143   }
144 }
145
146 void BatchImageVisual::SetSize( const Vector2& size )
147 {
148   Visual::Base::SetSize( size );
149 }
150
151 void BatchImageVisual::GetNaturalSize( Vector2& naturalSize ) const
152 {
153   if( mDesiredSize.GetWidth() > 0 && mDesiredSize.GetHeight() > 0 )
154   {
155     naturalSize.x = mDesiredSize.GetWidth();
156     naturalSize.y = mDesiredSize.GetHeight();
157     return;
158   }
159   else if( !mImageUrl.empty() )
160   {
161     ImageDimensions dimentions = ResourceImage::GetImageSize( mImageUrl );
162     naturalSize.x = dimentions.GetWidth();
163     naturalSize.y = dimentions.GetHeight();
164     return;
165   }
166
167   naturalSize = Vector2::ZERO;
168 }
169
170 void BatchImageVisual::InitializeRenderer( const std::string& imageUrl )
171 {
172   if( imageUrl.empty() )
173   {
174     return;
175   }
176
177   mImageUrl = imageUrl;
178   mImpl->mRenderer.Reset();
179   mAtlasRect = FULL_TEXTURE_RECT;
180
181   if( !mImpl->mCustomShader &&
182       ( strncasecmp( imageUrl.c_str(),HTTP_URL,  sizeof( HTTP_URL )  -1 ) != 0 ) && // Ignore remote images
183       ( strncasecmp( imageUrl.c_str(), HTTPS_URL, sizeof( HTTPS_URL ) -1 ) != 0 ) )
184   {
185     if( !mImpl->mRenderer )
186     {
187       TextureSet textureSet = mFactoryCache.GetAtlasManager()->Add(
188             mAtlasRect,
189             imageUrl,
190             mDesiredSize );
191
192       // If image doesn't fit the atlas, create new texture set with texture that
193       // is used as whole.
194       if( !textureSet )
195       {
196         BitmapLoader loader = BitmapLoader::New( imageUrl, mDesiredSize );
197         loader.Load();
198         Dali::PixelData pixelData = loader.GetPixelData();
199         Texture texture = Texture::New( TextureType::TEXTURE_2D,
200                                         pixelData.GetPixelFormat(),
201                                         pixelData.GetWidth(),
202                                         pixelData.GetHeight() );
203         texture.Upload( pixelData );
204         textureSet = TextureSet::New();
205         textureSet.SetTexture( 0, texture );
206         mAtlasRect = FULL_TEXTURE_RECT;
207       }
208
209       Geometry geometry = mFactoryCache.CreateBatchQuadGeometry( mAtlasRect );
210       Shader shader( GetBatchShader( mFactoryCache ) );
211       mImpl->mRenderer = Renderer::New( geometry, shader );
212       mImpl->mRenderer.SetTextures( textureSet );
213
214       // Turn batching on, to send message it must be on stage.
215       mImpl->mRenderer.SetProperty( Dali::Renderer::Property::BATCHING_ENABLED, true );
216     }
217     mImpl->mFlags |= Impl::IS_FROM_CACHE;
218   }
219 }
220
221 void BatchImageVisual::DoSetOnStage( Actor& actor )
222 {
223   if( !mImageUrl.empty() )
224   {
225     InitializeRenderer( mImageUrl );
226   }
227   // Turn batching on, to send message it must be on stage
228   mImpl->mRenderer.SetProperty( Dali::Renderer::Property::BATCHING_ENABLED, true );
229
230   actor.AddRenderer( mImpl->mRenderer );
231 }
232
233 void BatchImageVisual::DoSetOffStage( Actor& actor )
234 {
235   actor.RemoveRenderer( mImpl->mRenderer );
236
237   // If we own the image then make sure we release it when we go off stage
238   if( !mImageUrl.empty() )
239   {
240     CleanCache( mImageUrl );
241   }
242   else
243   {
244     mImpl->mRenderer.Reset();
245   }
246 }
247
248 void BatchImageVisual::DoCreatePropertyMap( Property::Map& map ) const
249 {
250   map.Clear();
251   map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE );
252
253   if( !mImageUrl.empty() )
254   {
255     map.Insert( Toolkit::ImageVisual::Property::URL, mImageUrl );
256     map.Insert( Toolkit::ImageVisual::Property::BATCHING_ENABLED, true );
257     map.Insert( Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth() );
258     map.Insert( Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight() );
259   }
260 }
261
262 void BatchImageVisual::DoSetProperty( Dali::Property::Index index, const Dali::Property::Value& propertyValue )
263 {
264   // TODO
265 }
266
267 Dali::Property::Value BatchImageVisual::DoGetProperty( Dali::Property::Index index )
268 {
269   // TODO
270   return Dali::Property::Value();
271 }
272
273 Shader BatchImageVisual::GetBatchShader( VisualFactoryCache& factoryCache )
274 {
275   Shader shader = factoryCache.GetShader( VisualFactoryCache::BATCH_IMAGE_SHADER );
276   if( !shader )
277   {
278     shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
279     factoryCache.SaveShader( VisualFactoryCache::BATCH_IMAGE_SHADER, shader );
280   }
281   return shader;
282 }
283
284 void BatchImageVisual::CleanCache(const std::string& url)
285 {
286   TextureSet textureSet = mImpl->mRenderer.GetTextures();
287   mImpl->mRenderer.Reset();
288   if( mFactoryCache.CleanRendererCache( url ) )
289   {
290     mFactoryCache.GetAtlasManager()->Remove( textureSet, mAtlasRect );
291   }
292 }
293
294
295 } // namespace Internal
296
297 } // namespace Toolkit
298
299 } // namespace Dali