2 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "gradient-renderer.h"
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>
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>
46 const char * const RENDERER_TYPE("rendererType");
47 const char * const RENDERER_TYPE_VALUE("gradient");
49 // properties: linear gradient
50 const char * const START_POSITION_NAME("startPosition"); // Property::VECTOR2
51 const char * const END_POSITION_NAME("endPosition"); // Property::VECTOR2
53 // properties: radial gradient
54 const char * const CENTER_NAME("center"); // Property::VECTOR2
55 const char * const RADIUS_NAME("radius"); // Property::FLOAT
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"
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");
71 const char * const UNIFORM_ALIGNMENT_MATRIX_NAME( "uAlignmentMatrix" );
72 const char * const UNIFORM_TEXTULRE_NAME("sTexture");
74 // default offset value
75 const unsigned int DEFAULT_OFFSET_MINIMUM = 0.0f;
76 const unsigned int DEFAULT_OFFSET_MAXIMUM = 1.0f;
78 RendererFactoryCache::ShaderType GetShaderType( GradientRenderer::Type type, Gradient::GradientUnits units)
80 if( type==GradientRenderer::LINEAR )
82 if( units == Gradient::USER_SPACE_ON_USE )
84 return RendererFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE;
86 return RendererFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX;
88 else if( units == Gradient::USER_SPACE_ON_USE )
90 return RendererFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE;
93 return RendererFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX;
96 const char* VERTEX_SHADER[] =
98 // vertex shader for gradient units as USER_SPACE_ON_USE
100 attribute mediump vec2 aPosition;\n
101 uniform mediump mat4 uMvpMatrix;\n
102 uniform mediump vec3 uSize;\n
103 uniform mediump mat3 uAlignmentMatrix;\n
104 varying mediump vec2 vTexCoord;\n
108 mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
109 vertexPosition.xyz *= uSize;\n
110 gl_Position = uMvpMatrix * vertexPosition;\n
112 vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
116 // vertex shader for gradient units as OBJECT_BOUNDING_BOX
118 attribute mediump vec2 aPosition;\n
119 uniform mediump mat4 uMvpMatrix;\n
120 uniform mediump vec3 uSize;\n
121 uniform mediump mat3 uAlignmentMatrix;\n
122 varying mediump vec2 vTexCoord;\n
126 mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
127 vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
129 vertexPosition.xyz *= uSize;\n
130 gl_Position = uMvpMatrix * vertexPosition;\n
135 const char* FRAGMENT_SHADER[] =
137 // fragment shader for linear gradient
139 uniform sampler2D sTexture;\n // sampler1D?
140 uniform lowp vec4 uColor;\n
141 varying mediump vec2 vTexCoord;\n
145 gl_FragColor = texture2D( sTexture, vec2( vTexCoord.y, 0.5 ) ) * uColor;\n
149 // fragment shader for radial gradient
151 uniform sampler2D sTexture;\n // sampler1D?
152 uniform lowp vec4 uColor;\n
153 varying mediump vec2 vTexCoord;\n
157 gl_FragColor = texture2D( sTexture, vec2( length(vTexCoord), 0.5 ) ) * uColor;\n
162 Dali::WrapMode::Type GetWrapMode( Gradient::SpreadMethod spread )
166 case Gradient::REPEAT:
168 return Dali::WrapMode::REPEAT;
170 case Gradient::REFLECT:
172 return Dali::WrapMode::MIRRORED_REPEAT;
177 return Dali::WrapMode::CLAMP_TO_EDGE;
185 GradientRenderer::GradientRenderer( RendererFactoryCache& factoryCache )
186 : ControlRenderer( factoryCache ),
187 mGradientType( LINEAR )
191 GradientRenderer::~GradientRenderer()
195 void GradientRenderer::DoInitialize( Actor& actor, const Property::Map& propertyMap )
197 Gradient::GradientUnits gradientUnits = Gradient::OBJECT_BOUNDING_BOX;
198 Property::Value* unitsValue = propertyMap.Find( UNITS_NAME );
200 // The default unit is OBJECT_BOUNDING_BOX.
201 // Only need to set new units if 'user-space'
202 if( unitsValue && unitsValue->Get( units ) && units == UNIT_USER_SPACE )
204 gradientUnits = Gradient::USER_SPACE_ON_USE;
207 mGradientType = LINEAR;
208 if( propertyMap.Find( RADIUS_NAME ))
210 mGradientType = RADIAL;
213 if( NewGradient( mGradientType, propertyMap ) )
215 mGradient->SetGradientUnits( gradientUnits );
216 mGradientTransform = mGradient->GetAlignmentTransform();
220 DALI_LOG_ERROR( "Fail to provide valid properties to create a GradientRenderer object" );
224 void GradientRenderer::SetSize( const Vector2& size )
226 ControlRenderer::SetSize( size );
229 void GradientRenderer::SetClipRect( const Rect<int>& clipRect )
231 ControlRenderer::SetClipRect( clipRect );
233 //ToDo: renderer responds to the clipRect change
236 void GradientRenderer::SetOffset( const Vector2& offset )
238 //ToDo: renderer applies the offset
241 void GradientRenderer::DoSetOnStage( Actor& actor )
243 InitializeRenderer();
246 void GradientRenderer::DoCreatePropertyMap( Property::Map& map ) const
249 map.Insert( RENDERER_TYPE, RENDERER_TYPE_VALUE );
251 Gradient::GradientUnits units = mGradient->GetGradientUnits();
252 if( units == Gradient::USER_SPACE_ON_USE )
254 map.Insert( UNITS_NAME, UNIT_USER_SPACE );
256 else // if( units == Gradient::OBJECT_BOUNDING_BOX )
258 map.Insert( UNITS_NAME, UNIT_BOUNDING_BOX );
261 Gradient::SpreadMethod spread = mGradient->GetSpreadMethod();
262 if( spread == Gradient::PAD )
264 map.Insert( SPREAD_METHOD_NAME, SPREAD_PAD );
266 else if( spread == Gradient::REFLECT )
268 map.Insert( SPREAD_METHOD_NAME, SPREAD_REFLECT );
270 else // if( units == Gradient::REPEAT )
272 map.Insert( SPREAD_METHOD_NAME, SPREAD_REPEAT );
275 const Vector<Gradient::GradientStop>& stops( mGradient->GetStops() );
276 Property::Array offsets;
277 Property::Array colors;
278 for( unsigned int i=0; i<stops.Count(); i++ )
280 offsets.PushBack( stops[i].mOffset );
281 colors.PushBack( stops[i].mStopColor );
284 map.Insert( STOP_OFFSET_NAME, offsets );
285 map.Insert( STOP_COLOR_NAME, colors );
287 if( &typeid( *mGradient ) == &typeid(LinearGradient) )
289 LinearGradient* gradient = static_cast<LinearGradient*>( mGradient.Get() );
290 map.Insert( START_POSITION_NAME, gradient->GetStartPosition() );
291 map.Insert( END_POSITION_NAME, gradient->GetEndPosition() );
293 else // if( &typeid( *mGradient ) == &typeid(RadialGradient) )
295 RadialGradient* gradient = static_cast<RadialGradient*>( mGradient.Get() );
296 map.Insert( CENTER_NAME, gradient->GetCenter() );
297 map.Insert( RADIUS_NAME, gradient->GetRadius() );
301 void GradientRenderer::InitializeRenderer()
303 Geometry geometry = mFactoryCache.GetGeometry( RendererFactoryCache::QUAD_GEOMETRY );
306 geometry = RendererFactoryCache::CreateQuadGeometry();
307 mFactoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, geometry );
310 Gradient::GradientUnits gradientUnits = mGradient->GetGradientUnits();
311 RendererFactoryCache::ShaderType shaderType = GetShaderType( mGradientType, gradientUnits );
312 Shader shader = mFactoryCache.GetShader( shaderType );
315 shader = Shader::New( VERTEX_SHADER[gradientUnits], FRAGMENT_SHADER[ mGradientType ] );
316 mFactoryCache.SaveShader( shaderType, shader );
320 material = Material::New( shader );
321 mImpl->mRenderer = Renderer::New( geometry, material );
323 Dali::BufferImage lookupTexture = mGradient->GenerateLookupTexture();
324 Sampler sampler = Sampler::New();
325 Dali::WrapMode::Type wrap = GetWrapMode( mGradient->GetSpreadMethod() );
326 sampler.SetWrapMode( wrap, wrap );
328 material.AddTexture( lookupTexture, UNIFORM_TEXTULRE_NAME, sampler );
330 mImpl->mRenderer.RegisterProperty( UNIFORM_ALIGNMENT_MATRIX_NAME, mGradientTransform );
333 bool GradientRenderer::NewGradient(Type gradientType, const Property::Map& propertyMap)
335 if( gradientType==LINEAR )
337 Property::Value* startPositionValue = propertyMap.Find( START_POSITION_NAME );
338 Property::Value* endPositionValue = propertyMap.Find( END_POSITION_NAME );
339 Vector2 startPosition;
342 if( startPositionValue && startPositionValue->Get(startPosition)
343 && endPositionValue && endPositionValue->Get( endPosition ) )
345 mGradient = new LinearGradient( startPosition, endPosition );
354 Property::Value* centerValue = propertyMap.Find( CENTER_NAME );
355 Property::Value* radiusValue = propertyMap.Find( RADIUS_NAME );
358 if( centerValue && centerValue->Get(center)
359 && radiusValue && radiusValue->Get(radius) )
361 mGradient = new RadialGradient( center, radius );
369 unsigned int numValidStop = 0u;
370 Property::Value* stopOffsetValue = propertyMap.Find( STOP_OFFSET_NAME );
371 Property::Value* stopColorValue = propertyMap.Find( STOP_COLOR_NAME );
374 Vector<float> offsetArray;
375 Property::Array* colorArray = stopColorValue->GetArray();
378 GetStopOffsets( stopOffsetValue, offsetArray );
379 unsigned int numStop = offsetArray.Count() < colorArray->Count() ?
380 offsetArray.Count() : colorArray->Count();
382 for( unsigned int i=0; i<numStop; i++ )
384 if( (colorArray->GetElementAt(i)).Get(color) )
386 mGradient->AddStop( offsetArray[i], color);
393 if( numValidStop < 1u ) // no valid stop
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 ))
404 if( stringValue == SPREAD_REFLECT )
406 mGradient->SetSpreadMethod( Gradient::REFLECT );
408 else if( stringValue == SPREAD_REPEAT )
410 mGradient->SetSpreadMethod( Gradient::REPEAT );
417 void GradientRenderer::GetStopOffsets(const Property::Value* value, Vector<float>& stopOffsets)
420 if ( value ) // Only check valve type if a valid Property has been passed in
422 switch ( value->GetType() )
424 case Property::VECTOR2:
427 value->Get( offset2 );
428 stopOffsets.PushBack( offset2.x );
429 stopOffsets.PushBack( offset2.y );
432 case Property::VECTOR3:
435 value->Get( offset3 );
436 stopOffsets.PushBack( offset3.x );
437 stopOffsets.PushBack( offset3.y );
438 stopOffsets.PushBack( offset3.z );
441 case Property::VECTOR4:
444 value->Get( offset4 );
445 stopOffsets.PushBack( offset4.x );
446 stopOffsets.PushBack( offset4.y );
447 stopOffsets.PushBack( offset4.z );
448 stopOffsets.PushBack( offset4.w );
451 case Property::ARRAY:
453 Property::Array* offsetArray = value->GetArray();
454 unsigned int numStop = offsetArray->Count();
456 for( unsigned int i=0; i<numStop; i++ )
458 if( offsetArray->GetElementAt(i).Get(offset) )
460 stopOffsets.PushBack( offset );
467 DALI_LOG_WARNING("GetStopOffsets passed unsupported Property Map\n");
473 if ( stopOffsets.Empty() )
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 );
481 } // namespace Internal
483 } // namespace Toolkit