2 * Copyright (c) 2016 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/renderer-string-constants.h>
33 #include <dali-toolkit/internal/controls/renderers/gradient/linear-gradient.h>
34 #include <dali-toolkit/internal/controls/renderers/gradient/radial-gradient.h>
47 // properties: linear gradient
48 const char * const START_POSITION_NAME("startPosition"); // Property::VECTOR2
49 const char * const END_POSITION_NAME("endPosition"); // Property::VECTOR2
51 // properties: radial gradient
52 const char * const CENTER_NAME("center"); // Property::VECTOR2
53 const char * const RADIUS_NAME("radius"); // Property::FLOAT
55 // properties: linear&radial gradient
56 const char * const STOP_OFFSET_NAME("stopOffset"); // Property::Array FLOAT
57 const char * const STOP_COLOR_NAME("stopColor"); // Property::Array VECTOR4
58 const char * const UNITS_NAME("units"); // Property::String "userSpaceOnUse | objectBoundingBox"
59 const char * const SPREAD_METHOD_NAME("spreadMethod"); // Property::String "pad | reflect | repeat"
62 const char * const UNIT_USER_SPACE("userSpace");
63 const char * const UNIT_BOUNDING_BOX("objectBoundingBox");
64 const char * const SPREAD_PAD("pad");
65 const char * const SPREAD_REFLECT("reflect");
66 const char * const SPREAD_REPEAT("repeat");
69 const char * const UNIFORM_ALIGNMENT_MATRIX_NAME( "uAlignmentMatrix" );
71 // default offset value
72 const unsigned int DEFAULT_OFFSET_MINIMUM = 0.0f;
73 const unsigned int DEFAULT_OFFSET_MAXIMUM = 1.0f;
75 RendererFactoryCache::ShaderType GetShaderType( GradientRenderer::Type type, Gradient::GradientUnits units)
77 if( type==GradientRenderer::LINEAR )
79 if( units == Gradient::USER_SPACE_ON_USE )
81 return RendererFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE;
83 return RendererFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX;
85 else if( units == Gradient::USER_SPACE_ON_USE )
87 return RendererFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE;
90 return RendererFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX;
93 const char* VERTEX_SHADER[] =
95 // vertex shader for gradient units as USER_SPACE_ON_USE
97 attribute mediump vec2 aPosition;\n
98 uniform mediump mat4 uMvpMatrix;\n
99 uniform mediump vec3 uSize;\n
100 uniform mediump mat3 uAlignmentMatrix;\n
101 varying mediump vec2 vTexCoord;\n
105 mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
106 vertexPosition.xyz *= uSize;\n
107 gl_Position = uMvpMatrix * vertexPosition;\n
109 vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
113 // vertex shader for gradient units as OBJECT_BOUNDING_BOX
115 attribute mediump vec2 aPosition;\n
116 uniform mediump mat4 uMvpMatrix;\n
117 uniform mediump vec3 uSize;\n
118 uniform mediump mat3 uAlignmentMatrix;\n
119 varying mediump vec2 vTexCoord;\n
123 mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
124 vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
126 vertexPosition.xyz *= uSize;\n
127 gl_Position = uMvpMatrix * vertexPosition;\n
132 const char* FRAGMENT_SHADER[] =
134 // fragment shader for linear gradient
136 uniform sampler2D sTexture;\n // sampler1D?
137 uniform lowp vec4 uColor;\n
138 varying mediump vec2 vTexCoord;\n
142 gl_FragColor = texture2D( sTexture, vec2( vTexCoord.y, 0.5 ) ) * uColor;\n
146 // fragment shader for radial gradient
148 uniform sampler2D sTexture;\n // sampler1D?
149 uniform lowp vec4 uColor;\n
150 varying mediump vec2 vTexCoord;\n
154 gl_FragColor = texture2D( sTexture, vec2( length(vTexCoord), 0.5 ) ) * uColor;\n
159 Dali::WrapMode::Type GetWrapMode( Gradient::SpreadMethod spread )
163 case Gradient::REPEAT:
165 return Dali::WrapMode::REPEAT;
167 case Gradient::REFLECT:
169 return Dali::WrapMode::MIRRORED_REPEAT;
174 return Dali::WrapMode::CLAMP_TO_EDGE;
182 GradientRenderer::GradientRenderer( RendererFactoryCache& factoryCache )
183 : ControlRenderer( factoryCache ),
184 mGradientType( LINEAR )
186 mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
189 GradientRenderer::~GradientRenderer()
193 void GradientRenderer::DoInitialize( Actor& actor, const Property::Map& propertyMap )
195 Gradient::GradientUnits gradientUnits = Gradient::OBJECT_BOUNDING_BOX;
196 Property::Value* unitsValue = propertyMap.Find( UNITS_NAME );
198 // The default unit is OBJECT_BOUNDING_BOX.
199 // Only need to set new units if 'user-space'
200 if( unitsValue && unitsValue->Get( units ) && units == UNIT_USER_SPACE )
202 gradientUnits = Gradient::USER_SPACE_ON_USE;
205 mGradientType = LINEAR;
206 if( propertyMap.Find( RADIUS_NAME ))
208 mGradientType = RADIAL;
211 if( NewGradient( mGradientType, propertyMap ) )
213 mGradient->SetGradientUnits( gradientUnits );
214 mGradientTransform = mGradient->GetAlignmentTransform();
218 DALI_LOG_ERROR( "Fail to provide valid properties to create a GradientRenderer object" );
222 void GradientRenderer::SetSize( const Vector2& size )
224 ControlRenderer::SetSize( size );
227 void GradientRenderer::SetClipRect( const Rect<int>& clipRect )
229 ControlRenderer::SetClipRect( clipRect );
231 //ToDo: renderer responds to the clipRect change
234 void GradientRenderer::SetOffset( const Vector2& offset )
236 //ToDo: renderer applies the offset
239 void GradientRenderer::DoSetOnStage( Actor& actor )
241 InitializeRenderer();
244 void GradientRenderer::DoCreatePropertyMap( Property::Map& map ) const
247 map.Insert( RENDERER_TYPE, GRADIENT_RENDERER );
249 Gradient::GradientUnits units = mGradient->GetGradientUnits();
250 if( units == Gradient::USER_SPACE_ON_USE )
252 map.Insert( UNITS_NAME, UNIT_USER_SPACE );
254 else // if( units == Gradient::OBJECT_BOUNDING_BOX )
256 map.Insert( UNITS_NAME, UNIT_BOUNDING_BOX );
259 Gradient::SpreadMethod spread = mGradient->GetSpreadMethod();
260 if( spread == Gradient::PAD )
262 map.Insert( SPREAD_METHOD_NAME, SPREAD_PAD );
264 else if( spread == Gradient::REFLECT )
266 map.Insert( SPREAD_METHOD_NAME, SPREAD_REFLECT );
268 else // if( units == Gradient::REPEAT )
270 map.Insert( SPREAD_METHOD_NAME, SPREAD_REPEAT );
273 const Vector<Gradient::GradientStop>& stops( mGradient->GetStops() );
274 Property::Array offsets;
275 Property::Array colors;
276 for( unsigned int i=0; i<stops.Count(); i++ )
278 offsets.PushBack( stops[i].mOffset );
279 if( EqualsZero(stops[i].mStopColor.a) )
281 colors.PushBack( Vector4::ZERO );
285 colors.PushBack( Vector4( stops[i].mStopColor.r / stops[i].mStopColor.a,
286 stops[i].mStopColor.g / stops[i].mStopColor.a,
287 stops[i].mStopColor.b / stops[i].mStopColor.a,
288 stops[i].mStopColor.a));
292 map.Insert( STOP_OFFSET_NAME, offsets );
293 map.Insert( STOP_COLOR_NAME, colors );
295 if( &typeid( *mGradient ) == &typeid(LinearGradient) )
297 LinearGradient* gradient = static_cast<LinearGradient*>( mGradient.Get() );
298 map.Insert( START_POSITION_NAME, gradient->GetStartPosition() );
299 map.Insert( END_POSITION_NAME, gradient->GetEndPosition() );
301 else // if( &typeid( *mGradient ) == &typeid(RadialGradient) )
303 RadialGradient* gradient = static_cast<RadialGradient*>( mGradient.Get() );
304 map.Insert( CENTER_NAME, gradient->GetCenter() );
305 map.Insert( RADIUS_NAME, gradient->GetRadius() );
309 void GradientRenderer::InitializeRenderer()
311 Geometry geometry = mFactoryCache.GetGeometry( RendererFactoryCache::QUAD_GEOMETRY );
314 geometry = Geometry::QUAD();
315 mFactoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, geometry );
318 Gradient::GradientUnits gradientUnits = mGradient->GetGradientUnits();
319 RendererFactoryCache::ShaderType shaderType = GetShaderType( mGradientType, gradientUnits );
320 Shader shader = mFactoryCache.GetShader( shaderType );
323 shader = Shader::New( VERTEX_SHADER[gradientUnits], FRAGMENT_SHADER[ mGradientType ] );
324 mFactoryCache.SaveShader( shaderType, shader );
327 //Set up the texture set
328 TextureSet textureSet = TextureSet::New();
329 Dali::Texture lookupTexture = mGradient->GenerateLookupTexture();
330 textureSet.SetTexture( 0u, lookupTexture );
331 Dali::WrapMode::Type wrap = GetWrapMode( mGradient->GetSpreadMethod() );
332 Sampler sampler = Sampler::New();
333 sampler.SetWrapMode( wrap, wrap );
334 textureSet.SetSampler( 0u, sampler );
336 mImpl->mRenderer = Renderer::New( geometry, shader );
337 mImpl->mRenderer.SetTextures( textureSet );
339 mImpl->mRenderer.RegisterProperty( UNIFORM_ALIGNMENT_MATRIX_NAME, mGradientTransform );
342 bool GradientRenderer::NewGradient(Type gradientType, const Property::Map& propertyMap)
344 if( gradientType==LINEAR )
346 Property::Value* startPositionValue = propertyMap.Find( START_POSITION_NAME );
347 Property::Value* endPositionValue = propertyMap.Find( END_POSITION_NAME );
348 Vector2 startPosition;
351 if( startPositionValue && startPositionValue->Get(startPosition)
352 && endPositionValue && endPositionValue->Get( endPosition ) )
354 mGradient = new LinearGradient( startPosition, endPosition );
363 Property::Value* centerValue = propertyMap.Find( CENTER_NAME );
364 Property::Value* radiusValue = propertyMap.Find( RADIUS_NAME );
367 if( centerValue && centerValue->Get(center)
368 && radiusValue && radiusValue->Get(radius) )
370 mGradient = new RadialGradient( center, radius );
378 unsigned int numValidStop = 0u;
379 Property::Value* stopOffsetValue = propertyMap.Find( STOP_OFFSET_NAME );
380 Property::Value* stopColorValue = propertyMap.Find( STOP_COLOR_NAME );
383 Vector<float> offsetArray;
384 Property::Array* colorArray = stopColorValue->GetArray();
387 GetStopOffsets( stopOffsetValue, offsetArray );
388 unsigned int numStop = offsetArray.Count() < colorArray->Count() ?
389 offsetArray.Count() : colorArray->Count();
391 for( unsigned int i=0; i<numStop; i++ )
393 if( (colorArray->GetElementAt(i)).Get(color) )
395 mGradient->AddStop( offsetArray[i], Vector4(color.r*color.a, color.g*color.a, color.b*color.a, color.a));
402 if( numValidStop < 1u ) // no valid stop
407 Property::Value* spread = propertyMap.Find( SPREAD_METHOD_NAME );
408 std::string stringValue ;
409 // The default spread method is PAD.
410 // Only need to set new spread if 'reflect' or 'repeat"
411 if( spread && spread->Get( stringValue ))
413 if( stringValue == SPREAD_REFLECT )
415 mGradient->SetSpreadMethod( Gradient::REFLECT );
417 else if( stringValue == SPREAD_REPEAT )
419 mGradient->SetSpreadMethod( Gradient::REPEAT );
426 void GradientRenderer::GetStopOffsets(const Property::Value* value, Vector<float>& stopOffsets)
429 if ( value ) // Only check valve type if a valid Property has been passed in
431 switch ( value->GetType() )
433 case Property::VECTOR2:
436 value->Get( offset2 );
437 stopOffsets.PushBack( offset2.x );
438 stopOffsets.PushBack( offset2.y );
441 case Property::VECTOR3:
444 value->Get( offset3 );
445 stopOffsets.PushBack( offset3.x );
446 stopOffsets.PushBack( offset3.y );
447 stopOffsets.PushBack( offset3.z );
450 case Property::VECTOR4:
453 value->Get( offset4 );
454 stopOffsets.PushBack( offset4.x );
455 stopOffsets.PushBack( offset4.y );
456 stopOffsets.PushBack( offset4.z );
457 stopOffsets.PushBack( offset4.w );
460 case Property::ARRAY:
462 Property::Array* offsetArray = value->GetArray();
465 unsigned int numStop = offsetArray->Count();
467 for( unsigned int i=0; i<numStop; i++ )
469 if( offsetArray->GetElementAt(i).Get(offset) )
471 stopOffsets.PushBack( offset );
479 DALI_LOG_WARNING("GetStopOffsets passed unsupported Property Map\n");
485 if ( stopOffsets.Empty() )
487 // Set default offset if none set by Property system, need a minimum and maximum
488 stopOffsets.PushBack( DEFAULT_OFFSET_MINIMUM );
489 stopOffsets.PushBack( DEFAULT_OFFSET_MAXIMUM );
493 } // namespace Internal
495 } // namespace Toolkit