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-visual.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>
27 #include <dali/devel-api/scripting/enum-helper.h>
28 #include <dali/devel-api/scripting/scripting.h>
31 #include <dali-toolkit/public-api/visuals/gradient-visual-properties.h>
32 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
33 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
34 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
35 #include <dali-toolkit/internal/visuals/gradient/linear-gradient.h>
36 #include <dali-toolkit/internal/visuals/gradient/radial-gradient.h>
37 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
50 // properties: linear gradient
51 const char * const START_POSITION_NAME("startPosition"); // Property::VECTOR2
52 const char * const END_POSITION_NAME("endPosition"); // Property::VECTOR2
54 // properties: radial gradient
55 const char * const CENTER_NAME("center"); // Property::VECTOR2
56 const char * const RADIUS_NAME("radius"); // Property::FLOAT
58 // properties: linear&radial gradient
59 const char * const STOP_OFFSET_NAME("stopOffset"); // Property::Array FLOAT
60 const char * const STOP_COLOR_NAME("stopColor"); // Property::Array VECTOR4
61 const char * const UNITS_NAME("units"); // Property::String "userSpaceOnUse | objectBoundingBox"
62 const char * const SPREAD_METHOD_NAME("spreadMethod"); // Property::String "pad | reflect | repeat"
64 DALI_ENUM_TO_STRING_TABLE_BEGIN( UNITS )
65 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::Units, OBJECT_BOUNDING_BOX )
66 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::Units, USER_SPACE )
67 DALI_ENUM_TO_STRING_TABLE_END( UNITS )
69 DALI_ENUM_TO_STRING_TABLE_BEGIN( SPREAD_METHOD )
70 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::SpreadMethod, PAD )
71 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::SpreadMethod, REFLECT )
72 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::SpreadMethod, REPEAT )
73 DALI_ENUM_TO_STRING_TABLE_END( SPREAD_METHOD )
76 const char * const UNIFORM_ALIGNMENT_MATRIX_NAME( "uAlignmentMatrix" );
78 // default offset value
79 const unsigned int DEFAULT_OFFSET_MINIMUM = 0.0f;
80 const unsigned int DEFAULT_OFFSET_MAXIMUM = 1.0f;
82 VisualFactoryCache::ShaderType GetShaderType( GradientVisual::Type type, Toolkit::GradientVisual::Units::Type units )
84 if( type == GradientVisual::LINEAR )
86 if( units == Toolkit::GradientVisual::Units::USER_SPACE )
88 return VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE;
90 return VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX;
92 else if( units == Toolkit::GradientVisual::Units::USER_SPACE )
94 return VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE;
97 return VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX;
100 const char* VERTEX_SHADER[] =
102 // vertex shader for gradient units as OBJECT_BOUNDING_BOX
104 attribute mediump vec2 aPosition;\n
105 uniform mediump mat4 uMvpMatrix;\n
106 uniform mediump vec3 uSize;\n
107 uniform mediump mat3 uAlignmentMatrix;\n
108 varying mediump vec2 vTexCoord;\n
112 mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
113 vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
115 vertexPosition.xyz *= uSize;\n
116 gl_Position = uMvpMatrix * vertexPosition;\n
120 // vertex shader for gradient units as USER_SPACE
122 attribute mediump vec2 aPosition;\n
123 uniform mediump mat4 uMvpMatrix;\n
124 uniform mediump vec3 uSize;\n
125 uniform mediump mat3 uAlignmentMatrix;\n
126 varying mediump vec2 vTexCoord;\n
130 mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
131 vertexPosition.xyz *= uSize;\n
132 gl_Position = uMvpMatrix * vertexPosition;\n
134 vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
139 const char* FRAGMENT_SHADER[] =
141 // fragment shader for linear gradient
143 uniform sampler2D sTexture;\n // sampler1D?
144 uniform lowp vec4 uColor;\n
145 varying mediump vec2 vTexCoord;\n
149 gl_FragColor = texture2D( sTexture, vec2( vTexCoord.y, 0.5 ) ) * uColor;\n
153 // fragment shader for radial gradient
155 uniform sampler2D sTexture;\n // sampler1D?
156 uniform lowp vec4 uColor;\n
157 varying mediump vec2 vTexCoord;\n
161 gl_FragColor = texture2D( sTexture, vec2( length(vTexCoord), 0.5 ) ) * uColor;\n
166 Dali::WrapMode::Type GetWrapMode( Toolkit::GradientVisual::SpreadMethod::Type spread )
170 case Toolkit::GradientVisual::SpreadMethod::REPEAT:
172 return Dali::WrapMode::REPEAT;
174 case Toolkit::GradientVisual::SpreadMethod::REFLECT:
176 return Dali::WrapMode::MIRRORED_REPEAT;
178 case Toolkit::GradientVisual::SpreadMethod::PAD:
181 return Dali::WrapMode::CLAMP_TO_EDGE;
186 } // unnamed namespace
189 GradientVisual::GradientVisual( VisualFactoryCache& factoryCache )
190 : Visual::Base( factoryCache ),
191 mGradientType( LINEAR )
193 mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
196 GradientVisual::~GradientVisual()
200 void GradientVisual::DoInitialize( Actor& actor, const Property::Map& propertyMap )
202 Toolkit::GradientVisual::Units::Type gradientUnits = Toolkit::GradientVisual::Units::OBJECT_BOUNDING_BOX;
204 Property::Value* unitsValue = propertyMap.Find( Toolkit::GradientVisual::Property::UNITS, UNITS_NAME );
207 Scripting::GetEnumerationProperty( *unitsValue, UNITS_TABLE, UNITS_TABLE_COUNT, gradientUnits );
210 mGradientType = LINEAR;
211 if( propertyMap.Find( Toolkit::GradientVisual::Property::RADIUS, RADIUS_NAME ) )
213 mGradientType = RADIAL;
216 if( NewGradient( mGradientType, propertyMap ) )
218 mGradient->SetGradientUnits( gradientUnits );
219 mGradientTransform = mGradient->GetAlignmentTransform();
223 DALI_LOG_ERROR( "Fail to provide valid properties to create a GradientVisual object\n" );
227 void GradientVisual::SetSize( const Vector2& size )
229 Visual::Base::SetSize( size );
232 void GradientVisual::DoSetOnStage( Actor& actor )
234 InitializeRenderer();
236 actor.AddRenderer( mImpl->mRenderer );
239 void GradientVisual::DoCreatePropertyMap( Property::Map& map ) const
242 map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::GRADIENT );
243 map.Insert( Toolkit::GradientVisual::Property::UNITS, mGradient->GetGradientUnits() );
244 map.Insert( Toolkit::GradientVisual::Property::SPREAD_METHOD, mGradient->GetSpreadMethod() );
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 if( EqualsZero(stops[i].mStopColor.a) )
254 colors.PushBack( Vector4::ZERO );
258 colors.PushBack( Vector4( stops[i].mStopColor.r / stops[i].mStopColor.a,
259 stops[i].mStopColor.g / stops[i].mStopColor.a,
260 stops[i].mStopColor.b / stops[i].mStopColor.a,
261 stops[i].mStopColor.a));
265 map.Insert( Toolkit::GradientVisual::Property::STOP_OFFSET, offsets );
266 map.Insert( Toolkit::GradientVisual::Property::STOP_COLOR, colors );
268 if( &typeid( *mGradient ) == &typeid(LinearGradient) )
270 LinearGradient* gradient = static_cast<LinearGradient*>( mGradient.Get() );
271 map.Insert( Toolkit::GradientVisual::Property::START_POSITION, gradient->GetStartPosition() );
272 map.Insert( Toolkit::GradientVisual::Property::END_POSITION, gradient->GetEndPosition() );
274 else // if( &typeid( *mGradient ) == &typeid(RadialGradient) )
276 RadialGradient* gradient = static_cast<RadialGradient*>( mGradient.Get() );
277 map.Insert( Toolkit::GradientVisual::Property::CENTER, gradient->GetCenter() );
278 map.Insert( Toolkit::GradientVisual::Property::RADIUS, gradient->GetRadius() );
282 void GradientVisual::DoSetProperty( Dali::Property::Index index, const Dali::Property::Value& propertyValue )
287 Dali::Property::Value GradientVisual::DoGetProperty( Dali::Property::Index index )
290 return Dali::Property::Value();
293 void GradientVisual::InitializeRenderer()
295 Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
298 geometry = VisualFactoryCache::CreateQuadGeometry();
299 mFactoryCache.SaveGeometry( VisualFactoryCache::QUAD_GEOMETRY, geometry );
302 Toolkit::GradientVisual::Units::Type gradientUnits = mGradient->GetGradientUnits();
303 VisualFactoryCache::ShaderType shaderType = GetShaderType( mGradientType, gradientUnits );
304 Shader shader = mFactoryCache.GetShader( shaderType );
307 shader = Shader::New( VERTEX_SHADER[gradientUnits], FRAGMENT_SHADER[ mGradientType ] );
308 mFactoryCache.SaveShader( shaderType, shader );
311 //Set up the texture set
312 TextureSet textureSet = TextureSet::New();
313 Dali::Texture lookupTexture = mGradient->GenerateLookupTexture();
314 textureSet.SetTexture( 0u, lookupTexture );
315 Dali::WrapMode::Type wrap = GetWrapMode( mGradient->GetSpreadMethod() );
316 Sampler sampler = Sampler::New();
317 sampler.SetWrapMode( wrap, wrap );
318 textureSet.SetSampler( 0u, sampler );
320 mImpl->mRenderer = Renderer::New( geometry, shader );
321 mImpl->mRenderer.SetTextures( textureSet );
323 mImpl->mRenderer.RegisterProperty( UNIFORM_ALIGNMENT_MATRIX_NAME, mGradientTransform );
326 bool GradientVisual::NewGradient(Type gradientType, const Property::Map& propertyMap)
328 if( gradientType == LINEAR )
330 Property::Value* startPositionValue = propertyMap.Find( Toolkit::GradientVisual::Property::START_POSITION, START_POSITION_NAME );
331 Property::Value* endPositionValue = propertyMap.Find( Toolkit::GradientVisual::Property::END_POSITION, END_POSITION_NAME );
332 Vector2 startPosition;
335 if( startPositionValue && startPositionValue->Get(startPosition)
336 && endPositionValue && endPositionValue->Get( endPosition ) )
338 mGradient = new LinearGradient( startPosition, endPosition );
347 Property::Value* centerValue = propertyMap.Find( Toolkit::GradientVisual::Property::CENTER, CENTER_NAME );
348 Property::Value* radiusValue = propertyMap.Find( Toolkit::GradientVisual::Property::RADIUS, RADIUS_NAME );
351 if( centerValue && centerValue->Get(center)
352 && radiusValue && radiusValue->Get(radius) )
354 mGradient = new RadialGradient( center, radius );
362 unsigned int numValidStop = 0u;
363 Property::Value* stopOffsetValue = propertyMap.Find( Toolkit::GradientVisual::Property::STOP_OFFSET, STOP_OFFSET_NAME );
364 Property::Value* stopColorValue = propertyMap.Find( Toolkit::GradientVisual::Property::STOP_COLOR, STOP_COLOR_NAME );
367 Vector<float> offsetArray;
368 Property::Array* colorArray = stopColorValue->GetArray();
371 GetStopOffsets( stopOffsetValue, offsetArray );
372 unsigned int numStop = offsetArray.Count() < colorArray->Count() ?
373 offsetArray.Count() : colorArray->Count();
375 for( unsigned int i=0; i<numStop; i++ )
377 if( (colorArray->GetElementAt(i)).Get(color) )
379 mGradient->AddStop( offsetArray[i], Vector4(color.r*color.a, color.g*color.a, color.b*color.a, color.a));
386 if( numValidStop < 1u ) // no valid stop
391 Property::Value* spread = propertyMap.Find( Toolkit::GradientVisual::Property::SPREAD_METHOD, SPREAD_METHOD_NAME );
392 // The default spread method is PAD. Only need to set new spread if it's anything else.
395 Toolkit::GradientVisual::SpreadMethod::Type spreadMethod = Toolkit::GradientVisual::SpreadMethod::PAD;
396 if( Scripting::GetEnumerationProperty( *spread, SPREAD_METHOD_TABLE, SPREAD_METHOD_TABLE_COUNT, spreadMethod ) );
398 mGradient->SetSpreadMethod( spreadMethod );
405 void GradientVisual::GetStopOffsets(const Property::Value* value, Vector<float>& stopOffsets)
408 if ( value ) // Only check valve type if a valid Property has been passed in
410 switch ( value->GetType() )
412 case Property::VECTOR2:
415 value->Get( offset2 );
416 stopOffsets.PushBack( offset2.x );
417 stopOffsets.PushBack( offset2.y );
420 case Property::VECTOR3:
423 value->Get( offset3 );
424 stopOffsets.PushBack( offset3.x );
425 stopOffsets.PushBack( offset3.y );
426 stopOffsets.PushBack( offset3.z );
429 case Property::VECTOR4:
432 value->Get( offset4 );
433 stopOffsets.PushBack( offset4.x );
434 stopOffsets.PushBack( offset4.y );
435 stopOffsets.PushBack( offset4.z );
436 stopOffsets.PushBack( offset4.w );
439 case Property::ARRAY:
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 );
458 DALI_LOG_WARNING("GetStopOffsets passed unsupported Property Map\n");
464 if ( stopOffsets.Empty() )
466 // Set default offset if none set by Property system, need a minimum and maximum
467 stopOffsets.PushBack( DEFAULT_OFFSET_MINIMUM );
468 stopOffsets.PushBack( DEFAULT_OFFSET_MAXIMUM );
472 } // namespace Internal
474 } // namespace Toolkit