Changed ImageView to utilise ImageRenderer.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / renderers / image / image-renderer.cpp
1 /*
2  * Copyright (c) 2015 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 "image-renderer.h"
20
21 #include <dali-toolkit/internal/controls/renderers/renderer-factory-impl.h>
22 #include <dali-toolkit/internal/controls/renderers/renderer-factory-cache.h>
23 #include <dali-toolkit/internal/controls/renderers/control-renderer-impl.h>
24 #include <dali-toolkit/internal/controls/renderers/control-renderer-data-impl.h>
25 #include <dali/public-api/images/resource-image.h>
26
27 namespace Dali
28 {
29
30 namespace Toolkit
31 {
32
33 namespace Internal
34 {
35
36 namespace
37 {
38
39 const char * const IMAGE_URL_NAME("image-url");
40 const char * const IMAGE_FITTING_MODE("image-fitting-mode");
41 const char * const IMAGE_SAMPLING_MODE("image-sampling-mode");
42 const char * const IMAGE_DESIRED_WIDTH("image-desired-width");
43 const char * const IMAGE_DESIRED_HEIGHT("image-desired-height");
44
45 std::string TEXTURE_UNIFORM_NAME = "sTexture";
46
47 #define MAKE_SHADER(A)#A
48
49 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
50   attribute mediump vec2 aPosition;\n
51   varying mediump vec2 vTexCoord;\n
52   uniform mediump mat4 uMvpMatrix;\n
53   uniform mediump vec3 uSize;\n
54   \n
55   void main()\n
56   {\n
57     mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
58     vertexPosition.xyz *= uSize;\n
59     vertexPosition = uMvpMatrix * vertexPosition;\n
60     \n
61     vTexCoord = aPosition + vec2(0.5);\n
62     gl_Position = vertexPosition;\n
63   }\n
64 );
65
66 const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
67   varying mediump vec2 vTexCoord;\n
68   uniform sampler2D sTexture;\n
69   uniform lowp vec4 uColor;\n
70   \n
71   void main()\n
72   {\n
73     gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n
74   }\n
75 );
76
77 } //unnamed namespace
78
79 ImageRenderer::ImageRenderer()
80 : ControlRenderer(),
81   mDesiredSize(),
82   mFittingMode( FittingMode::DEFAULT ),
83   mSamplingMode( SamplingMode::DEFAULT )
84 {
85 }
86
87 ImageRenderer::~ImageRenderer()
88 {
89 }
90
91 void ImageRenderer::Initialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
92 {
93   Initialize(factoryCache);
94
95   Property::Value* imageURLValue = propertyMap.Find( IMAGE_URL_NAME );
96   if( imageURLValue )
97   {
98     imageURLValue->Get( mImageUrl );
99
100     Property::Value* fittingValue = propertyMap.Find( IMAGE_FITTING_MODE );
101     if( fittingValue )
102     {
103       std::string fitting;
104       fittingValue->Get( fitting );
105
106       mFittingMode = FittingMode::DEFAULT;
107       if( fitting == "shrink-to-fit" )
108       {
109         mFittingMode = FittingMode::SHRINK_TO_FIT;
110       }
111       else if( fitting == "scale-to-fill" )
112       {
113         mFittingMode = FittingMode::SCALE_TO_FILL;
114       }
115       else if( fitting == "fit-width" )
116       {
117         mFittingMode = FittingMode::FIT_WIDTH;
118       }
119       else if( fitting == "fit-height" )
120       {
121         mFittingMode = FittingMode::FIT_HEIGHT;
122       }
123       else if( fitting == "default" )
124       {
125         mFittingMode = FittingMode::DEFAULT;
126       }
127       else
128       {
129         DALI_ASSERT_ALWAYS("Unknown fitting mode");
130       }
131     }
132
133     Property::Value* samplingValue = propertyMap.Find( IMAGE_SAMPLING_MODE );
134     if( samplingValue )
135     {
136       std::string sampling;
137       samplingValue->Get( sampling );
138
139       mSamplingMode = SamplingMode::DEFAULT;
140       if( sampling == "box" )
141       {
142         mSamplingMode = SamplingMode::BOX;
143       }
144       else if( sampling == "nearest" )
145       {
146         mSamplingMode = SamplingMode::NEAREST;
147       }
148       else if( sampling == "linear" )
149       {
150         mSamplingMode = SamplingMode::LINEAR;
151       }
152       else if( sampling == "box-then-nearest" )
153       {
154         mSamplingMode = SamplingMode::BOX_THEN_NEAREST;
155       }
156       else if( sampling == "box-then-linear" )
157       {
158         mSamplingMode = SamplingMode::BOX_THEN_LINEAR;
159       }
160       else if( sampling == "no-filter" )
161       {
162         mSamplingMode = SamplingMode::NO_FILTER;
163       }
164       else if( sampling == "dont-care" )
165       {
166         mSamplingMode = SamplingMode::DONT_CARE;
167       }
168       else if( sampling == "default" )
169       {
170         mSamplingMode = SamplingMode::DEFAULT;
171       }
172       else
173       {
174         DALI_ASSERT_ALWAYS("Unknown sampling mode");
175       }
176     }
177
178     int desiredWidth = 0;
179     Property::Value* desiredWidthValue = propertyMap.Find( IMAGE_DESIRED_WIDTH );
180     if( desiredWidthValue )
181     {
182       desiredWidthValue->Get( desiredWidth );
183     }
184
185     int desiredHeight = 0;
186     Property::Value* desiredHeightValue = propertyMap.Find( IMAGE_DESIRED_HEIGHT );
187     if( desiredHeightValue )
188     {
189       desiredHeightValue->Get( desiredHeight );
190     }
191
192     mDesiredSize = ImageDimensions( desiredWidth, desiredHeight );
193   }
194
195   mImage.Reset();
196 }
197
198 void ImageRenderer::SetSize( const Vector2& size )
199 {
200   ControlRenderer::SetSize( size );
201   // ToDo: renderer responds to the size change
202 }
203
204 void ImageRenderer::SetClipRect( const Rect<int>& clipRect )
205 {
206   ControlRenderer::SetClipRect( clipRect );
207   //ToDo: renderer responds to the clipRect change
208 }
209
210 void ImageRenderer::SetOffset( const Vector2& offset )
211 {
212   //ToDo: renderer applies the offset
213 }
214
215 void ImageRenderer::DoSetOnStage( Actor& actor )
216 {
217   if( !mImageUrl.empty() && !mImage )
218   {
219     mImage = Dali::ResourceImage::New( mImageUrl, mDesiredSize, mFittingMode, mSamplingMode );
220   }
221
222   ApplyImageToSampler();
223 }
224
225 void ImageRenderer::DoSetOffStage( Actor& actor )
226 {
227   //If we own the image then make sure we release it when we go off stage
228   if( !mImageUrl.empty() )
229   {
230     mImage.Reset();
231   }
232
233   ControlRenderer::SetOffStage( actor );
234 }
235
236 void ImageRenderer::Initialize( RendererFactoryCache& factoryCache )
237 {
238   mImpl->mGeometry = factoryCache.GetGeometry( RendererFactoryCache::QUAD_GEOMETRY );
239   if( !(mImpl->mGeometry) )
240   {
241     mImpl->mGeometry =  factoryCache.CreateQuadGeometry();
242     factoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, mImpl->mGeometry );
243   }
244
245   mImpl->mShader = factoryCache.GetShader( RendererFactoryCache::IMAGE_SHADER );
246   if( !mImpl->mShader )
247   {
248     mImpl->mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
249     factoryCache.SaveShader( RendererFactoryCache::IMAGE_SHADER, mImpl->mShader );
250   }
251
252   mDesiredSize = ImageDimensions();
253   mFittingMode = FittingMode::DEFAULT;
254   mSamplingMode = SamplingMode::DEFAULT;
255   mImageUrl.clear();
256 }
257
258 void ImageRenderer::SetImage( const std::string& imageUrl )
259 {
260   SetImage( imageUrl, 0, 0, Dali::FittingMode::DEFAULT, Dali::SamplingMode::DEFAULT );
261 }
262
263 void ImageRenderer::SetImage( const std::string& imageUrl, int desiredWidth, int desiredHeight, Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode )
264 {
265   if( mImageUrl != imageUrl )
266   {
267     mImageUrl = imageUrl;
268     mDesiredSize = ImageDimensions( desiredWidth, desiredHeight );
269     mFittingMode = fittingMode;
270     mSamplingMode = samplingMode;
271
272     if( !mImageUrl.empty() && mImpl->mIsOnStage )
273     {
274       mImage = Dali::ResourceImage::New( mImageUrl, mDesiredSize, mFittingMode, mSamplingMode );
275       ApplyImageToSampler();
276     }
277     else
278     {
279       mImage.Reset();
280     }
281   }
282 }
283
284 void ImageRenderer::SetImage( Image image )
285 {
286   if( mImage != image )
287   {
288     mImageUrl.clear();
289     mDesiredSize = ImageDimensions();
290     mFittingMode = FittingMode::DEFAULT;
291     mSamplingMode = SamplingMode::DEFAULT;
292     mImage = image;
293
294     if( mImage && mImpl->mIsOnStage )
295     {
296       ApplyImageToSampler();
297     }
298   }
299 }
300
301 Image ImageRenderer::GetImage() const
302 {
303   return mImage;
304 }
305
306 void ImageRenderer::ApplyImageToSampler()
307 {
308   if( mImage )
309   {
310     Material material = mImpl->mRenderer.GetMaterial();
311     if( material )
312     {
313       for( std::size_t i = 0; i < material.GetNumberOfSamplers(); ++i )
314       {
315         Sampler sampler = material.GetSamplerAt( i );
316         if( sampler.GetUniformName() == TEXTURE_UNIFORM_NAME )
317         {
318           sampler.SetImage( mImage );
319           return;
320         }
321       }
322
323       Sampler sampler = Sampler::New( mImage, TEXTURE_UNIFORM_NAME );
324       material.AddSampler( sampler );
325     }
326   }
327 }
328
329 } // namespace Internal
330
331 } // namespace Toolkit
332
333 } // namespace Dali