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