2 * Copyright (c) 2018 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>
30 // @todo: using generated file in the dali-core!!!!
31 #include <dali-toolkit/devel-api/graphics/builtin-shader-extern-gen.h>
32 #include <dali/devel-api/rendering/shader-devel.h>
35 #include <dali-toolkit/public-api/visuals/gradient-visual-properties.h>
36 #include <dali-toolkit/public-api/visuals/visual-properties.h>
37 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
38 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
39 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
40 #include <dali-toolkit/internal/visuals/gradient/linear-gradient.h>
41 #include <dali-toolkit/internal/visuals/gradient/radial-gradient.h>
42 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
55 // properties: linear gradient
56 const char * const START_POSITION_NAME("startPosition"); // Property::VECTOR2
57 const char * const END_POSITION_NAME("endPosition"); // Property::VECTOR2
59 // properties: radial gradient
60 const char * const CENTER_NAME("center"); // Property::VECTOR2
61 const char * const RADIUS_NAME("radius"); // Property::FLOAT
63 // properties: linear&radial gradient
64 const char * const STOP_OFFSET_NAME("stopOffset"); // Property::Array FLOAT
65 const char * const STOP_COLOR_NAME("stopColor"); // Property::Array VECTOR4
66 const char * const UNITS_NAME("units"); // Property::String "userSpaceOnUse | objectBoundingBox"
67 const char * const SPREAD_METHOD_NAME("spreadMethod"); // Property::String "pad | reflect | repeat"
69 DALI_ENUM_TO_STRING_TABLE_BEGIN( UNITS )
70 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::Units, OBJECT_BOUNDING_BOX )
71 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::Units, USER_SPACE )
72 DALI_ENUM_TO_STRING_TABLE_END( UNITS )
74 DALI_ENUM_TO_STRING_TABLE_BEGIN( SPREAD_METHOD )
75 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::SpreadMethod, PAD )
76 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::SpreadMethod, REFLECT )
77 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::SpreadMethod, REPEAT )
78 DALI_ENUM_TO_STRING_TABLE_END( SPREAD_METHOD )
81 const char * const UNIFORM_ALIGNMENT_MATRIX_NAME( "uAlignmentMatrix" );
83 // default offset value
84 const unsigned int DEFAULT_OFFSET_MINIMUM = 0.0f;
85 const unsigned int DEFAULT_OFFSET_MAXIMUM = 1.0f;
87 VisualFactoryCache::ShaderType GetShaderType( GradientVisual::Type type, Toolkit::GradientVisual::Units::Type units )
89 if( type == GradientVisual::LINEAR )
91 if( units == Toolkit::GradientVisual::Units::USER_SPACE )
93 return VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE;
95 return VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX;
97 else if( units == Toolkit::GradientVisual::Units::USER_SPACE )
99 return VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE;
102 return VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX;
106 const char* VERTEX_SHADER[] =
108 // vertex shader for gradient units as OBJECT_BOUNDING_BOX
110 attribute mediump vec2 aPosition;\n
111 uniform mediump mat4 uMvpMatrix;\n
112 uniform mediump vec3 uSize;\n
113 uniform mediump mat3 uAli3gnmentMatrix;\n
114 varying mediump vec2 vTexCoord;\n
117 //Visual size and offset
118 uniform mediump vec2 offset;\n
119 uniform mediump vec2 size;\n
120 uniform mediump vec4 offsetSizeMode;\n
121 uniform mediump vec2 origin;\n
122 uniform mediump vec2 anchorPoint;\n
124 vec4 ComputeVertexPosition()\n
126 vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );\n
127 vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
128 return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
133 mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
134 vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
136 gl_Position = uMvpMatrix * ComputeVertexPosition();\n
140 // vertex shader for gradient units as USER_SPACE
142 attribute mediump vec2 aPosition;\n
143 uniform mediump mat4 uMvpMatrix;\n
144 uniform mediump vec3 uSize;\n
145 uniform mediump mat3 uAlignmentMatrix;\n
146 varying mediump vec2 vTexCoord;\n
149 //Visual size and offset
150 uniform mediump vec2 offset;\n
151 uniform mediump vec2 size;\n
152 uniform mediump vec4 offsetSizeMode;\n
153 uniform mediump vec2 origin;\n
154 uniform mediump vec2 anchorPoint;\n
156 vec4 ComputeVertexPosition()\n
158 vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );\n
159 vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
160 return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
165 mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
166 vertexPosition.xyz *= uSize;\n
167 gl_Position = uMvpMatrix * ComputeVertexPosition();\n
169 vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
174 const char* FRAGMENT_SHADER[] =
176 // fragment shader for linear gradient
178 uniform sampler2D sTexture;\n // sampler1D?
179 uniform lowp vec4 uColor;\n
180 uniform lowp vec3 mixColor;\n
181 varying mediump vec2 vTexCoord;\n
185 gl_FragColor = texture2D( sTexture, vec2( vTexCoord.y, 0.5 ) ) * vec4(mixColor, 1.0) * uColor;\n
189 // fragment shader for radial gradient
191 uniform sampler2D sTexture;\n // sampler1D?
192 uniform lowp vec4 uColor;\n
193 uniform lowp vec3 mixColor;\n
194 varying mediump vec2 vTexCoord;\n
198 gl_FragColor = texture2D( sTexture, vec2( length(vTexCoord), 0.5 ) ) * vec4(mixColor, 1.0) * uColor;\n
205 Dali::WrapMode::Type GetWrapMode( Toolkit::GradientVisual::SpreadMethod::Type spread )
209 case Toolkit::GradientVisual::SpreadMethod::REPEAT:
211 return Dali::WrapMode::REPEAT;
213 case Toolkit::GradientVisual::SpreadMethod::REFLECT:
215 return Dali::WrapMode::MIRRORED_REPEAT;
217 case Toolkit::GradientVisual::SpreadMethod::PAD:
220 return Dali::WrapMode::CLAMP_TO_EDGE;
225 } // unnamed namespace
227 GradientVisualPtr GradientVisual::New( VisualFactoryCache& factoryCache, const Property::Map& properties )
229 GradientVisualPtr gradientVisualPtr( new GradientVisual( factoryCache ) );
230 gradientVisualPtr->SetProperties( properties );
231 return gradientVisualPtr;
234 GradientVisual::GradientVisual( VisualFactoryCache& factoryCache )
235 : Visual::Base( factoryCache, Visual::FittingMode::FILL ),
236 mGradientType( LINEAR ),
239 mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
242 GradientVisual::~GradientVisual()
246 void GradientVisual::DoSetProperties( const Property::Map& propertyMap )
248 Toolkit::GradientVisual::Units::Type gradientUnits = Toolkit::GradientVisual::Units::OBJECT_BOUNDING_BOX;
250 Property::Value* unitsValue = propertyMap.Find( Toolkit::GradientVisual::Property::UNITS, UNITS_NAME );
253 Scripting::GetEnumerationProperty( *unitsValue, UNITS_TABLE, UNITS_TABLE_COUNT, gradientUnits );
256 mGradientType = LINEAR;
257 if( propertyMap.Find( Toolkit::GradientVisual::Property::RADIUS, RADIUS_NAME ) )
259 mGradientType = RADIAL;
262 if( NewGradient( mGradientType, propertyMap ) )
264 mGradient->SetGradientUnits( gradientUnits );
265 mGradientTransform = mGradient->GetAlignmentTransform();
269 DALI_LOG_ERROR( "Fail to provide valid properties to create a GradientVisual object\n" );
273 void GradientVisual::OnSetTransform()
275 if( mImpl->mRenderer )
277 mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
281 void GradientVisual::DoSetOnStage( Actor& actor )
283 InitializeRenderer();
285 actor.AddRenderer( mImpl->mRenderer );
287 // Gradient Visual generated and ready to display
288 ResourceReady( Toolkit::Visual::ResourceStatus::READY );
291 void GradientVisual::DoCreatePropertyMap( Property::Map& map ) const
294 map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::GRADIENT );
295 map.Insert( Toolkit::GradientVisual::Property::UNITS, mGradient->GetGradientUnits() );
296 map.Insert( Toolkit::GradientVisual::Property::SPREAD_METHOD, mGradient->GetSpreadMethod() );
298 const Vector<Gradient::GradientStop>& stops( mGradient->GetStops() );
299 Property::Array offsets;
300 Property::Array colors;
301 for( unsigned int i=0; i<stops.Count(); i++ )
303 offsets.PushBack( stops[i].mOffset );
304 if( EqualsZero(stops[i].mStopColor.a) )
306 colors.PushBack( Vector4::ZERO );
310 colors.PushBack( Vector4( stops[i].mStopColor.r / stops[i].mStopColor.a,
311 stops[i].mStopColor.g / stops[i].mStopColor.a,
312 stops[i].mStopColor.b / stops[i].mStopColor.a,
313 stops[i].mStopColor.a));
317 map.Insert( Toolkit::GradientVisual::Property::STOP_OFFSET, offsets );
318 map.Insert( Toolkit::GradientVisual::Property::STOP_COLOR, colors );
320 if( &typeid( *mGradient ) == &typeid(LinearGradient) )
322 LinearGradient* gradient = static_cast<LinearGradient*>( mGradient.Get() );
323 map.Insert( Toolkit::GradientVisual::Property::START_POSITION, gradient->GetStartPosition() );
324 map.Insert( Toolkit::GradientVisual::Property::END_POSITION, gradient->GetEndPosition() );
326 else // if( &typeid( *mGradient ) == &typeid(RadialGradient) )
328 RadialGradient* gradient = static_cast<RadialGradient*>( mGradient.Get() );
329 map.Insert( Toolkit::GradientVisual::Property::CENTER, gradient->GetCenter() );
330 map.Insert( Toolkit::GradientVisual::Property::RADIUS, gradient->GetRadius() );
334 void GradientVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
339 void GradientVisual::InitializeRenderer()
341 Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
343 Toolkit::GradientVisual::Units::Type gradientUnits = mGradient->GetGradientUnits();
344 VisualFactoryCache::ShaderType shaderType = GetShaderType( mGradientType, gradientUnits );
345 Shader shader = mFactoryCache.GetShader( shaderType );
347 const char* VERTEX_SHADER_STR[] = {
348 "SHADER_GRADIENT_VISUAL_SHADER_0_VERT",
349 "SHADER_GRADIENT_VISUAL_SHADER_1_VERT",
352 const char* FRAGMENT_SHADER_STR[] = {
353 "SHADER_GRADIENT_VISUAL_SHADER_0_FRAG",
354 "SHADER_GRADIENT_VISUAL_SHADER_1_FRAG",
359 shader = DevelShader::New(
360 GraphicsGetBuiltinShader( VERTEX_SHADER_STR[gradientUnits] ),
361 GraphicsGetBuiltinShader( FRAGMENT_SHADER_STR[mGradientType] ),
362 DevelShader::ShaderLanguage::SPIRV_1_0,
366 mFactoryCache.SaveShader( shaderType, shader );
369 //Set up the texture set
370 TextureSet textureSet = TextureSet::New();
371 Dali::Texture lookupTexture = mGradient->GenerateLookupTexture();
372 textureSet.SetTexture( 0u, lookupTexture );
373 Dali::WrapMode::Type wrap = GetWrapMode( mGradient->GetSpreadMethod() );
374 Sampler sampler = Sampler::New();
375 sampler.SetWrapMode( wrap, wrap );
376 textureSet.SetSampler( 0u, sampler );
378 mImpl->mRenderer = Renderer::New( geometry, shader );
379 mImpl->mRenderer.SetTextures( textureSet );
381 // If opaque then no need to have blending
384 mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::OFF );
387 mImpl->mRenderer.RegisterProperty( UNIFORM_ALIGNMENT_MATRIX_NAME, mGradientTransform );
389 //Register transform properties
390 mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
393 bool GradientVisual::NewGradient(Type gradientType, const Property::Map& propertyMap)
395 if( gradientType == LINEAR )
397 Property::Value* startPositionValue = propertyMap.Find( Toolkit::GradientVisual::Property::START_POSITION, START_POSITION_NAME );
398 Property::Value* endPositionValue = propertyMap.Find( Toolkit::GradientVisual::Property::END_POSITION, END_POSITION_NAME );
399 Vector2 startPosition;
402 if( startPositionValue && startPositionValue->Get(startPosition)
403 && endPositionValue && endPositionValue->Get( endPosition ) )
405 mGradient = new LinearGradient( startPosition, endPosition );
414 Property::Value* centerValue = propertyMap.Find( Toolkit::GradientVisual::Property::CENTER, CENTER_NAME );
415 Property::Value* radiusValue = propertyMap.Find( Toolkit::GradientVisual::Property::RADIUS, RADIUS_NAME );
418 if( centerValue && centerValue->Get(center)
419 && radiusValue && radiusValue->Get(radius) )
421 mGradient = new RadialGradient( center, radius );
429 unsigned int numValidStop = 0u;
430 Property::Value* stopOffsetValue = propertyMap.Find( Toolkit::GradientVisual::Property::STOP_OFFSET, STOP_OFFSET_NAME );
431 Property::Value* stopColorValue = propertyMap.Find( Toolkit::GradientVisual::Property::STOP_COLOR, STOP_COLOR_NAME );
434 Vector<float> offsetArray;
435 Property::Array* colorArray = stopColorValue->GetArray();
438 GetStopOffsets( stopOffsetValue, offsetArray );
439 unsigned int numStop = offsetArray.Count() < colorArray->Count() ?
440 offsetArray.Count() : colorArray->Count();
442 for( unsigned int i=0; i<numStop; i++ )
444 if( (colorArray->GetElementAt(i)).Get(color) )
446 mGradient->AddStop( offsetArray[i], Vector4(color.r*color.a, color.g*color.a, color.b*color.a, color.a));
448 if( ! Equals( color.a, 1.0f, Math::MACHINE_EPSILON_1 ) )
457 if( numValidStop < 1u ) // no valid stop
462 Property::Value* spread = propertyMap.Find( Toolkit::GradientVisual::Property::SPREAD_METHOD, SPREAD_METHOD_NAME );
463 // The default spread method is PAD. Only need to set new spread if it's anything else.
466 Toolkit::GradientVisual::SpreadMethod::Type spreadMethod = Toolkit::GradientVisual::SpreadMethod::PAD;
467 if( Scripting::GetEnumerationProperty( *spread, SPREAD_METHOD_TABLE, SPREAD_METHOD_TABLE_COUNT, spreadMethod ) )
469 mGradient->SetSpreadMethod( spreadMethod );
476 void GradientVisual::GetStopOffsets(const Property::Value* value, Vector<float>& stopOffsets)
479 if ( value ) // Only check valve type if a valid Property has been passed in
481 switch ( value->GetType() )
483 case Property::VECTOR2:
486 value->Get( offset2 );
487 stopOffsets.PushBack( offset2.x );
488 stopOffsets.PushBack( offset2.y );
491 case Property::VECTOR3:
494 value->Get( offset3 );
495 stopOffsets.PushBack( offset3.x );
496 stopOffsets.PushBack( offset3.y );
497 stopOffsets.PushBack( offset3.z );
500 case Property::VECTOR4:
503 value->Get( offset4 );
504 stopOffsets.PushBack( offset4.x );
505 stopOffsets.PushBack( offset4.y );
506 stopOffsets.PushBack( offset4.z );
507 stopOffsets.PushBack( offset4.w );
510 case Property::ARRAY:
512 Property::Array* offsetArray = value->GetArray();
515 unsigned int numStop = offsetArray->Count();
517 for( unsigned int i=0; i<numStop; i++ )
519 if( offsetArray->GetElementAt(i).Get(offset) )
521 stopOffsets.PushBack( offset );
529 DALI_LOG_WARNING("GetStopOffsets passed unsupported Property Map\n");
535 if ( stopOffsets.Empty() )
537 // Set default offset if none set by Property system, need a minimum and maximum
538 stopOffsets.PushBack( DEFAULT_OFFSET_MINIMUM );
539 stopOffsets.PushBack( DEFAULT_OFFSET_MAXIMUM );
543 } // namespace Internal
545 } // namespace Toolkit