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("renderer-type");
47 const char * const RENDERER_TYPE_VALUE("gradient-renderer");
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
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
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"
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");
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( 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::DoCreatePropertyMap( Property::Map& map ) const
240 map.Insert( RENDERER_TYPE, RENDERER_TYPE_VALUE );
242 Gradient::GradientUnits units = mGradient->GetGradientUnits();
243 if( units == Gradient::USER_SPACE_ON_USE )
245 map.Insert( GRADIENT_UNITS_NAME, UNIT_USER_SPACE );
247 else // if( units == Gradient::OBJECT_BOUNDING_BOX )
249 map.Insert( GRADIENT_UNITS_NAME, UNIT_BOUNDING_BOX );
252 Gradient::SpreadMethod spread = mGradient->GetSpreadMethod();
253 if( spread == Gradient::PAD )
255 map.Insert( GRADIENT_SPREAD_METHOD_NAME, SPREAD_PAD );
257 else if( spread == Gradient::REFLECT )
259 map.Insert( GRADIENT_SPREAD_METHOD_NAME, SPREAD_REFLECT );
261 else // if( units == Gradient::REPEAT )
263 map.Insert( GRADIENT_SPREAD_METHOD_NAME, SPREAD_REPEAT );
266 const Vector<Gradient::GradientStop>& stops( mGradient->GetStops() );
267 Property::Array offsets;
268 Property::Array colors;
269 for( unsigned int i=0; i<stops.Count(); i++ )
271 offsets.PushBack( stops[i].mOffset );
272 colors.PushBack( stops[i].mStopColor );
275 map.Insert( GRADIENT_STOP_OFFSET_NAME, offsets );
276 map.Insert( GRADIENT_STOP_COLOR_NAME, colors );
278 if( &typeid( *mGradient ) == &typeid(LinearGradient) )
280 LinearGradient* gradient = static_cast<LinearGradient*>( mGradient.Get() );
281 map.Insert( GRADIENT_START_POSITION_NAME, gradient->GetStartPosition() );
282 map.Insert( GRADIENT_END_POSITION_NAME, gradient->GetEndPosition() );
284 else // if( &typeid( *mGradient ) == &typeid(RadialGradient) )
286 RadialGradient* gradient = static_cast<RadialGradient*>( mGradient.Get() );
287 map.Insert( GRADIENT_CENTER_NAME, gradient->GetCenter() );
288 map.Insert( GRADIENT_RADIUS_NAME, gradient->GetRadius() );
292 void GradientRenderer::InitializeRenderer( Dali::Renderer& renderer )
294 Geometry geometry = mFactoryCache.GetGeometry( RendererFactoryCache::QUAD_GEOMETRY );
297 geometry = RendererFactoryCache::CreateQuadGeometry();
298 mFactoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, geometry );
301 Gradient::GradientUnits gradientUnits = mGradient->GetGradientUnits();
302 RendererFactoryCache::ShaderType shaderType = GetShaderType( mGradientType, gradientUnits );
303 Shader shader = mFactoryCache.GetShader( shaderType );
306 shader = Shader::New( VERTEX_SHADER[gradientUnits], FRAGMENT_SHADER[ mGradientType ] );
307 mFactoryCache.SaveShader( shaderType, shader );
313 material = Material::New( shader );
314 renderer = Renderer::New( geometry, material );
318 mImpl->mRenderer.SetGeometry( geometry );
319 material = mImpl->mRenderer.GetMaterial();
322 material.SetShader( shader );
326 Dali::BufferImage lookupTexture = mGradient->GenerateLookupTexture();
327 Sampler sampler = Sampler::New();
328 Dali::WrapMode::Type wrap = GetWrapMode( mGradient->GetSpreadMethod() );
329 sampler.SetWrapMode( wrap, wrap );
331 material.AddTexture( lookupTexture, UNIFORM_TEXTULRE_NAME, sampler );
333 renderer.RegisterProperty( UNIFORM_ALIGNMENT_MATRIX_NAME, mGradientTransform );
336 bool GradientRenderer::NewGradient(Type gradientType, const Property::Map& propertyMap)
338 if( gradientType==LINEAR )
340 Property::Value* startPositionValue = propertyMap.Find( GRADIENT_START_POSITION_NAME );
341 Property::Value* endPositionValue = propertyMap.Find( GRADIENT_END_POSITION_NAME );
342 Vector2 startPosition;
345 if( startPositionValue && startPositionValue->Get(startPosition)
346 && endPositionValue && endPositionValue->Get( endPosition ) )
348 mGradient = new LinearGradient( startPosition, endPosition );
357 Property::Value* centerValue = propertyMap.Find( GRADIENT_CENTER_NAME );
358 Property::Value* radiusValue = propertyMap.Find( GRADIENT_RADIUS_NAME );
361 if( centerValue && centerValue->Get(center)
362 && radiusValue && radiusValue->Get(radius) )
364 mGradient = new RadialGradient( center, radius );
372 unsigned int numValidStop = 0u;
373 Property::Value* stopOffsetValue = propertyMap.Find( GRADIENT_STOP_OFFSET_NAME );
374 Property::Value* stopColorValue = propertyMap.Find( GRADIENT_STOP_COLOR_NAME );
375 if( stopOffsetValue && stopColorValue )
377 Vector<float> offsetArray;
378 Property::Array* colorArray = stopColorValue->GetArray();
379 if( colorArray && GetStopOffsets( stopOffsetValue, offsetArray ))
381 unsigned int numStop = offsetArray.Count() < colorArray->Count() ?
382 offsetArray.Count() : colorArray->Count();
384 for( unsigned int i=0; i<numStop; i++ )
386 if( (colorArray->GetElementAt(i)).Get(color) )
388 mGradient->AddStop( offsetArray[i], color);
395 if( numValidStop < 1u ) // no valid stop
400 Property::Value* spread = propertyMap.Find( GRADIENT_SPREAD_METHOD_NAME );
401 std::string stringValue ;
402 // The default spread method is PAD.
403 // Only need to set new spread if 'reflect' or 'repeat"
404 if( spread && spread->Get( stringValue ))
406 if( stringValue == SPREAD_REFLECT )
408 mGradient->SetSpreadMethod( Gradient::REFLECT );
410 else if( stringValue == SPREAD_REPEAT )
412 mGradient->SetSpreadMethod( Gradient::REPEAT );
419 bool GradientRenderer::GetStopOffsets(const Property::Value* value, Vector<float>& stopOffsets)
422 if( value->Get( offset2 ) )
424 stopOffsets.PushBack( offset2.x );
425 stopOffsets.PushBack( offset2.y );
430 if( value->Get( offset3 ) )
432 stopOffsets.PushBack( offset3.x );
433 stopOffsets.PushBack( offset3.y );
434 stopOffsets.PushBack( offset3.z );
439 if( value->Get( offset4 ) )
441 stopOffsets.PushBack( offset4.x );
442 stopOffsets.PushBack( offset4.y );
443 stopOffsets.PushBack( offset4.z );
444 stopOffsets.PushBack( offset4.w );
448 Property::Array* offsetArray = value->GetArray();
451 unsigned int numStop = offsetArray->Count();
453 for( unsigned int i=0; i<numStop; i++ )
455 if( offsetArray->GetElementAt(i).Get(offset) )
457 stopOffsets.PushBack( offset );
466 } // namespace Internal
468 } // namespace Toolkit