2 * Copyright (c) 2021 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/object/property-array.h>
26 #include <dali/devel-api/scripting/enum-helper.h>
27 #include <dali/devel-api/scripting/scripting.h>
28 #include <dali/devel-api/rendering/renderer-devel.h>
31 #include <dali-toolkit/public-api/visuals/gradient-visual-properties.h>
32 #include <dali-toolkit/public-api/visuals/visual-properties.h>
33 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
34 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
35 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
36 #include <dali-toolkit/internal/visuals/gradient/linear-gradient.h>
37 #include <dali-toolkit/internal/visuals/gradient/radial-gradient.h>
38 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
39 #include <dali-toolkit/internal/graphics/generated/gradient-visual-bounding-box-rounded-corner-shader-vert.h>
40 #include <dali-toolkit/internal/graphics/generated/gradient-visual-bounding-box-shader-vert.h>
41 #include <dali-toolkit/internal/graphics/generated/gradient-visual-linear-rounded-corner-shader-frag.h>
42 #include <dali-toolkit/internal/graphics/generated/gradient-visual-linear-shader-frag.h>
43 #include <dali-toolkit/internal/graphics/generated/gradient-visual-radial-rounded-corner-shader-frag.h>
44 #include <dali-toolkit/internal/graphics/generated/gradient-visual-radial-shader-frag.h>
45 #include <dali-toolkit/internal/graphics/generated/gradient-visual-user-space-rounded-corner-shader-vert.h>
46 #include <dali-toolkit/internal/graphics/generated/gradient-visual-user-space-shader-vert.h>
60 DALI_ENUM_TO_STRING_TABLE_BEGIN( UNITS )
61 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::Units, OBJECT_BOUNDING_BOX )
62 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::Units, USER_SPACE )
63 DALI_ENUM_TO_STRING_TABLE_END( UNITS )
65 DALI_ENUM_TO_STRING_TABLE_BEGIN( SPREAD_METHOD )
66 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::SpreadMethod, PAD )
67 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::SpreadMethod, REFLECT )
68 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::SpreadMethod, REPEAT )
69 DALI_ENUM_TO_STRING_TABLE_END( SPREAD_METHOD )
72 const char * const UNIFORM_ALIGNMENT_MATRIX_NAME( "uAlignmentMatrix" );
74 // default offset value
75 const unsigned int DEFAULT_OFFSET_MINIMUM = 0.0f;
76 const unsigned int DEFAULT_OFFSET_MAXIMUM = 1.0f;
78 VisualFactoryCache::ShaderType SHADER_TYPE_TABLE[][4] =
81 VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE,
82 VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX,
83 VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE_ROUNDED_CORNER,
84 VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX_ROUNDED_CORNER
87 VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE,
88 VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX,
89 VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE_ROUNDED_CORNER,
90 VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX_ROUNDED_CORNER
94 const std::string_view VERTEX_SHADER[] =
96 // vertex shader for gradient units as OBJECT_BOUNDING_BOX
97 SHADER_GRADIENT_VISUAL_BOUNDING_BOX_SHADER_VERT,
99 // vertex shader for gradient units as USER_SPACE
100 SHADER_GRADIENT_VISUAL_USER_SPACE_SHADER_VERT,
102 // vertex shader for gradient units as OBJECT_BOUNDING_BOX with corner radius
103 SHADER_GRADIENT_VISUAL_BOUNDING_BOX_ROUNDED_CORNER_SHADER_VERT,
105 // vertex shader for gradient units as USER_SPACE with corner radius
106 SHADER_GRADIENT_VISUAL_USER_SPACE_ROUNDED_CORNER_SHADER_VERT
109 const std::string_view FRAGMENT_SHADER[] =
111 // fragment shader for linear gradient
112 SHADER_GRADIENT_VISUAL_LINEAR_SHADER_FRAG,
114 // fragment shader for radial gradient
115 SHADER_GRADIENT_VISUAL_RADIAL_SHADER_FRAG,
117 // fragment shader for linear gradient with corner radius
118 SHADER_GRADIENT_VISUAL_LINEAR_ROUNDED_CORNER_SHADER_FRAG,
120 // fragment shader for radial gradient with corner radius
121 SHADER_GRADIENT_VISUAL_RADIAL_ROUNDED_CORNER_SHADER_FRAG
124 Dali::WrapMode::Type GetWrapMode( Toolkit::GradientVisual::SpreadMethod::Type spread )
128 case Toolkit::GradientVisual::SpreadMethod::REPEAT:
130 return Dali::WrapMode::REPEAT;
132 case Toolkit::GradientVisual::SpreadMethod::REFLECT:
134 return Dali::WrapMode::MIRRORED_REPEAT;
136 case Toolkit::GradientVisual::SpreadMethod::PAD:
139 return Dali::WrapMode::CLAMP_TO_EDGE;
144 } // unnamed namespace
146 GradientVisualPtr GradientVisual::New( VisualFactoryCache& factoryCache, const Property::Map& properties )
148 GradientVisualPtr gradientVisualPtr( new GradientVisual( factoryCache ) );
149 gradientVisualPtr->SetProperties( properties );
150 gradientVisualPtr->Initialize();
151 return gradientVisualPtr;
154 GradientVisual::GradientVisual( VisualFactoryCache& factoryCache )
155 : Visual::Base( factoryCache, Visual::FittingMode::FILL, Toolkit::Visual::GRADIENT ),
156 mGradientType( LINEAR ),
159 mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
162 GradientVisual::~GradientVisual()
166 void GradientVisual::DoSetProperties( const Property::Map& propertyMap )
168 Toolkit::GradientVisual::Units::Type gradientUnits = Toolkit::GradientVisual::Units::OBJECT_BOUNDING_BOX;
170 Property::Value* unitsValue = propertyMap.Find( Toolkit::GradientVisual::Property::UNITS, UNITS_NAME );
173 Scripting::GetEnumerationProperty( *unitsValue, UNITS_TABLE, UNITS_TABLE_COUNT, gradientUnits );
176 mGradientType = LINEAR;
177 if( propertyMap.Find( Toolkit::GradientVisual::Property::RADIUS, RADIUS_NAME ) )
179 mGradientType = RADIAL;
182 if( NewGradient( mGradientType, propertyMap ) )
184 mGradient->SetGradientUnits( gradientUnits );
185 mGradientTransform = mGradient->GetAlignmentTransform();
189 DALI_LOG_ERROR( "Fail to provide valid properties to create a GradientVisual object\n" );
193 void GradientVisual::OnSetTransform()
195 if( mImpl->mRenderer )
197 mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
201 void GradientVisual::DoSetOnScene( Actor& actor )
203 actor.AddRenderer( mImpl->mRenderer );
205 // Gradient Visual generated and ready to display
206 ResourceReady( Toolkit::Visual::ResourceStatus::READY );
209 void GradientVisual::UpdateShader()
213 Shader shader = GetShader();
214 mImpl->mRenderer.SetShader(shader);
218 void GradientVisual::DoCreatePropertyMap( Property::Map& map ) const
221 map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::GRADIENT );
222 map.Insert( Toolkit::GradientVisual::Property::UNITS, mGradient->GetGradientUnits() );
223 map.Insert( Toolkit::GradientVisual::Property::SPREAD_METHOD, mGradient->GetSpreadMethod() );
225 const Vector<Gradient::GradientStop>& stops( mGradient->GetStops() );
226 Property::Array offsets;
227 Property::Array colors;
228 for( unsigned int i=0; i<stops.Count(); i++ )
230 offsets.PushBack( stops[i].mOffset );
231 if( EqualsZero(stops[i].mStopColor.a) )
233 colors.PushBack( Vector4::ZERO );
237 colors.PushBack( Vector4( stops[i].mStopColor.r / stops[i].mStopColor.a,
238 stops[i].mStopColor.g / stops[i].mStopColor.a,
239 stops[i].mStopColor.b / stops[i].mStopColor.a,
240 stops[i].mStopColor.a));
244 map.Insert( Toolkit::GradientVisual::Property::STOP_OFFSET, offsets );
245 map.Insert( Toolkit::GradientVisual::Property::STOP_COLOR, colors );
247 if( &typeid( *mGradient ) == &typeid(LinearGradient) )
249 LinearGradient* gradient = static_cast<LinearGradient*>( mGradient.Get() );
250 map.Insert( Toolkit::GradientVisual::Property::START_POSITION, gradient->GetStartPosition() );
251 map.Insert( Toolkit::GradientVisual::Property::END_POSITION, gradient->GetEndPosition() );
253 else // if( &typeid( *mGradient ) == &typeid(RadialGradient) )
255 RadialGradient* gradient = static_cast<RadialGradient*>( mGradient.Get() );
256 map.Insert( Toolkit::GradientVisual::Property::CENTER, gradient->GetCenter() );
257 map.Insert( Toolkit::GradientVisual::Property::RADIUS, gradient->GetRadius() );
261 void GradientVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
266 void GradientVisual::OnInitialize()
268 Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
269 Shader shader = GetShader();
271 //Set up the texture set
272 TextureSet textureSet = TextureSet::New();
273 Dali::Texture lookupTexture = mGradient->GenerateLookupTexture();
274 textureSet.SetTexture( 0u, lookupTexture );
275 Dali::WrapMode::Type wrap = GetWrapMode( mGradient->GetSpreadMethod() );
276 Sampler sampler = Sampler::New();
277 sampler.SetWrapMode( wrap, wrap );
278 textureSet.SetSampler( 0u, sampler );
280 mImpl->mRenderer = Renderer::New( geometry, shader );
281 mImpl->mRenderer.SetTextures( textureSet );
283 // If opaque and then no need to have blending
286 mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::OFF );
289 mImpl->mRenderer.RegisterProperty( UNIFORM_ALIGNMENT_MATRIX_NAME, mGradientTransform );
291 //Register transform properties
292 mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
295 bool GradientVisual::NewGradient(Type gradientType, const Property::Map& propertyMap)
297 if( gradientType == LINEAR )
299 Property::Value* startPositionValue = propertyMap.Find( Toolkit::GradientVisual::Property::START_POSITION, START_POSITION_NAME );
300 Property::Value* endPositionValue = propertyMap.Find( Toolkit::GradientVisual::Property::END_POSITION, END_POSITION_NAME );
301 Vector2 startPosition;
304 if( startPositionValue && startPositionValue->Get(startPosition)
305 && endPositionValue && endPositionValue->Get( endPosition ) )
307 mGradient = new LinearGradient( startPosition, endPosition );
316 Property::Value* centerValue = propertyMap.Find( Toolkit::GradientVisual::Property::CENTER, CENTER_NAME );
317 Property::Value* radiusValue = propertyMap.Find( Toolkit::GradientVisual::Property::RADIUS, RADIUS_NAME );
320 if( centerValue && centerValue->Get(center)
321 && radiusValue && radiusValue->Get(radius) )
323 mGradient = new RadialGradient( center, radius );
331 unsigned int numValidStop = 0u;
332 Property::Value* stopOffsetValue = propertyMap.Find( Toolkit::GradientVisual::Property::STOP_OFFSET, STOP_OFFSET_NAME );
333 Property::Value* stopColorValue = propertyMap.Find( Toolkit::GradientVisual::Property::STOP_COLOR, STOP_COLOR_NAME );
336 Vector<float> offsetArray;
337 Property::Array* colorArray = stopColorValue->GetArray();
340 GetStopOffsets( stopOffsetValue, offsetArray );
341 unsigned int numStop = offsetArray.Count() < colorArray->Count() ?
342 offsetArray.Count() : colorArray->Count();
344 for( unsigned int i=0; i<numStop; i++ )
346 if( (colorArray->GetElementAt(i)).Get(color) )
348 mGradient->AddStop( offsetArray[i], Vector4(color.r*color.a, color.g*color.a, color.b*color.a, color.a));
350 if( ! Equals( color.a, 1.0f, Math::MACHINE_EPSILON_1 ) )
359 if( numValidStop < 1u ) // no valid stop
364 Property::Value* spread = propertyMap.Find( Toolkit::GradientVisual::Property::SPREAD_METHOD, SPREAD_METHOD_NAME );
365 // The default spread method is PAD. Only need to set new spread if it's anything else.
368 Toolkit::GradientVisual::SpreadMethod::Type spreadMethod = Toolkit::GradientVisual::SpreadMethod::PAD;
369 if( Scripting::GetEnumerationProperty( *spread, SPREAD_METHOD_TABLE, SPREAD_METHOD_TABLE_COUNT, spreadMethod ) )
371 mGradient->SetSpreadMethod( spreadMethod );
378 Shader GradientVisual::GetShader()
380 Toolkit::GradientVisual::Units::Type gradientUnits = mGradient->GetGradientUnits();
381 int roundedCorner = IsRoundedCornerRequired() ? 1 : 0;
382 VisualFactoryCache::ShaderType shaderType = SHADER_TYPE_TABLE[mGradientType][gradientUnits + roundedCorner * 2];
383 Shader shader = mFactoryCache.GetShader(shaderType);
386 shader = Shader::New(VERTEX_SHADER[gradientUnits + roundedCorner * 2], FRAGMENT_SHADER[mGradientType + roundedCorner * 2]);
387 mFactoryCache.SaveShader(shaderType, shader);
393 void GradientVisual::GetStopOffsets(const Property::Value* value, Vector<float>& stopOffsets)
396 if ( value ) // Only check valve type if a valid Property has been passed in
398 switch ( value->GetType() )
400 case Property::VECTOR2:
403 value->Get( offset2 );
404 stopOffsets.PushBack( offset2.x );
405 stopOffsets.PushBack( offset2.y );
408 case Property::VECTOR3:
411 value->Get( offset3 );
412 stopOffsets.PushBack( offset3.x );
413 stopOffsets.PushBack( offset3.y );
414 stopOffsets.PushBack( offset3.z );
417 case Property::VECTOR4:
420 value->Get( offset4 );
421 stopOffsets.PushBack( offset4.x );
422 stopOffsets.PushBack( offset4.y );
423 stopOffsets.PushBack( offset4.z );
424 stopOffsets.PushBack( offset4.w );
427 case Property::ARRAY:
429 const Property::Array* offsetArray = value->GetArray();
432 unsigned int numStop = offsetArray->Count();
434 for( unsigned int i=0; i<numStop; i++ )
436 if( offsetArray->GetElementAt(i).Get(offset) )
438 stopOffsets.PushBack( offset );
446 DALI_LOG_WARNING("GetStopOffsets passed unsupported Property Map\n");
452 if ( stopOffsets.Empty() )
454 // Set default offset if none set by Property system, need a minimum and maximum
455 stopOffsets.PushBack( DEFAULT_OFFSET_MINIMUM );
456 stopOffsets.PushBack( DEFAULT_OFFSET_MAXIMUM );
460 } // namespace Internal
462 } // namespace Toolkit