Merge "Implemented custom shader in ImageRenderer and changed Dissolve-effect to...
[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("renderer-type");
47 const char * const RENDERER_TYPE_VALUE("gradient-renderer");
48
49 // properties: linear gradient
50 const char * const GRADIENT_START_POSITION_NAME("gradient-start-position"); // Property::VECTOR2
51 const char * const GRADIENT_END_POSITION_NAME("gradient-end-position"); // Property::VECTOR2
52
53 // properties: radial gradient
54 const char * const GRADIENT_CENTER_NAME("gradient-center"); // Property::VECTOR2
55 const char * const GRADIENT_RADIUS_NAME("gradient-radius"); // Property::FLOAT
56
57 // properties: linear&radial gradient
58 const char * const GRADIENT_STOP_OFFSET_NAME("gradient-stop-offset"); // Property::Array FLOAT
59 const char * const GRADIENT_STOP_COLOR_NAME("gradient-stop-color"); // Property::Array VECTOR4
60 const char * const GRADIENT_UNITS_NAME("gradient-units"); // Property::String  "userSpaceOnUse | objectBoundingBox"
61 const char * const GRADIENT_SPREAD_METHOD_NAME("gradient-spread-method"); // Property::String  "pad | reflect | repeat"
62
63 // string values
64 const char * const UNIT_USER_SPACE("user-space");
65 const char * const UNIT_BOUNDING_BOX("object-bounding-box");
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 const char * const UNIFORM_TEXTULRE_NAME("sTexture");
73
74
75 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
76   attribute mediump vec2 aPosition;\n
77   uniform mediump mat4 uMvpMatrix;\n
78   uniform mediump vec3 uSize;\n
79   uniform mediump mat3 uAlignmentMatrix;\n
80   varying mediump vec2 vTexCoord;\n
81   \n
82   void main()\n
83   {\n
84     mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
85     vertexPosition.xyz *= uSize;\n
86     gl_Position = uMvpMatrix * vertexPosition;\n
87     \n
88     vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
89   }\n
90 );
91
92 const char* FRAGMENT_SHADER_LINEAR = DALI_COMPOSE_SHADER(
93   uniform sampler2D sTexture;\n // sampler1D?
94   uniform lowp vec4 uColor;\n
95   varying mediump vec2 vTexCoord;\n
96   \n
97   void main()\n
98   {\n
99     gl_FragColor = texture2D( sTexture, vec2( vTexCoord.y, 0.5 ) ) * uColor;\n
100   }\n
101 );
102
103 const char* FRAGMENT_SHADER_RADIAL = DALI_COMPOSE_SHADER(
104   uniform sampler2D sTexture;\n // sampler1D?
105   uniform lowp vec4 uColor;\n
106   varying mediump vec2 vTexCoord;\n
107   \n
108   void main()\n
109   {\n
110     gl_FragColor = texture2D( sTexture, vec2( length(vTexCoord), 0.5 ) ) * uColor;\n
111   }\n
112 );
113
114 Sampler::WrapMode GetWrapMode( Gradient::SpreadMethod spread )
115 {
116   switch(spread)
117   {
118     case Gradient::REPEAT:
119     {
120       return Sampler::REPEAT;
121     }
122     case Gradient::REFLECT:
123     {
124       return Sampler::MIRRORED_REPEAT;
125     }
126     case Gradient::PAD:
127     default:
128     {
129       return Sampler::CLAMP_TO_EDGE;
130     }
131   }
132 }
133
134 }
135
136
137 GradientRenderer::GradientRenderer()
138 :mGradientTransformIndex( Property::INVALID_INDEX )
139 {
140 }
141
142 GradientRenderer::~GradientRenderer()
143 {
144 }
145
146 void GradientRenderer::DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
147 {
148   mImpl->mGeometry = factoryCache.GetGeometry( RendererFactoryCache::QUAD_GEOMETRY );
149   if( !(mImpl->mGeometry) )
150   {
151     mImpl->mGeometry =  RendererFactoryCache::CreateQuadGeometry();
152     factoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, mImpl->mGeometry );
153   }
154
155   Type gradientType;
156   if( propertyMap.Find( GRADIENT_RADIUS_NAME ))
157   {
158     mImpl->mShader = factoryCache.GetShader( RendererFactoryCache::GRADIENT_SHADER_RADIAL );
159     if( !(mImpl->mShader) )
160     {
161       mImpl->mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_RADIAL );
162       factoryCache.SaveShader( RendererFactoryCache::GRADIENT_SHADER_RADIAL, mImpl->mShader );
163     }
164     gradientType = RADIAL;
165   }
166   else
167   {
168     mImpl->mShader = factoryCache.GetShader( RendererFactoryCache::GRADIENT_SHADER_LINEAR );
169     if( !(mImpl->mShader) )
170     {
171       mImpl->mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_LINEAR );
172       factoryCache.SaveShader( RendererFactoryCache::GRADIENT_SHADER_LINEAR, mImpl->mShader );
173     }
174     gradientType = LINEAR;
175   }
176
177   if( NewGradient(gradientType, propertyMap) )
178   {
179     mGradientTransform = mGradient->GetAlignmentTransform();
180   }
181   else
182   {
183     DALI_LOG_ERROR( "Fail to provide valid properties to create a GradientRenderer object" );
184   }
185 }
186
187 void GradientRenderer::SetSize( const Vector2& size )
188 {
189   ControlRenderer::SetSize( size );
190
191   if( mGradient->GetGradientUnits() == Gradient::OBJECT_BOUNDING_BOX )
192   {
193     // Apply scaling
194     Matrix3 scaling( 1.f/(size.x+Math::MACHINE_EPSILON_100), 0.f, 0.f,
195                      0.f, 1.f/(size.y+Math::MACHINE_EPSILON_100), 0.f, 0.5f, 0.5f, 1.f );
196     Matrix3::Multiply( mGradientTransform, scaling, mGradient->GetAlignmentTransform() );
197
198     if( mImpl->mRenderer )
199     {
200       (mImpl->mRenderer).SetProperty( mGradientTransformIndex, mGradientTransform );
201     }
202   }
203 }
204
205 void GradientRenderer::SetClipRect( const Rect<int>& clipRect )
206 {
207   ControlRenderer::SetClipRect( clipRect );
208
209   //ToDo: renderer responds to the clipRect change
210 }
211
212 void GradientRenderer::SetOffset( const Vector2& offset )
213 {
214   //ToDo: renderer applies the offset
215 }
216
217 void GradientRenderer::DoCreatePropertyMap( Property::Map& map ) const
218 {
219   map.Clear();
220   map.Insert( RENDERER_TYPE, RENDERER_TYPE_VALUE );
221
222   Gradient::GradientUnits units = mGradient->GetGradientUnits();
223   if( units == Gradient::USER_SPACE_ON_USE )
224   {
225     map.Insert( GRADIENT_UNITS_NAME, UNIT_USER_SPACE );
226   }
227   else // if( units == Gradient::OBJECT_BOUNDING_BOX )
228   {
229     map.Insert( GRADIENT_UNITS_NAME, UNIT_BOUNDING_BOX );
230   }
231
232   Gradient::SpreadMethod spread = mGradient->GetSpreadMethod();
233   if( spread == Gradient::PAD )
234   {
235     map.Insert( GRADIENT_SPREAD_METHOD_NAME, SPREAD_PAD );
236   }
237   else if( spread == Gradient::REFLECT )
238   {
239     map.Insert( GRADIENT_SPREAD_METHOD_NAME, SPREAD_REFLECT );
240   }
241   else // if( units == Gradient::REPEAT )
242   {
243     map.Insert( GRADIENT_SPREAD_METHOD_NAME, SPREAD_REPEAT );
244   }
245
246   const Vector<Gradient::GradientStop>& stops( mGradient->GetStops() );
247   Property::Array offsets;
248   Property::Array colors;
249   for( unsigned int i=0; i<stops.Count(); i++ )
250   {
251     offsets.PushBack( stops[i].mOffset );
252     colors.PushBack( stops[i].mStopColor );
253   }
254
255   map.Insert( GRADIENT_STOP_OFFSET_NAME, offsets );
256   map.Insert( GRADIENT_STOP_COLOR_NAME, colors );
257
258   if( &typeid( *mGradient ) == &typeid(LinearGradient) )
259   {
260     LinearGradient* gradient = static_cast<LinearGradient*>( mGradient.Get() );
261     map.Insert( GRADIENT_START_POSITION_NAME, gradient->GetStartPosition() );
262     map.Insert( GRADIENT_END_POSITION_NAME, gradient->GetEndPosition() );
263   }
264   else // if( &typeid( *mGradient ) == &typeid(RadialGradient) )
265   {
266     RadialGradient* gradient = static_cast<RadialGradient*>( mGradient.Get() );
267     map.Insert( GRADIENT_CENTER_NAME, gradient->GetCenter() );
268     map.Insert( GRADIENT_RADIUS_NAME, gradient->GetRadius() );
269   }
270 }
271
272 void GradientRenderer::DoSetOnStage( Actor& actor )
273 {
274   mGradientTransformIndex = (mImpl->mRenderer).RegisterProperty( UNIFORM_ALIGNMENT_MATRIX_NAME, mGradientTransform );
275
276   Dali::BufferImage lookupTexture = mGradient->GenerateLookupTexture();
277   Sampler sampler = Sampler::New( lookupTexture, UNIFORM_TEXTULRE_NAME );
278   Sampler::WrapMode wrap = GetWrapMode( mGradient->GetSpreadMethod() );
279   sampler.SetWrapMode(  wrap, wrap  );
280
281   Material material = (mImpl->mRenderer).GetMaterial();
282   if( material )
283   {
284     material.AddSampler( sampler );
285   }
286 }
287
288 bool GradientRenderer::NewGradient(Type gradientType, const Property::Map& propertyMap)
289 {
290   if( gradientType==LINEAR )
291   {
292     Property::Value* startPositionValue = propertyMap.Find( GRADIENT_START_POSITION_NAME );
293     Property::Value* endPositionValue = propertyMap.Find( GRADIENT_END_POSITION_NAME );
294     Vector2 startPosition;
295     Vector2 endPosition;
296
297     if( startPositionValue && startPositionValue->Get(startPosition)
298      && endPositionValue && endPositionValue->Get( endPosition ) )
299     {
300       mGradient = new LinearGradient( startPosition, endPosition );
301     }
302     else
303     {
304       return false;
305     }
306   }
307   else // type==RADIAL
308   {
309     Property::Value* centerValue = propertyMap.Find( GRADIENT_CENTER_NAME );
310     Property::Value* radiusValue = propertyMap.Find( GRADIENT_RADIUS_NAME );
311     Vector2 center;
312     float radius;
313     if( centerValue && centerValue->Get(center)
314         && radiusValue && radiusValue->Get(radius) )
315     {
316       mGradient = new RadialGradient( center, radius );
317     }
318     else
319     {
320       return false;
321     }
322   }
323
324   unsigned int numValidStop = 0u;
325   Property::Value* stopOffsetValue = propertyMap.Find( GRADIENT_STOP_OFFSET_NAME );
326   Property::Value* stopColorValue = propertyMap.Find( GRADIENT_STOP_COLOR_NAME );
327   if( stopOffsetValue && stopColorValue )
328   {
329     Vector<float> offsetArray;
330     Property::Array* colorArray = stopColorValue->GetArray();
331     if( colorArray && GetStopOffsets( stopOffsetValue, offsetArray ))
332     {
333       unsigned int numStop = offsetArray.Count() < colorArray->Count() ?
334                              offsetArray.Count() : colorArray->Count();
335       Vector4 color;
336       for( unsigned int i=0; i<numStop; i++ )
337       {
338         if( (colorArray->GetElementAt(i)).Get(color) )
339         {
340           mGradient->AddStop( offsetArray[i], color);
341           numValidStop++;
342         }
343       }
344     }
345   }
346
347   if( numValidStop < 1u ) // no valid stop
348   {
349     return false;
350   }
351
352   Property::Value* unitsValue = propertyMap.Find( GRADIENT_UNITS_NAME );
353   std::string units;
354   // The default unit is OBJECT_BOUNDING_BOX.
355   // Only need to set new units if 'user-space'
356   if( unitsValue && unitsValue->Get( units ) && units == UNIT_USER_SPACE )
357   {
358      mGradient->SetGradientUnits( Gradient::USER_SPACE_ON_USE );
359   }
360
361   Property::Value* spread = propertyMap.Find( GRADIENT_SPREAD_METHOD_NAME );
362   std::string stringValue ;
363   // The default spread method is PAD.
364   // Only need to set new spread if 'reflect' or 'repeat"
365   if( spread && spread->Get( stringValue ))
366   {
367     if( stringValue == SPREAD_REFLECT )
368     {
369       mGradient->SetSpreadMethod( Gradient::REFLECT );
370     }
371     else if( stringValue == SPREAD_REPEAT )
372     {
373       mGradient->SetSpreadMethod( Gradient::REPEAT );
374     }
375   }
376
377   return true;
378 }
379
380 bool GradientRenderer::GetStopOffsets(const Property::Value* value, Vector<float>& stopOffsets)
381 {
382   Vector2 offset2;
383   if( value->Get( offset2 ) )
384   {
385     stopOffsets.PushBack( offset2.x );
386     stopOffsets.PushBack( offset2.y );
387     return true;
388   }
389
390   Vector3 offset3;
391   if( value->Get( offset3 ) )
392   {
393     stopOffsets.PushBack( offset3.x );
394     stopOffsets.PushBack( offset3.y );
395     stopOffsets.PushBack( offset3.z );
396     return true;
397   }
398
399   Vector4 offset4;
400   if( value->Get( offset4 ) )
401   {
402     stopOffsets.PushBack( offset4.x );
403     stopOffsets.PushBack( offset4.y );
404     stopOffsets.PushBack( offset4.z );
405     stopOffsets.PushBack( offset4.w );
406     return true;
407   }
408
409   Property::Array* offsetArray = value->GetArray();
410   if( offsetArray )
411   {
412     unsigned int numStop = offsetArray->Count();
413     float offset;
414     for( unsigned int i=0; i<numStop; i++ )
415     {
416       if( offsetArray->GetElementAt(i).Get(offset) )
417       {
418         stopOffsets.PushBack( offset );
419       }
420     }
421     return true;
422   }
423
424   return false;
425 }
426
427 } // namespace Internal
428
429 } // namespace Toolkit
430
431 } // namespace Dali