Fix various SVACE errors
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / gradient / gradient-visual.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-visual.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 #include <dali/devel-api/scripting/enum-helper.h>
28 #include <dali/devel-api/scripting/scripting.h>
29
30 // INTERNAL INCLUDES
31 #include <dali-toolkit/public-api/visuals/gradient-visual-properties.h>
32 #include <dali-toolkit/devel-api/visual-factory/devel-visual-properties.h>
33 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
34 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
35 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
36 #include <dali-toolkit/internal/visuals/gradient/linear-gradient.h>
37 #include <dali-toolkit/internal/visuals/gradient/radial-gradient.h>
38 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
39
40 namespace Dali
41 {
42
43 namespace Toolkit
44 {
45
46 namespace Internal
47 {
48
49 namespace
50 {
51 // properties: linear gradient
52 const char * const START_POSITION_NAME("startPosition"); // Property::VECTOR2
53 const char * const END_POSITION_NAME("endPosition"); // Property::VECTOR2
54
55 // properties: radial gradient
56 const char * const CENTER_NAME("center"); // Property::VECTOR2
57 const char * const RADIUS_NAME("radius"); // Property::FLOAT
58
59 // properties: linear&radial gradient
60 const char * const STOP_OFFSET_NAME("stopOffset"); // Property::Array FLOAT
61 const char * const STOP_COLOR_NAME("stopColor"); // Property::Array VECTOR4
62 const char * const UNITS_NAME("units"); // Property::String  "userSpaceOnUse | objectBoundingBox"
63 const char * const SPREAD_METHOD_NAME("spreadMethod"); // Property::String  "pad | reflect | repeat"
64
65 DALI_ENUM_TO_STRING_TABLE_BEGIN( UNITS )
66 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::Units, OBJECT_BOUNDING_BOX )
67 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::Units, USER_SPACE )
68 DALI_ENUM_TO_STRING_TABLE_END( UNITS )
69
70 DALI_ENUM_TO_STRING_TABLE_BEGIN( SPREAD_METHOD )
71 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::SpreadMethod, PAD )
72 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::SpreadMethod, REFLECT )
73 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::SpreadMethod, REPEAT )
74 DALI_ENUM_TO_STRING_TABLE_END( SPREAD_METHOD )
75
76 // uniform names
77 const char * const UNIFORM_ALIGNMENT_MATRIX_NAME( "uAlignmentMatrix" );
78
79 // default offset value
80 const unsigned int DEFAULT_OFFSET_MINIMUM = 0.0f;
81 const unsigned int DEFAULT_OFFSET_MAXIMUM = 1.0f;
82
83 VisualFactoryCache::ShaderType GetShaderType( GradientVisual::Type type, Toolkit::GradientVisual::Units::Type units )
84 {
85   if( type == GradientVisual::LINEAR )
86   {
87    if( units == Toolkit::GradientVisual::Units::USER_SPACE )
88    {
89      return VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE;
90    }
91    return VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX;
92   }
93   else if( units == Toolkit::GradientVisual::Units::USER_SPACE )
94   {
95     return VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE;
96   }
97
98   return VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX;
99 }
100
101 const char* VERTEX_SHADER[] =
102 {
103 // vertex shader for gradient units as OBJECT_BOUNDING_BOX
104  DALI_COMPOSE_SHADER(
105   attribute mediump vec2 aPosition;\n
106   uniform mediump mat4 uMvpMatrix;\n
107   uniform mediump vec3 uSize;\n
108   uniform mediump mat3 uAlignmentMatrix;\n
109   varying mediump vec2 vTexCoord;\n
110   \n
111
112   //Visual size and offset
113   uniform mediump vec2 offset;\n
114   uniform mediump vec2 size;\n
115   uniform mediump vec4 offsetSizeMode;\n
116   uniform mediump vec2 origin;\n
117   uniform mediump vec2 anchorPoint;\n
118
119   vec4 ComputeVertexPosition()\n
120   {\n
121     vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );\n
122     vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
123     return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
124   }\n
125
126   void main()\n
127   {\n
128     mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
129     vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
130     \n
131     gl_Position = uMvpMatrix * ComputeVertexPosition();\n
132   }\n
133 ),
134
135 // vertex shader for gradient units as USER_SPACE
136 DALI_COMPOSE_SHADER(
137   attribute mediump vec2 aPosition;\n
138   uniform mediump mat4 uMvpMatrix;\n
139   uniform mediump vec3 uSize;\n
140   uniform mediump mat3 uAlignmentMatrix;\n
141   varying mediump vec2 vTexCoord;\n
142   \n
143
144   //Visual size and offset
145   uniform mediump vec2 offset;\n
146   uniform mediump vec2 size;\n
147   uniform mediump vec4 offsetSizeMode;\n
148   uniform mediump vec2 origin;\n
149   uniform mediump vec2 anchorPoint;\n
150
151   vec4 ComputeVertexPosition()\n
152   {\n
153     vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );\n
154     vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
155     return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
156   }\n
157
158   void main()\n
159   {\n
160     mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
161     vertexPosition.xyz *= uSize;\n
162     gl_Position = uMvpMatrix * ComputeVertexPosition();\n
163     \n
164     vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
165   }\n
166 )
167 };
168
169 const char* FRAGMENT_SHADER[] =
170 {
171 // fragment shader for linear gradient
172 DALI_COMPOSE_SHADER(
173   uniform sampler2D sTexture;\n // sampler1D?
174   uniform lowp vec4 uColor;\n
175   varying mediump vec2 vTexCoord;\n
176   \n
177   void main()\n
178   {\n
179     gl_FragColor = texture2D( sTexture, vec2( vTexCoord.y, 0.5 ) ) * uColor;\n
180   }\n
181 ),
182
183 // fragment shader for radial gradient
184 DALI_COMPOSE_SHADER(
185   uniform sampler2D sTexture;\n // sampler1D?
186   uniform lowp vec4 uColor;\n
187   varying mediump vec2 vTexCoord;\n
188   \n
189   void main()\n
190   {\n
191     gl_FragColor = texture2D( sTexture, vec2( length(vTexCoord), 0.5 ) ) * uColor;\n
192   }\n
193 )
194 };
195
196 Dali::WrapMode::Type GetWrapMode( Toolkit::GradientVisual::SpreadMethod::Type spread )
197 {
198   switch(spread)
199   {
200     case Toolkit::GradientVisual::SpreadMethod::REPEAT:
201     {
202       return Dali::WrapMode::REPEAT;
203     }
204     case Toolkit::GradientVisual::SpreadMethod::REFLECT:
205     {
206       return Dali::WrapMode::MIRRORED_REPEAT;
207     }
208     case Toolkit::GradientVisual::SpreadMethod::PAD:
209     default:
210     {
211       return Dali::WrapMode::CLAMP_TO_EDGE;
212     }
213   }
214 }
215
216 } // unnamed namespace
217
218 GradientVisualPtr GradientVisual::New( VisualFactoryCache& factoryCache )
219 {
220   return new GradientVisual( factoryCache );
221 }
222
223 GradientVisual::GradientVisual( VisualFactoryCache& factoryCache )
224 : Visual::Base( factoryCache ),
225   mGradientType( LINEAR ),
226   mIsOpaque( true )
227 {
228   mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
229 }
230
231 GradientVisual::~GradientVisual()
232 {
233 }
234
235 void GradientVisual::DoSetProperties( const Property::Map& propertyMap )
236 {
237   Toolkit::GradientVisual::Units::Type gradientUnits = Toolkit::GradientVisual::Units::OBJECT_BOUNDING_BOX;
238
239   Property::Value* unitsValue = propertyMap.Find( Toolkit::GradientVisual::Property::UNITS, UNITS_NAME );
240   if( unitsValue )
241   {
242     Scripting::GetEnumerationProperty( *unitsValue, UNITS_TABLE, UNITS_TABLE_COUNT, gradientUnits );
243   }
244
245   mGradientType = LINEAR;
246   if( propertyMap.Find( Toolkit::GradientVisual::Property::RADIUS, RADIUS_NAME ) )
247   {
248     mGradientType = RADIAL;
249   }
250
251   if( NewGradient( mGradientType, propertyMap ) )
252   {
253     mGradient->SetGradientUnits( gradientUnits );
254     mGradientTransform = mGradient->GetAlignmentTransform();
255   }
256   else
257   {
258     DALI_LOG_ERROR( "Fail to provide valid properties to create a GradientVisual object\n" );
259   }
260 }
261
262 void GradientVisual::OnSetTransform()
263 {
264   if( mImpl->mRenderer )
265   {
266     mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
267   }
268 }
269
270 void GradientVisual::SetSize( const Vector2& size )
271 {
272   Visual::Base::SetSize( size );
273 }
274
275 void GradientVisual::DoSetOnStage( Actor& actor )
276 {
277   InitializeRenderer();
278
279   actor.AddRenderer( mImpl->mRenderer );
280 }
281
282 void GradientVisual::DoCreatePropertyMap( Property::Map& map ) const
283 {
284   map.Clear();
285   map.Insert( Toolkit::VisualProperty::TYPE, Toolkit::Visual::GRADIENT );
286   map.Insert( Toolkit::GradientVisual::Property::UNITS, mGradient->GetGradientUnits() );
287   map.Insert( Toolkit::GradientVisual::Property::SPREAD_METHOD, mGradient->GetSpreadMethod() );
288
289   const Vector<Gradient::GradientStop>& stops( mGradient->GetStops() );
290   Property::Array offsets;
291   Property::Array colors;
292   for( unsigned int i=0; i<stops.Count(); i++ )
293   {
294     offsets.PushBack( stops[i].mOffset );
295     if( EqualsZero(stops[i].mStopColor.a) )
296     {
297       colors.PushBack( Vector4::ZERO );
298     }
299     else
300     {
301       colors.PushBack( Vector4( stops[i].mStopColor.r / stops[i].mStopColor.a,
302                                 stops[i].mStopColor.g / stops[i].mStopColor.a,
303                                 stops[i].mStopColor.b / stops[i].mStopColor.a,
304                                 stops[i].mStopColor.a));
305     }
306   }
307
308   map.Insert( Toolkit::GradientVisual::Property::STOP_OFFSET, offsets );
309   map.Insert( Toolkit::GradientVisual::Property::STOP_COLOR, colors );
310
311   if( &typeid( *mGradient ) == &typeid(LinearGradient) )
312   {
313     LinearGradient* gradient = static_cast<LinearGradient*>( mGradient.Get() );
314     map.Insert( Toolkit::GradientVisual::Property::START_POSITION, gradient->GetStartPosition() );
315     map.Insert( Toolkit::GradientVisual::Property::END_POSITION, gradient->GetEndPosition() );
316   }
317   else // if( &typeid( *mGradient ) == &typeid(RadialGradient) )
318   {
319     RadialGradient* gradient = static_cast<RadialGradient*>( mGradient.Get() );
320     map.Insert( Toolkit::GradientVisual::Property::CENTER, gradient->GetCenter() );
321     map.Insert( Toolkit::GradientVisual::Property::RADIUS, gradient->GetRadius() );
322   }
323 }
324
325 void GradientVisual::DoSetProperty( Dali::Property::Index index, const Dali::Property::Value& propertyValue )
326 {
327   // TODO
328 }
329
330 Dali::Property::Value GradientVisual::DoGetProperty( Dali::Property::Index index )
331 {
332   // TODO
333   return Dali::Property::Value();
334 }
335
336 void GradientVisual::InitializeRenderer()
337 {
338   Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
339   if( !geometry )
340   {
341     geometry =  VisualFactoryCache::CreateQuadGeometry();
342     mFactoryCache.SaveGeometry( VisualFactoryCache::QUAD_GEOMETRY, geometry );
343   }
344
345   Toolkit::GradientVisual::Units::Type gradientUnits = mGradient->GetGradientUnits();
346   VisualFactoryCache::ShaderType shaderType = GetShaderType( mGradientType, gradientUnits );
347   Shader shader = mFactoryCache.GetShader( shaderType );
348   if( !shader )
349   {
350     shader = Shader::New( VERTEX_SHADER[gradientUnits], FRAGMENT_SHADER[ mGradientType ] );
351     mFactoryCache.SaveShader( shaderType, shader );
352   }
353
354   //Set up the texture set
355   TextureSet textureSet = TextureSet::New();
356   Dali::Texture lookupTexture = mGradient->GenerateLookupTexture();
357   textureSet.SetTexture( 0u, lookupTexture );
358   Dali::WrapMode::Type wrap = GetWrapMode( mGradient->GetSpreadMethod() );
359   Sampler sampler = Sampler::New();
360   sampler.SetWrapMode(  wrap, wrap  );
361   textureSet.SetSampler( 0u, sampler );
362
363   mImpl->mRenderer = Renderer::New( geometry, shader );
364   mImpl->mRenderer.SetTextures( textureSet );
365
366   // If opaque then no need to have blending
367   if( mIsOpaque )
368   {
369     mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::OFF );
370   }
371
372   mImpl->mRenderer.RegisterProperty( UNIFORM_ALIGNMENT_MATRIX_NAME, mGradientTransform );
373
374   //Register transform properties
375   mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
376 }
377
378 bool GradientVisual::NewGradient(Type gradientType, const Property::Map& propertyMap)
379 {
380   if( gradientType == LINEAR )
381   {
382     Property::Value* startPositionValue = propertyMap.Find( Toolkit::GradientVisual::Property::START_POSITION, START_POSITION_NAME );
383     Property::Value* endPositionValue = propertyMap.Find( Toolkit::GradientVisual::Property::END_POSITION, END_POSITION_NAME );
384     Vector2 startPosition;
385     Vector2 endPosition;
386
387     if( startPositionValue && startPositionValue->Get(startPosition)
388      && endPositionValue && endPositionValue->Get( endPosition ) )
389     {
390       mGradient = new LinearGradient( startPosition, endPosition );
391     }
392     else
393     {
394       return false;
395     }
396   }
397   else // type==RADIAL
398   {
399     Property::Value* centerValue = propertyMap.Find( Toolkit::GradientVisual::Property::CENTER, CENTER_NAME );
400     Property::Value* radiusValue = propertyMap.Find( Toolkit::GradientVisual::Property::RADIUS, RADIUS_NAME );
401     Vector2 center;
402     float radius;
403     if( centerValue && centerValue->Get(center)
404         && radiusValue && radiusValue->Get(radius) )
405     {
406       mGradient = new RadialGradient( center, radius );
407     }
408     else
409     {
410       return false;
411     }
412   }
413
414   unsigned int numValidStop = 0u;
415   Property::Value* stopOffsetValue = propertyMap.Find( Toolkit::GradientVisual::Property::STOP_OFFSET, STOP_OFFSET_NAME );
416   Property::Value* stopColorValue = propertyMap.Find( Toolkit::GradientVisual::Property::STOP_COLOR, STOP_COLOR_NAME );
417   if( stopColorValue )
418   {
419     Vector<float> offsetArray;
420     Property::Array* colorArray = stopColorValue->GetArray();
421     if( colorArray )
422     {
423       GetStopOffsets( stopOffsetValue, offsetArray );
424       unsigned int numStop = offsetArray.Count() < colorArray->Count() ?
425                              offsetArray.Count() : colorArray->Count();
426       Vector4 color;
427       for( unsigned int i=0; i<numStop; i++ )
428       {
429         if( (colorArray->GetElementAt(i)).Get(color) )
430         {
431           mGradient->AddStop( offsetArray[i], Vector4(color.r*color.a, color.g*color.a, color.b*color.a, color.a));
432           numValidStop++;
433           if( ! Equals( color.a, 1.0f, Math::MACHINE_EPSILON_1 ) )
434           {
435             mIsOpaque = false;
436           }
437         }
438       }
439     }
440   }
441
442   if( numValidStop < 1u ) // no valid stop
443   {
444     return false;
445   }
446
447   Property::Value* spread = propertyMap.Find( Toolkit::GradientVisual::Property::SPREAD_METHOD, SPREAD_METHOD_NAME );
448   // The default spread method is PAD. Only need to set new spread if it's anything else.
449   if( spread )
450   {
451     Toolkit::GradientVisual::SpreadMethod::Type spreadMethod = Toolkit::GradientVisual::SpreadMethod::PAD;
452     if( Scripting::GetEnumerationProperty( *spread, SPREAD_METHOD_TABLE, SPREAD_METHOD_TABLE_COUNT, spreadMethod ) )
453     {
454       mGradient->SetSpreadMethod( spreadMethod );
455     }
456   }
457
458   return true;
459 }
460
461 void GradientVisual::GetStopOffsets(const Property::Value* value, Vector<float>& stopOffsets)
462 {
463
464   if ( value ) // Only check valve type if a valid Property has been passed in
465   {
466     switch ( value->GetType() )
467     {
468       case Property::VECTOR2:
469       {
470         Vector2 offset2;
471         value->Get( offset2 );
472         stopOffsets.PushBack( offset2.x );
473         stopOffsets.PushBack( offset2.y );
474         break;
475       }
476       case Property::VECTOR3:
477       {
478         Vector3 offset3;
479         value->Get( offset3 );
480         stopOffsets.PushBack( offset3.x );
481         stopOffsets.PushBack( offset3.y );
482         stopOffsets.PushBack( offset3.z );
483         break;
484       }
485       case Property::VECTOR4:
486       {
487         Vector4 offset4;
488         value->Get( offset4 );
489         stopOffsets.PushBack( offset4.x );
490         stopOffsets.PushBack( offset4.y );
491         stopOffsets.PushBack( offset4.z );
492         stopOffsets.PushBack( offset4.w );
493         break;
494       }
495       case Property::ARRAY:
496       {
497         Property::Array* offsetArray = value->GetArray();
498         if( offsetArray )
499         {
500           unsigned int numStop = offsetArray->Count();
501           float offset;
502           for( unsigned int i=0; i<numStop; i++ )
503           {
504             if( offsetArray->GetElementAt(i).Get(offset) )
505             {
506               stopOffsets.PushBack( offset );
507             }
508           }
509         }
510         break;
511       }
512       default:
513       {
514         DALI_LOG_WARNING("GetStopOffsets passed unsupported Property Map\n");
515         // Unsupported Type
516       }
517     }
518   }
519
520   if ( stopOffsets.Empty() )
521   {
522     // Set default offset if none set by Property system, need a minimum and maximum
523     stopOffsets.PushBack( DEFAULT_OFFSET_MINIMUM );
524     stopOffsets.PushBack( DEFAULT_OFFSET_MAXIMUM );
525   }
526 }
527
528 } // namespace Internal
529
530 } // namespace Toolkit
531
532 } // namespace Dali