Select the renderer type based on the image url
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / renderers / gradient / gradient-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 "gradient-renderer.h"
20
21 // EXTERNAL INCLUDES
22 #include <typeinfo>
23 #include <dali/integration-api/debug.h>
24 #include <dali/public-api/common/dali-vector.h>
25 #include <dali/public-api/images/buffer-image.h>
26 #include <dali/public-api/object/property-array.h>
27
28 //INTERNAL INCLUDES
29 #include <dali-toolkit/internal/controls/renderers/renderer-factory-impl.h>
30 #include <dali-toolkit/internal/controls/renderers/renderer-factory-cache.h>
31 #include <dali-toolkit/internal/controls/renderers/control-renderer-data-impl.h>
32 #include <dali-toolkit/internal/controls/renderers/renderer-string-constants.h>
33 #include <dali-toolkit/internal/controls/renderers/gradient/linear-gradient.h>
34 #include <dali-toolkit/internal/controls/renderers/gradient/radial-gradient.h>
35
36 namespace Dali
37 {
38
39 namespace Toolkit
40 {
41
42 namespace Internal
43 {
44
45 namespace
46 {
47 // properties: linear gradient
48 const char * const START_POSITION_NAME("startPosition"); // Property::VECTOR2
49 const char * const END_POSITION_NAME("endPosition"); // Property::VECTOR2
50
51 // properties: radial gradient
52 const char * const CENTER_NAME("center"); // Property::VECTOR2
53 const char * const RADIUS_NAME("radius"); // Property::FLOAT
54
55 // properties: linear&radial gradient
56 const char * const STOP_OFFSET_NAME("stopOffset"); // Property::Array FLOAT
57 const char * const STOP_COLOR_NAME("stopColor"); // Property::Array VECTOR4
58 const char * const UNITS_NAME("units"); // Property::String  "userSpaceOnUse | objectBoundingBox"
59 const char * const SPREAD_METHOD_NAME("spreadMethod"); // Property::String  "pad | reflect | repeat"
60
61 // string values
62 const char * const UNIT_USER_SPACE("userSpace");
63 const char * const UNIT_BOUNDING_BOX("objectBoundingBox");
64 const char * const SPREAD_PAD("pad");
65 const char * const SPREAD_REFLECT("reflect");
66 const char * const SPREAD_REPEAT("repeat");
67
68 // uniform names
69 const char * const UNIFORM_ALIGNMENT_MATRIX_NAME( "uAlignmentMatrix" );
70
71 // default offset value
72 const unsigned int DEFAULT_OFFSET_MINIMUM = 0.0f;
73 const unsigned int DEFAULT_OFFSET_MAXIMUM = 1.0f;
74
75 RendererFactoryCache::ShaderType GetShaderType( GradientRenderer::Type type, Gradient::GradientUnits units)
76 {
77   if( type==GradientRenderer::LINEAR )
78   {
79    if( units == Gradient::USER_SPACE_ON_USE )
80    {
81      return RendererFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE;
82    }
83    return RendererFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX;
84   }
85   else if( units == Gradient::USER_SPACE_ON_USE )
86   {
87     return RendererFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE;
88   }
89
90   return RendererFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX;
91 }
92
93 const char* VERTEX_SHADER[] =
94 {
95 // vertex shader for gradient units as USER_SPACE_ON_USE
96 DALI_COMPOSE_SHADER(
97   attribute mediump vec2 aPosition;\n
98   uniform mediump mat4 uMvpMatrix;\n
99   uniform mediump vec3 uSize;\n
100   uniform mediump mat3 uAlignmentMatrix;\n
101   varying mediump vec2 vTexCoord;\n
102   \n
103   void main()\n
104   {\n
105     mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
106     vertexPosition.xyz *= uSize;\n
107     gl_Position = uMvpMatrix * vertexPosition;\n
108     \n
109     vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
110   }\n
111 ),
112
113 // vertex shader for gradient units as OBJECT_BOUNDING_BOX
114  DALI_COMPOSE_SHADER(
115   attribute mediump vec2 aPosition;\n
116   uniform mediump mat4 uMvpMatrix;\n
117   uniform mediump vec3 uSize;\n
118   uniform mediump mat3 uAlignmentMatrix;\n
119   varying mediump vec2 vTexCoord;\n
120   \n
121   void main()\n
122   {\n
123     mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
124     vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
125     \n
126     vertexPosition.xyz *= uSize;\n
127     gl_Position = uMvpMatrix * vertexPosition;\n
128   }\n
129 )
130 };
131
132 const char* FRAGMENT_SHADER[] =
133 {
134 // fragment shader for linear gradient
135 DALI_COMPOSE_SHADER(
136   uniform sampler2D sTexture;\n // sampler1D?
137   uniform lowp vec4 uColor;\n
138   varying mediump vec2 vTexCoord;\n
139   \n
140   void main()\n
141   {\n
142     gl_FragColor = texture2D( sTexture, vec2( vTexCoord.y, 0.5 ) ) * uColor;\n
143   }\n
144 ),
145
146 // fragment shader for radial gradient
147 DALI_COMPOSE_SHADER(
148   uniform sampler2D sTexture;\n // sampler1D?
149   uniform lowp vec4 uColor;\n
150   varying mediump vec2 vTexCoord;\n
151   \n
152   void main()\n
153   {\n
154     gl_FragColor = texture2D( sTexture, vec2( length(vTexCoord), 0.5 ) ) * uColor;\n
155   }\n
156 )
157 };
158
159 Dali::WrapMode::Type GetWrapMode( Gradient::SpreadMethod spread )
160 {
161   switch(spread)
162   {
163     case Gradient::REPEAT:
164     {
165       return Dali::WrapMode::REPEAT;
166     }
167     case Gradient::REFLECT:
168     {
169       return Dali::WrapMode::MIRRORED_REPEAT;
170     }
171     case Gradient::PAD:
172     default:
173     {
174       return Dali::WrapMode::CLAMP_TO_EDGE;
175     }
176   }
177 }
178
179 }
180
181
182 GradientRenderer::GradientRenderer( RendererFactoryCache& factoryCache )
183 : ControlRenderer( factoryCache ),
184   mGradientType( LINEAR )
185 {
186 }
187
188 GradientRenderer::~GradientRenderer()
189 {
190 }
191
192 void GradientRenderer::DoInitialize( Actor& actor, const Property::Map& propertyMap )
193 {
194   Gradient::GradientUnits gradientUnits = Gradient::OBJECT_BOUNDING_BOX;
195   Property::Value* unitsValue = propertyMap.Find( UNITS_NAME );
196   std::string units;
197   // The default unit is OBJECT_BOUNDING_BOX.
198   // Only need to set new units if 'user-space'
199   if( unitsValue && unitsValue->Get( units ) && units == UNIT_USER_SPACE )
200   {
201     gradientUnits = Gradient::USER_SPACE_ON_USE;
202   }
203
204   mGradientType = LINEAR;
205   if( propertyMap.Find( RADIUS_NAME ))
206   {
207     mGradientType = RADIAL;
208   }
209
210   if( NewGradient( mGradientType, propertyMap ) )
211   {
212     mGradient->SetGradientUnits( gradientUnits );
213     mGradientTransform = mGradient->GetAlignmentTransform();
214   }
215   else
216   {
217     DALI_LOG_ERROR( "Fail to provide valid properties to create a GradientRenderer object" );
218   }
219 }
220
221 void GradientRenderer::SetSize( const Vector2& size )
222 {
223   ControlRenderer::SetSize( size );
224 }
225
226 void GradientRenderer::SetClipRect( const Rect<int>& clipRect )
227 {
228   ControlRenderer::SetClipRect( clipRect );
229
230   //ToDo: renderer responds to the clipRect change
231 }
232
233 void GradientRenderer::SetOffset( const Vector2& offset )
234 {
235   //ToDo: renderer applies the offset
236 }
237
238 void GradientRenderer::DoSetOnStage( Actor& actor )
239 {
240   InitializeRenderer();
241 }
242
243 void GradientRenderer::DoCreatePropertyMap( Property::Map& map ) const
244 {
245   map.Clear();
246   map.Insert( RENDERER_TYPE, GRADIENT_RENDERER );
247
248   Gradient::GradientUnits units = mGradient->GetGradientUnits();
249   if( units == Gradient::USER_SPACE_ON_USE )
250   {
251     map.Insert( UNITS_NAME, UNIT_USER_SPACE );
252   }
253   else // if( units == Gradient::OBJECT_BOUNDING_BOX )
254   {
255     map.Insert( UNITS_NAME, UNIT_BOUNDING_BOX );
256   }
257
258   Gradient::SpreadMethod spread = mGradient->GetSpreadMethod();
259   if( spread == Gradient::PAD )
260   {
261     map.Insert( SPREAD_METHOD_NAME, SPREAD_PAD );
262   }
263   else if( spread == Gradient::REFLECT )
264   {
265     map.Insert( SPREAD_METHOD_NAME, SPREAD_REFLECT );
266   }
267   else // if( units == Gradient::REPEAT )
268   {
269     map.Insert( SPREAD_METHOD_NAME, SPREAD_REPEAT );
270   }
271
272   const Vector<Gradient::GradientStop>& stops( mGradient->GetStops() );
273   Property::Array offsets;
274   Property::Array colors;
275   for( unsigned int i=0; i<stops.Count(); i++ )
276   {
277     offsets.PushBack( stops[i].mOffset );
278     colors.PushBack( stops[i].mStopColor );
279   }
280
281   map.Insert( STOP_OFFSET_NAME, offsets );
282   map.Insert( STOP_COLOR_NAME, colors );
283
284   if( &typeid( *mGradient ) == &typeid(LinearGradient) )
285   {
286     LinearGradient* gradient = static_cast<LinearGradient*>( mGradient.Get() );
287     map.Insert( START_POSITION_NAME, gradient->GetStartPosition() );
288     map.Insert( END_POSITION_NAME, gradient->GetEndPosition() );
289   }
290   else // if( &typeid( *mGradient ) == &typeid(RadialGradient) )
291   {
292     RadialGradient* gradient = static_cast<RadialGradient*>( mGradient.Get() );
293     map.Insert( CENTER_NAME, gradient->GetCenter() );
294     map.Insert( RADIUS_NAME, gradient->GetRadius() );
295   }
296 }
297
298 void GradientRenderer::InitializeRenderer()
299 {
300   Geometry geometry = mFactoryCache.GetGeometry( RendererFactoryCache::QUAD_GEOMETRY );
301   if( !geometry )
302   {
303     geometry =  RendererFactoryCache::CreateQuadGeometry();
304     mFactoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, geometry );
305   }
306
307   Gradient::GradientUnits gradientUnits = mGradient->GetGradientUnits();
308   RendererFactoryCache::ShaderType shaderType = GetShaderType( mGradientType, gradientUnits );
309   Shader shader = mFactoryCache.GetShader( shaderType );
310   if( !shader )
311   {
312     shader = Shader::New( VERTEX_SHADER[gradientUnits], FRAGMENT_SHADER[ mGradientType ] );
313     mFactoryCache.SaveShader( shaderType, shader );
314   }
315
316   //Set up the texture set
317   TextureSet textureSet = TextureSet::New();
318   Dali::BufferImage lookupTexture = mGradient->GenerateLookupTexture();
319   textureSet.SetImage( 0u, lookupTexture );
320   Dali::WrapMode::Type wrap = GetWrapMode( mGradient->GetSpreadMethod() );
321   Sampler sampler = Sampler::New();
322   sampler.SetWrapMode(  wrap, wrap  );
323   textureSet.SetSampler( 0u, sampler );
324
325   mImpl->mRenderer = Renderer::New( geometry, shader );
326   mImpl->mRenderer.SetTextures( textureSet );
327
328   mImpl->mRenderer.RegisterProperty( UNIFORM_ALIGNMENT_MATRIX_NAME, mGradientTransform );
329 }
330
331 bool GradientRenderer::NewGradient(Type gradientType, const Property::Map& propertyMap)
332 {
333   if( gradientType==LINEAR )
334   {
335     Property::Value* startPositionValue = propertyMap.Find( START_POSITION_NAME );
336     Property::Value* endPositionValue = propertyMap.Find( END_POSITION_NAME );
337     Vector2 startPosition;
338     Vector2 endPosition;
339
340     if( startPositionValue && startPositionValue->Get(startPosition)
341      && endPositionValue && endPositionValue->Get( endPosition ) )
342     {
343       mGradient = new LinearGradient( startPosition, endPosition );
344     }
345     else
346     {
347       return false;
348     }
349   }
350   else // type==RADIAL
351   {
352     Property::Value* centerValue = propertyMap.Find( CENTER_NAME );
353     Property::Value* radiusValue = propertyMap.Find( RADIUS_NAME );
354     Vector2 center;
355     float radius;
356     if( centerValue && centerValue->Get(center)
357         && radiusValue && radiusValue->Get(radius) )
358     {
359       mGradient = new RadialGradient( center, radius );
360     }
361     else
362     {
363       return false;
364     }
365   }
366
367   unsigned int numValidStop = 0u;
368   Property::Value* stopOffsetValue = propertyMap.Find( STOP_OFFSET_NAME );
369   Property::Value* stopColorValue = propertyMap.Find( STOP_COLOR_NAME );
370   if( stopColorValue )
371   {
372     Vector<float> offsetArray;
373     Property::Array* colorArray = stopColorValue->GetArray();
374     if( colorArray )
375     {
376       GetStopOffsets( stopOffsetValue, offsetArray );
377       unsigned int numStop = offsetArray.Count() < colorArray->Count() ?
378                              offsetArray.Count() : colorArray->Count();
379       Vector4 color;
380       for( unsigned int i=0; i<numStop; i++ )
381       {
382         if( (colorArray->GetElementAt(i)).Get(color) )
383         {
384           mGradient->AddStop( offsetArray[i], color);
385           numValidStop++;
386         }
387       }
388     }
389   }
390
391   if( numValidStop < 1u ) // no valid stop
392   {
393     return false;
394   }
395
396   Property::Value* spread = propertyMap.Find( SPREAD_METHOD_NAME );
397   std::string stringValue ;
398   // The default spread method is PAD.
399   // Only need to set new spread if 'reflect' or 'repeat"
400   if( spread && spread->Get( stringValue ))
401   {
402     if( stringValue == SPREAD_REFLECT )
403     {
404       mGradient->SetSpreadMethod( Gradient::REFLECT );
405     }
406     else if( stringValue == SPREAD_REPEAT )
407     {
408       mGradient->SetSpreadMethod( Gradient::REPEAT );
409     }
410   }
411
412   return true;
413 }
414
415 void GradientRenderer::GetStopOffsets(const Property::Value* value, Vector<float>& stopOffsets)
416 {
417
418   if ( value ) // Only check valve type if a valid Property has been passed in
419   {
420     switch ( value->GetType() )
421     {
422       case Property::VECTOR2:
423       {
424         Vector2 offset2;
425         value->Get( offset2 );
426         stopOffsets.PushBack( offset2.x );
427         stopOffsets.PushBack( offset2.y );
428         break;
429       }
430       case Property::VECTOR3:
431       {
432         Vector3 offset3;
433         value->Get( offset3 );
434         stopOffsets.PushBack( offset3.x );
435         stopOffsets.PushBack( offset3.y );
436         stopOffsets.PushBack( offset3.z );
437         break;
438       }
439       case Property::VECTOR4:
440       {
441         Vector4 offset4;
442         value->Get( offset4 );
443         stopOffsets.PushBack( offset4.x );
444         stopOffsets.PushBack( offset4.y );
445         stopOffsets.PushBack( offset4.z );
446         stopOffsets.PushBack( offset4.w );
447         break;
448       }
449       case Property::ARRAY:
450       {
451         Property::Array* offsetArray = value->GetArray();
452         unsigned int numStop = offsetArray->Count();
453         float offset;
454         for( unsigned int i=0; i<numStop; i++ )
455         {
456           if( offsetArray->GetElementAt(i).Get(offset) )
457           {
458             stopOffsets.PushBack( offset );
459           }
460         }
461         break;
462       }
463       default:
464       {
465         DALI_LOG_WARNING("GetStopOffsets passed unsupported Property Map\n");
466         // Unsupported Type
467       }
468     }
469   }
470
471   if ( stopOffsets.Empty() )
472   {
473     // Set default offset if none set by Property system, need a minimum and maximum
474     stopOffsets.PushBack( DEFAULT_OFFSET_MINIMUM );
475     stopOffsets.PushBack( DEFAULT_OFFSET_MAXIMUM );
476   }
477 }
478
479 } // namespace Internal
480
481 } // namespace Toolkit
482
483 } // namespace Dali