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