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("gradientRenderer");
49 // properties: linear gradient
50 const char * const GRADIENT_START_POSITION_NAME("gradientStartPosition"); // Property::VECTOR2
51 const char * const GRADIENT_END_POSITION_NAME("gradientEndPosition"); // Property::VECTOR2
53 // properties: radial gradient
54 const char * const GRADIENT_CENTER_NAME("gradientCenter"); // Property::VECTOR2
55 const char * const GRADIENT_RADIUS_NAME("gradientRadius"); // Property::FLOAT
57 // properties: linear&radial gradient
58 const char * const GRADIENT_STOP_OFFSET_NAME("gradientStopOffset"); // Property::Array FLOAT
59 const char * const GRADIENT_STOP_COLOR_NAME("gradientStopColor"); // Property::Array VECTOR4
60 const char * const GRADIENT_UNITS_NAME("gradientUnits"); // Property::String "userSpaceOnUse | objectBoundingBox"
61 const char * const GRADIENT_SPREAD_METHOD_NAME("gradientSpreadMethod"); // 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 RendererFactoryCache::ShaderType GetShaderType( GradientRenderer::Type type, Gradient::GradientUnits units)
76 if( type==GradientRenderer::LINEAR )
78 if( units == Gradient::USER_SPACE_ON_USE )
80 return RendererFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE;
82 return RendererFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX;
84 else if( units == Gradient::USER_SPACE_ON_USE )
86 return RendererFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE;
89 return RendererFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX;
92 const char* VERTEX_SHADER[] =
94 // vertex shader for gradient units as USER_SPACE_ON_USE
96 attribute mediump vec2 aPosition;\n
97 uniform mediump mat4 uMvpMatrix;\n
98 uniform mediump vec3 uSize;\n
99 uniform mediump mat3 uAlignmentMatrix;\n
100 varying mediump vec2 vTexCoord;\n
104 mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
105 vertexPosition.xyz *= uSize;\n
106 gl_Position = uMvpMatrix * vertexPosition;\n
108 vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
112 // vertex shader for gradient units as OBJECT_BOUNDING_BOX
114 attribute mediump vec2 aPosition;\n
115 uniform mediump mat4 uMvpMatrix;\n
116 uniform mediump vec3 uSize;\n
117 uniform mediump mat3 uAlignmentMatrix;\n
118 varying mediump vec2 vTexCoord;\n
122 mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
123 vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
125 vertexPosition.xyz *= uSize;\n
126 gl_Position = uMvpMatrix * vertexPosition;\n
131 const char* FRAGMENT_SHADER[] =
133 // fragment shader for linear gradient
135 uniform sampler2D sTexture;\n // sampler1D?
136 uniform lowp vec4 uColor;\n
137 varying mediump vec2 vTexCoord;\n
141 gl_FragColor = texture2D( sTexture, vec2( vTexCoord.y, 0.5 ) ) * uColor;\n
145 // fragment shader for radial gradient
147 uniform sampler2D sTexture;\n // sampler1D?
148 uniform lowp vec4 uColor;\n
149 varying mediump vec2 vTexCoord;\n
153 gl_FragColor = texture2D( sTexture, vec2( length(vTexCoord), 0.5 ) ) * uColor;\n
158 Dali::WrapMode::Type GetWrapMode( Gradient::SpreadMethod spread )
162 case Gradient::REPEAT:
164 return Dali::WrapMode::REPEAT;
166 case Gradient::REFLECT:
168 return Dali::WrapMode::MIRRORED_REPEAT;
173 return Dali::WrapMode::CLAMP_TO_EDGE;
181 GradientRenderer::GradientRenderer( RendererFactoryCache& factoryCache )
182 : ControlRenderer( factoryCache ),
183 mGradientType( LINEAR )
187 GradientRenderer::~GradientRenderer()
191 void GradientRenderer::DoInitialize( Actor& actor, const Property::Map& propertyMap )
193 Gradient::GradientUnits gradientUnits = Gradient::OBJECT_BOUNDING_BOX;
194 Property::Value* unitsValue = propertyMap.Find( GRADIENT_UNITS_NAME );
196 // The default unit is OBJECT_BOUNDING_BOX.
197 // Only need to set new units if 'user-space'
198 if( unitsValue && unitsValue->Get( units ) && units == UNIT_USER_SPACE )
200 gradientUnits = Gradient::USER_SPACE_ON_USE;
203 mGradientType = LINEAR;
204 if( propertyMap.Find( GRADIENT_RADIUS_NAME ))
206 mGradientType = RADIAL;
209 if( NewGradient( mGradientType, propertyMap ) )
211 mGradient->SetGradientUnits( gradientUnits );
212 mGradientTransform = mGradient->GetAlignmentTransform();
216 DALI_LOG_ERROR( "Fail to provide valid properties to create a GradientRenderer object" );
220 void GradientRenderer::SetSize( const Vector2& size )
222 ControlRenderer::SetSize( size );
225 void GradientRenderer::SetClipRect( const Rect<int>& clipRect )
227 ControlRenderer::SetClipRect( clipRect );
229 //ToDo: renderer responds to the clipRect change
232 void GradientRenderer::SetOffset( const Vector2& offset )
234 //ToDo: renderer applies the offset
237 void GradientRenderer::DoSetOnStage( Actor& actor )
239 InitializeRenderer();
242 void GradientRenderer::DoCreatePropertyMap( Property::Map& map ) const
245 map.Insert( RENDERER_TYPE, RENDERER_TYPE_VALUE );
247 Gradient::GradientUnits units = mGradient->GetGradientUnits();
248 if( units == Gradient::USER_SPACE_ON_USE )
250 map.Insert( GRADIENT_UNITS_NAME, UNIT_USER_SPACE );
252 else // if( units == Gradient::OBJECT_BOUNDING_BOX )
254 map.Insert( GRADIENT_UNITS_NAME, UNIT_BOUNDING_BOX );
257 Gradient::SpreadMethod spread = mGradient->GetSpreadMethod();
258 if( spread == Gradient::PAD )
260 map.Insert( GRADIENT_SPREAD_METHOD_NAME, SPREAD_PAD );
262 else if( spread == Gradient::REFLECT )
264 map.Insert( GRADIENT_SPREAD_METHOD_NAME, SPREAD_REFLECT );
266 else // if( units == Gradient::REPEAT )
268 map.Insert( GRADIENT_SPREAD_METHOD_NAME, SPREAD_REPEAT );
271 const Vector<Gradient::GradientStop>& stops( mGradient->GetStops() );
272 Property::Array offsets;
273 Property::Array colors;
274 for( unsigned int i=0; i<stops.Count(); i++ )
276 offsets.PushBack( stops[i].mOffset );
277 colors.PushBack( stops[i].mStopColor );
280 map.Insert( GRADIENT_STOP_OFFSET_NAME, offsets );
281 map.Insert( GRADIENT_STOP_COLOR_NAME, colors );
283 if( &typeid( *mGradient ) == &typeid(LinearGradient) )
285 LinearGradient* gradient = static_cast<LinearGradient*>( mGradient.Get() );
286 map.Insert( GRADIENT_START_POSITION_NAME, gradient->GetStartPosition() );
287 map.Insert( GRADIENT_END_POSITION_NAME, gradient->GetEndPosition() );
289 else // if( &typeid( *mGradient ) == &typeid(RadialGradient) )
291 RadialGradient* gradient = static_cast<RadialGradient*>( mGradient.Get() );
292 map.Insert( GRADIENT_CENTER_NAME, gradient->GetCenter() );
293 map.Insert( GRADIENT_RADIUS_NAME, gradient->GetRadius() );
297 void GradientRenderer::InitializeRenderer()
299 Geometry geometry = mFactoryCache.GetGeometry( RendererFactoryCache::QUAD_GEOMETRY );
302 geometry = RendererFactoryCache::CreateQuadGeometry();
303 mFactoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, geometry );
306 Gradient::GradientUnits gradientUnits = mGradient->GetGradientUnits();
307 RendererFactoryCache::ShaderType shaderType = GetShaderType( mGradientType, gradientUnits );
308 Shader shader = mFactoryCache.GetShader( shaderType );
311 shader = Shader::New( VERTEX_SHADER[gradientUnits], FRAGMENT_SHADER[ mGradientType ] );
312 mFactoryCache.SaveShader( shaderType, shader );
316 material = Material::New( shader );
317 mImpl->mRenderer = Renderer::New( geometry, material );
319 Dali::BufferImage lookupTexture = mGradient->GenerateLookupTexture();
320 Sampler sampler = Sampler::New();
321 Dali::WrapMode::Type wrap = GetWrapMode( mGradient->GetSpreadMethod() );
322 sampler.SetWrapMode( wrap, wrap );
324 material.AddTexture( lookupTexture, UNIFORM_TEXTULRE_NAME, sampler );
326 mImpl->mRenderer.RegisterProperty( UNIFORM_ALIGNMENT_MATRIX_NAME, mGradientTransform );
329 bool GradientRenderer::NewGradient(Type gradientType, const Property::Map& propertyMap)
331 if( gradientType==LINEAR )
333 Property::Value* startPositionValue = propertyMap.Find( GRADIENT_START_POSITION_NAME );
334 Property::Value* endPositionValue = propertyMap.Find( GRADIENT_END_POSITION_NAME );
335 Vector2 startPosition;
338 if( startPositionValue && startPositionValue->Get(startPosition)
339 && endPositionValue && endPositionValue->Get( endPosition ) )
341 mGradient = new LinearGradient( startPosition, endPosition );
350 Property::Value* centerValue = propertyMap.Find( GRADIENT_CENTER_NAME );
351 Property::Value* radiusValue = propertyMap.Find( GRADIENT_RADIUS_NAME );
354 if( centerValue && centerValue->Get(center)
355 && radiusValue && radiusValue->Get(radius) )
357 mGradient = new RadialGradient( center, radius );
365 unsigned int numValidStop = 0u;
366 Property::Value* stopOffsetValue = propertyMap.Find( GRADIENT_STOP_OFFSET_NAME );
367 Property::Value* stopColorValue = propertyMap.Find( GRADIENT_STOP_COLOR_NAME );
368 if( stopOffsetValue && stopColorValue )
370 Vector<float> offsetArray;
371 Property::Array* colorArray = stopColorValue->GetArray();
372 if( colorArray && GetStopOffsets( stopOffsetValue, offsetArray ))
374 unsigned int numStop = offsetArray.Count() < colorArray->Count() ?
375 offsetArray.Count() : colorArray->Count();
377 for( unsigned int i=0; i<numStop; i++ )
379 if( (colorArray->GetElementAt(i)).Get(color) )
381 mGradient->AddStop( offsetArray[i], color);
388 if( numValidStop < 1u ) // no valid stop
393 Property::Value* spread = propertyMap.Find( GRADIENT_SPREAD_METHOD_NAME );
394 std::string stringValue ;
395 // The default spread method is PAD.
396 // Only need to set new spread if 'reflect' or 'repeat"
397 if( spread && spread->Get( stringValue ))
399 if( stringValue == SPREAD_REFLECT )
401 mGradient->SetSpreadMethod( Gradient::REFLECT );
403 else if( stringValue == SPREAD_REPEAT )
405 mGradient->SetSpreadMethod( Gradient::REPEAT );
412 bool GradientRenderer::GetStopOffsets(const Property::Value* value, Vector<float>& stopOffsets)
415 if( value->Get( offset2 ) )
417 stopOffsets.PushBack( offset2.x );
418 stopOffsets.PushBack( offset2.y );
423 if( value->Get( offset3 ) )
425 stopOffsets.PushBack( offset3.x );
426 stopOffsets.PushBack( offset3.y );
427 stopOffsets.PushBack( offset3.z );
432 if( value->Get( offset4 ) )
434 stopOffsets.PushBack( offset4.x );
435 stopOffsets.PushBack( offset4.y );
436 stopOffsets.PushBack( offset4.z );
437 stopOffsets.PushBack( offset4.w );
441 Property::Array* offsetArray = value->GetArray();
444 unsigned int numStop = offsetArray->Count();
446 for( unsigned int i=0; i<numStop; i++ )
448 if( offsetArray->GetElementAt(i).Get(offset) )
450 stopOffsets.PushBack( offset );
459 } // namespace Internal
461 } // namespace Toolkit