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");
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
84 mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
85 vertexPosition.xyz *= uSize;\n
86 gl_Position = uMvpMatrix * vertexPosition;\n
88 vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
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
99 gl_FragColor = texture2D( sTexture, vec2( vTexCoord.y, 0.5 ) ) * uColor;\n
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
110 gl_FragColor = texture2D( sTexture, vec2( length(vTexCoord), 0.5 ) ) * uColor;\n
114 Sampler::WrapMode GetWrapMode( Gradient::SpreadMethod spread )
118 case Gradient::REPEAT:
120 return Sampler::REPEAT;
122 case Gradient::REFLECT:
124 return Sampler::MIRRORED_REPEAT;
129 return Sampler::CLAMP_TO_EDGE;
137 GradientRenderer::GradientRenderer()
138 :mGradientTransformIndex( Property::INVALID_INDEX )
142 GradientRenderer::~GradientRenderer()
146 void GradientRenderer::Initialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
148 mImpl->mGeometry = factoryCache.GetGeometry( RendererFactoryCache::QUAD_GEOMETRY );
149 if( !(mImpl->mGeometry) )
151 mImpl->mGeometry = RendererFactoryCache::CreateQuadGeometry();
152 factoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, mImpl->mGeometry );
156 if( propertyMap.Find( GRADIENT_RADIUS_NAME ))
158 mImpl->mShader = factoryCache.GetShader( RendererFactoryCache::GRADIENT_SHADER_RADIAL );
159 if( !(mImpl->mShader) )
161 mImpl->mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_RADIAL );
162 factoryCache.SaveShader( RendererFactoryCache::GRADIENT_SHADER_RADIAL, mImpl->mShader );
164 gradientType = RADIAL;
168 mImpl->mShader = factoryCache.GetShader( RendererFactoryCache::GRADIENT_SHADER_LINEAR );
169 if( !(mImpl->mShader) )
171 mImpl->mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_LINEAR );
172 factoryCache.SaveShader( RendererFactoryCache::GRADIENT_SHADER_LINEAR, mImpl->mShader );
174 gradientType = LINEAR;
177 if( NewGradient(gradientType, propertyMap) )
179 mGradientTransform = mGradient->GetAlignmentTransform();
183 DALI_LOG_ERROR( "Fail to provide valid properties to create a GradientRenderer object" );
187 void GradientRenderer::SetSize( const Vector2& size )
189 ControlRenderer::SetSize( size );
191 if( mGradient->GetGradientUnits() == Gradient::OBJECT_BOUNDING_BOX )
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() );
198 if( mImpl->mRenderer )
200 (mImpl->mRenderer).SetProperty( mGradientTransformIndex, mGradientTransform );
205 void GradientRenderer::SetClipRect( const Rect<int>& clipRect )
207 ControlRenderer::SetClipRect( clipRect );
209 //ToDo: renderer responds to the clipRect change
212 void GradientRenderer::SetOffset( const Vector2& offset )
214 //ToDo: renderer applies the offset
217 void GradientRenderer::CreatePropertyMap( Property::Map& map ) const
220 map.Insert( RENDERER_TYPE, RENDERER_TYPE_VALUE );
222 Gradient::GradientUnits units = mGradient->GetGradientUnits();
223 if( units == Gradient::USER_SPACE_ON_USE )
225 map.Insert( GRADIENT_UNITS_NAME, UNIT_USER_SPACE );
227 else // if( units == Gradient::OBJECT_BOUNDING_BOX )
229 map.Insert( GRADIENT_UNITS_NAME, UNIT_BOUNDING_BOX );
232 Gradient::SpreadMethod spread = mGradient->GetSpreadMethod();
233 if( spread == Gradient::PAD )
235 map.Insert( GRADIENT_SPREAD_METHOD_NAME, SPREAD_PAD );
237 else if( spread == Gradient::REFLECT )
239 map.Insert( GRADIENT_SPREAD_METHOD_NAME, SPREAD_REFLECT );
241 else // if( units == Gradient::REPEAT )
243 map.Insert( GRADIENT_SPREAD_METHOD_NAME, SPREAD_REPEAT );
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++ )
251 offsets.PushBack( stops[i].mOffset );
252 colors.PushBack( stops[i].mStopColor );
255 map.Insert( GRADIENT_STOP_OFFSET_NAME, offsets );
256 map.Insert( GRADIENT_STOP_COLOR_NAME, colors );
258 if( &typeid( *mGradient ) == &typeid(LinearGradient) )
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() );
264 else // if( &typeid( *mGradient ) == &typeid(RadialGradient) )
266 RadialGradient* gradient = static_cast<RadialGradient*>( mGradient.Get() );
267 map.Insert( GRADIENT_CENTER_NAME, gradient->GetCenter() );
268 map.Insert( GRADIENT_RADIUS_NAME, gradient->GetRadius() );
272 void GradientRenderer::DoSetOnStage( Actor& actor )
274 mGradientTransformIndex = (mImpl->mRenderer).RegisterProperty( UNIFORM_ALIGNMENT_MATRIX_NAME, mGradientTransform );
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 );
281 Material material = (mImpl->mRenderer).GetMaterial();
284 material.AddSampler( sampler );
288 bool GradientRenderer::NewGradient(Type gradientType, const Property::Map& propertyMap)
290 if( gradientType==LINEAR )
292 Property::Value* startPositionValue = propertyMap.Find( GRADIENT_START_POSITION_NAME );
293 Property::Value* endPositionValue = propertyMap.Find( GRADIENT_END_POSITION_NAME );
294 Vector2 startPosition;
297 if( startPositionValue && startPositionValue->Get(startPosition)
298 && endPositionValue && endPositionValue->Get( endPosition ) )
300 mGradient = new LinearGradient( startPosition, endPosition );
309 Property::Value* centerValue = propertyMap.Find( GRADIENT_CENTER_NAME );
310 Property::Value* radiusValue = propertyMap.Find( GRADIENT_RADIUS_NAME );
313 if( centerValue && centerValue->Get(center)
314 && radiusValue && radiusValue->Get(radius) )
316 mGradient = new RadialGradient( center, radius );
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 )
329 Vector<float> offsetArray;
330 Property::Array* colorArray = stopColorValue->GetArray();
331 if( colorArray && GetStopOffsets( stopOffsetValue, offsetArray ))
333 unsigned int numStop = offsetArray.Count() < colorArray->Count() ?
334 offsetArray.Count() : colorArray->Count();
336 for( unsigned int i=0; i<numStop; i++ )
338 if( (colorArray->GetElementAt(i)).Get(color) )
340 mGradient->AddStop( offsetArray[i], color);
347 if( numValidStop < 1u ) // no valid stop
352 Property::Value* unitsValue = propertyMap.Find( GRADIENT_UNITS_NAME );
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 )
358 mGradient->SetGradientUnits( Gradient::USER_SPACE_ON_USE );
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 ))
367 if( stringValue == SPREAD_REFLECT )
369 mGradient->SetSpreadMethod( Gradient::REFLECT );
371 else if( stringValue == SPREAD_REPEAT )
373 mGradient->SetSpreadMethod( Gradient::REPEAT );
380 bool GradientRenderer::GetStopOffsets(const Property::Value* value, Vector<float>& stopOffsets)
383 if( value->Get( offset2 ) )
385 stopOffsets.PushBack( offset2.x );
386 stopOffsets.PushBack( offset2.y );
391 if( value->Get( offset3 ) )
393 stopOffsets.PushBack( offset3.x );
394 stopOffsets.PushBack( offset3.y );
395 stopOffsets.PushBack( offset3.z );
400 if( value->Get( offset4 ) )
402 stopOffsets.PushBack( offset4.x );
403 stopOffsets.PushBack( offset4.y );
404 stopOffsets.PushBack( offset4.z );
405 stopOffsets.PushBack( offset4.w );
409 Property::Array* offsetArray = value->GetArray();
412 unsigned int numStop = offsetArray->Count();
414 for( unsigned int i=0; i<numStop; i++ )
416 if( offsetArray->GetElementAt(i).Get(offset) )
418 stopOffsets.PushBack( offset );
427 } // namespace Internal
429 } // namespace Toolkit