Updated Gradient renderer to use SetTexture
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / renderers / gradient / gradient-renderer.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 "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   mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
187 }
188
189 GradientRenderer::~GradientRenderer()
190 {
191 }
192
193 void GradientRenderer::DoInitialize( Actor& actor, const Property::Map& propertyMap )
194 {
195   Gradient::GradientUnits gradientUnits = Gradient::OBJECT_BOUNDING_BOX;
196   Property::Value* unitsValue = propertyMap.Find( UNITS_NAME );
197   std::string units;
198   // The default unit is OBJECT_BOUNDING_BOX.
199   // Only need to set new units if 'user-space'
200   if( unitsValue && unitsValue->Get( units ) && units == UNIT_USER_SPACE )
201   {
202     gradientUnits = Gradient::USER_SPACE_ON_USE;
203   }
204
205   mGradientType = LINEAR;
206   if( propertyMap.Find( RADIUS_NAME ))
207   {
208     mGradientType = RADIAL;
209   }
210
211   if( NewGradient( mGradientType, propertyMap ) )
212   {
213     mGradient->SetGradientUnits( gradientUnits );
214     mGradientTransform = mGradient->GetAlignmentTransform();
215   }
216   else
217   {
218     DALI_LOG_ERROR( "Fail to provide valid properties to create a GradientRenderer object" );
219   }
220 }
221
222 void GradientRenderer::SetSize( const Vector2& size )
223 {
224   ControlRenderer::SetSize( size );
225 }
226
227 void GradientRenderer::SetClipRect( const Rect<int>& clipRect )
228 {
229   ControlRenderer::SetClipRect( clipRect );
230
231   //ToDo: renderer responds to the clipRect change
232 }
233
234 void GradientRenderer::SetOffset( const Vector2& offset )
235 {
236   //ToDo: renderer applies the offset
237 }
238
239 void GradientRenderer::DoSetOnStage( Actor& actor )
240 {
241   InitializeRenderer();
242 }
243
244 void GradientRenderer::DoCreatePropertyMap( Property::Map& map ) const
245 {
246   map.Clear();
247   map.Insert( RENDERER_TYPE, GRADIENT_RENDERER );
248
249   Gradient::GradientUnits units = mGradient->GetGradientUnits();
250   if( units == Gradient::USER_SPACE_ON_USE )
251   {
252     map.Insert( UNITS_NAME, UNIT_USER_SPACE );
253   }
254   else // if( units == Gradient::OBJECT_BOUNDING_BOX )
255   {
256     map.Insert( UNITS_NAME, UNIT_BOUNDING_BOX );
257   }
258
259   Gradient::SpreadMethod spread = mGradient->GetSpreadMethod();
260   if( spread == Gradient::PAD )
261   {
262     map.Insert( SPREAD_METHOD_NAME, SPREAD_PAD );
263   }
264   else if( spread == Gradient::REFLECT )
265   {
266     map.Insert( SPREAD_METHOD_NAME, SPREAD_REFLECT );
267   }
268   else // if( units == Gradient::REPEAT )
269   {
270     map.Insert( SPREAD_METHOD_NAME, SPREAD_REPEAT );
271   }
272
273   const Vector<Gradient::GradientStop>& stops( mGradient->GetStops() );
274   Property::Array offsets;
275   Property::Array colors;
276   for( unsigned int i=0; i<stops.Count(); i++ )
277   {
278     offsets.PushBack( stops[i].mOffset );
279     if( EqualsZero(stops[i].mStopColor.a) )
280     {
281       colors.PushBack( Vector4::ZERO );
282     }
283     else
284     {
285       colors.PushBack( Vector4( stops[i].mStopColor.r / stops[i].mStopColor.a,
286                                 stops[i].mStopColor.g / stops[i].mStopColor.a,
287                                 stops[i].mStopColor.b / stops[i].mStopColor.a,
288                                 stops[i].mStopColor.a));
289     }
290   }
291
292   map.Insert( STOP_OFFSET_NAME, offsets );
293   map.Insert( STOP_COLOR_NAME, colors );
294
295   if( &typeid( *mGradient ) == &typeid(LinearGradient) )
296   {
297     LinearGradient* gradient = static_cast<LinearGradient*>( mGradient.Get() );
298     map.Insert( START_POSITION_NAME, gradient->GetStartPosition() );
299     map.Insert( END_POSITION_NAME, gradient->GetEndPosition() );
300   }
301   else // if( &typeid( *mGradient ) == &typeid(RadialGradient) )
302   {
303     RadialGradient* gradient = static_cast<RadialGradient*>( mGradient.Get() );
304     map.Insert( CENTER_NAME, gradient->GetCenter() );
305     map.Insert( RADIUS_NAME, gradient->GetRadius() );
306   }
307 }
308
309 void GradientRenderer::InitializeRenderer()
310 {
311   Geometry geometry = mFactoryCache.GetGeometry( RendererFactoryCache::QUAD_GEOMETRY );
312   if( !geometry )
313   {
314     geometry =  Geometry::QUAD();
315     mFactoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, geometry );
316   }
317
318   Gradient::GradientUnits gradientUnits = mGradient->GetGradientUnits();
319   RendererFactoryCache::ShaderType shaderType = GetShaderType( mGradientType, gradientUnits );
320   Shader shader = mFactoryCache.GetShader( shaderType );
321   if( !shader )
322   {
323     shader = Shader::New( VERTEX_SHADER[gradientUnits], FRAGMENT_SHADER[ mGradientType ] );
324     mFactoryCache.SaveShader( shaderType, shader );
325   }
326
327   //Set up the texture set
328   TextureSet textureSet = TextureSet::New();
329   Dali::Texture lookupTexture = mGradient->GenerateLookupTexture();
330   textureSet.SetTexture( 0u, lookupTexture );
331   Dali::WrapMode::Type wrap = GetWrapMode( mGradient->GetSpreadMethod() );
332   Sampler sampler = Sampler::New();
333   sampler.SetWrapMode(  wrap, wrap  );
334   textureSet.SetSampler( 0u, sampler );
335
336   mImpl->mRenderer = Renderer::New( geometry, shader );
337   mImpl->mRenderer.SetTextures( textureSet );
338
339   mImpl->mRenderer.RegisterProperty( UNIFORM_ALIGNMENT_MATRIX_NAME, mGradientTransform );
340 }
341
342 bool GradientRenderer::NewGradient(Type gradientType, const Property::Map& propertyMap)
343 {
344   if( gradientType==LINEAR )
345   {
346     Property::Value* startPositionValue = propertyMap.Find( START_POSITION_NAME );
347     Property::Value* endPositionValue = propertyMap.Find( END_POSITION_NAME );
348     Vector2 startPosition;
349     Vector2 endPosition;
350
351     if( startPositionValue && startPositionValue->Get(startPosition)
352      && endPositionValue && endPositionValue->Get( endPosition ) )
353     {
354       mGradient = new LinearGradient( startPosition, endPosition );
355     }
356     else
357     {
358       return false;
359     }
360   }
361   else // type==RADIAL
362   {
363     Property::Value* centerValue = propertyMap.Find( CENTER_NAME );
364     Property::Value* radiusValue = propertyMap.Find( RADIUS_NAME );
365     Vector2 center;
366     float radius;
367     if( centerValue && centerValue->Get(center)
368         && radiusValue && radiusValue->Get(radius) )
369     {
370       mGradient = new RadialGradient( center, radius );
371     }
372     else
373     {
374       return false;
375     }
376   }
377
378   unsigned int numValidStop = 0u;
379   Property::Value* stopOffsetValue = propertyMap.Find( STOP_OFFSET_NAME );
380   Property::Value* stopColorValue = propertyMap.Find( STOP_COLOR_NAME );
381   if( stopColorValue )
382   {
383     Vector<float> offsetArray;
384     Property::Array* colorArray = stopColorValue->GetArray();
385     if( colorArray )
386     {
387       GetStopOffsets( stopOffsetValue, offsetArray );
388       unsigned int numStop = offsetArray.Count() < colorArray->Count() ?
389                              offsetArray.Count() : colorArray->Count();
390       Vector4 color;
391       for( unsigned int i=0; i<numStop; i++ )
392       {
393         if( (colorArray->GetElementAt(i)).Get(color) )
394         {
395           mGradient->AddStop( offsetArray[i], Vector4(color.r*color.a, color.g*color.a, color.b*color.a, color.a));
396           numValidStop++;
397         }
398       }
399     }
400   }
401
402   if( numValidStop < 1u ) // no valid stop
403   {
404     return false;
405   }
406
407   Property::Value* spread = propertyMap.Find( SPREAD_METHOD_NAME );
408   std::string stringValue ;
409   // The default spread method is PAD.
410   // Only need to set new spread if 'reflect' or 'repeat"
411   if( spread && spread->Get( stringValue ))
412   {
413     if( stringValue == SPREAD_REFLECT )
414     {
415       mGradient->SetSpreadMethod( Gradient::REFLECT );
416     }
417     else if( stringValue == SPREAD_REPEAT )
418     {
419       mGradient->SetSpreadMethod( Gradient::REPEAT );
420     }
421   }
422
423   return true;
424 }
425
426 void GradientRenderer::GetStopOffsets(const Property::Value* value, Vector<float>& stopOffsets)
427 {
428
429   if ( value ) // Only check valve type if a valid Property has been passed in
430   {
431     switch ( value->GetType() )
432     {
433       case Property::VECTOR2:
434       {
435         Vector2 offset2;
436         value->Get( offset2 );
437         stopOffsets.PushBack( offset2.x );
438         stopOffsets.PushBack( offset2.y );
439         break;
440       }
441       case Property::VECTOR3:
442       {
443         Vector3 offset3;
444         value->Get( offset3 );
445         stopOffsets.PushBack( offset3.x );
446         stopOffsets.PushBack( offset3.y );
447         stopOffsets.PushBack( offset3.z );
448         break;
449       }
450       case Property::VECTOR4:
451       {
452         Vector4 offset4;
453         value->Get( offset4 );
454         stopOffsets.PushBack( offset4.x );
455         stopOffsets.PushBack( offset4.y );
456         stopOffsets.PushBack( offset4.z );
457         stopOffsets.PushBack( offset4.w );
458         break;
459       }
460       case Property::ARRAY:
461       {
462         Property::Array* offsetArray = value->GetArray();
463         if( offsetArray )
464         {
465           unsigned int numStop = offsetArray->Count();
466           float offset;
467           for( unsigned int i=0; i<numStop; i++ )
468           {
469             if( offsetArray->GetElementAt(i).Get(offset) )
470             {
471               stopOffsets.PushBack( offset );
472             }
473           }
474         }
475         break;
476       }
477       default:
478       {
479         DALI_LOG_WARNING("GetStopOffsets passed unsupported Property Map\n");
480         // Unsupported Type
481       }
482     }
483   }
484
485   if ( stopOffsets.Empty() )
486   {
487     // Set default offset if none set by Property system, need a minimum and maximum
488     stopOffsets.PushBack( DEFAULT_OFFSET_MINIMUM );
489     stopOffsets.PushBack( DEFAULT_OFFSET_MAXIMUM );
490   }
491 }
492
493 } // namespace Internal
494
495 } // namespace Toolkit
496
497 } // namespace Dali