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"
22 #include <dali/devel-api/rendering/renderer-devel.h>
23 #include <dali/devel-api/scripting/enum-helper.h>
24 #include <dali/devel-api/scripting/scripting.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/public-api/common/dali-vector.h>
27 #include <dali/public-api/object/property-array.h>
31 #include <dali-toolkit/internal/graphics/generated/gradient-visual-bounding-box-rounded-corner-shader-vert.h>
32 #include <dali-toolkit/internal/graphics/generated/gradient-visual-bounding-box-shader-vert.h>
33 #include <dali-toolkit/internal/graphics/generated/gradient-visual-linear-rounded-corner-shader-frag.h>
34 #include <dali-toolkit/internal/graphics/generated/gradient-visual-linear-shader-frag.h>
35 #include <dali-toolkit/internal/graphics/generated/gradient-visual-radial-rounded-corner-shader-frag.h>
36 #include <dali-toolkit/internal/graphics/generated/gradient-visual-radial-shader-frag.h>
37 #include <dali-toolkit/internal/graphics/generated/gradient-visual-user-space-rounded-corner-shader-vert.h>
38 #include <dali-toolkit/internal/graphics/generated/gradient-visual-user-space-shader-vert.h>
39 #include <dali-toolkit/internal/visuals/gradient/linear-gradient.h>
40 #include <dali-toolkit/internal/visuals/gradient/radial-gradient.h>
41 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
42 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
43 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
44 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
45 #include <dali-toolkit/public-api/visuals/gradient-visual-properties.h>
46 #include <dali-toolkit/public-api/visuals/visual-properties.h>
56 DALI_ENUM_TO_STRING_TABLE_BEGIN(UNITS)
57 DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::GradientVisual::Units, OBJECT_BOUNDING_BOX)
58 DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::GradientVisual::Units, USER_SPACE)
59 DALI_ENUM_TO_STRING_TABLE_END(UNITS)
61 DALI_ENUM_TO_STRING_TABLE_BEGIN(SPREAD_METHOD)
62 DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::GradientVisual::SpreadMethod, PAD)
63 DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::GradientVisual::SpreadMethod, REFLECT)
64 DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::GradientVisual::SpreadMethod, REPEAT)
65 DALI_ENUM_TO_STRING_TABLE_END(SPREAD_METHOD)
68 const char* const UNIFORM_ALIGNMENT_MATRIX_NAME("uAlignmentMatrix");
70 // default offset value
71 const unsigned int DEFAULT_OFFSET_MINIMUM = 0.0f;
72 const unsigned int DEFAULT_OFFSET_MAXIMUM = 1.0f;
74 VisualFactoryCache::ShaderType SHADER_TYPE_TABLE[][4] =
76 {VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE,
77 VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX,
78 VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE_ROUNDED_CORNER,
79 VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX_ROUNDED_CORNER},
80 {VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE,
81 VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX,
82 VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE_ROUNDED_CORNER,
83 VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX_ROUNDED_CORNER}};
85 const std::string_view VERTEX_SHADER[] =
87 // vertex shader for gradient units as OBJECT_BOUNDING_BOX
88 SHADER_GRADIENT_VISUAL_BOUNDING_BOX_SHADER_VERT,
90 // vertex shader for gradient units as USER_SPACE
91 SHADER_GRADIENT_VISUAL_USER_SPACE_SHADER_VERT,
93 // vertex shader for gradient units as OBJECT_BOUNDING_BOX with corner radius
94 SHADER_GRADIENT_VISUAL_BOUNDING_BOX_ROUNDED_CORNER_SHADER_VERT,
96 // vertex shader for gradient units as USER_SPACE with corner radius
97 SHADER_GRADIENT_VISUAL_USER_SPACE_ROUNDED_CORNER_SHADER_VERT};
99 const std::string_view FRAGMENT_SHADER[] =
101 // fragment shader for linear gradient
102 SHADER_GRADIENT_VISUAL_LINEAR_SHADER_FRAG,
104 // fragment shader for radial gradient
105 SHADER_GRADIENT_VISUAL_RADIAL_SHADER_FRAG,
107 // fragment shader for linear gradient with corner radius
108 SHADER_GRADIENT_VISUAL_LINEAR_ROUNDED_CORNER_SHADER_FRAG,
110 // fragment shader for radial gradient with corner radius
111 SHADER_GRADIENT_VISUAL_RADIAL_ROUNDED_CORNER_SHADER_FRAG};
113 Dali::WrapMode::Type GetWrapMode(Toolkit::GradientVisual::SpreadMethod::Type spread)
117 case Toolkit::GradientVisual::SpreadMethod::REPEAT:
119 return Dali::WrapMode::REPEAT;
121 case Toolkit::GradientVisual::SpreadMethod::REFLECT:
123 return Dali::WrapMode::MIRRORED_REPEAT;
125 case Toolkit::GradientVisual::SpreadMethod::PAD:
128 return Dali::WrapMode::CLAMP_TO_EDGE;
133 } // unnamed namespace
135 GradientVisualPtr GradientVisual::New(VisualFactoryCache& factoryCache, const Property::Map& properties)
137 GradientVisualPtr gradientVisualPtr(new GradientVisual(factoryCache));
138 gradientVisualPtr->SetProperties(properties);
139 gradientVisualPtr->Initialize();
140 return gradientVisualPtr;
143 GradientVisual::GradientVisual(VisualFactoryCache& factoryCache)
144 : Visual::Base(factoryCache, Visual::FittingMode::FILL, Toolkit::Visual::GRADIENT),
145 mGradientType(LINEAR),
148 mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
151 GradientVisual::~GradientVisual()
155 void GradientVisual::DoSetProperties(const Property::Map& propertyMap)
157 Toolkit::GradientVisual::Units::Type gradientUnits = Toolkit::GradientVisual::Units::OBJECT_BOUNDING_BOX;
159 Property::Value* unitsValue = propertyMap.Find(Toolkit::GradientVisual::Property::UNITS, UNITS_NAME);
162 Scripting::GetEnumerationProperty(*unitsValue, UNITS_TABLE, UNITS_TABLE_COUNT, gradientUnits);
165 mGradientType = LINEAR;
166 if(propertyMap.Find(Toolkit::GradientVisual::Property::RADIUS, RADIUS_NAME))
168 mGradientType = RADIAL;
171 if(NewGradient(mGradientType, propertyMap))
173 mGradient->SetGradientUnits(gradientUnits);
174 mGradientTransform = mGradient->GetAlignmentTransform();
178 DALI_LOG_ERROR("Fail to provide valid properties to create a GradientVisual object\n");
182 void GradientVisual::OnSetTransform()
186 mImpl->mTransform.RegisterUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
190 void GradientVisual::DoSetOnScene(Actor& actor)
192 actor.AddRenderer(mImpl->mRenderer);
194 // Gradient Visual generated and ready to display
195 ResourceReady(Toolkit::Visual::ResourceStatus::READY);
198 void GradientVisual::UpdateShader()
202 Shader shader = GetShader();
203 mImpl->mRenderer.SetShader(shader);
207 void GradientVisual::DoCreatePropertyMap(Property::Map& map) const
210 map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::GRADIENT);
211 map.Insert(Toolkit::GradientVisual::Property::UNITS, mGradient->GetGradientUnits());
212 map.Insert(Toolkit::GradientVisual::Property::SPREAD_METHOD, mGradient->GetSpreadMethod());
214 const Vector<Gradient::GradientStop>& stops(mGradient->GetStops());
215 Property::Array offsets;
216 Property::Array colors;
217 for(unsigned int i = 0; i < stops.Count(); i++)
219 offsets.PushBack(stops[i].mOffset);
220 if(EqualsZero(stops[i].mStopColor.a))
222 colors.PushBack(Vector4::ZERO);
226 colors.PushBack(Vector4(stops[i].mStopColor.r / stops[i].mStopColor.a,
227 stops[i].mStopColor.g / stops[i].mStopColor.a,
228 stops[i].mStopColor.b / stops[i].mStopColor.a,
229 stops[i].mStopColor.a));
233 map.Insert(Toolkit::GradientVisual::Property::STOP_OFFSET, offsets);
234 map.Insert(Toolkit::GradientVisual::Property::STOP_COLOR, colors);
236 if(&typeid(*mGradient) == &typeid(LinearGradient))
238 LinearGradient* gradient = static_cast<LinearGradient*>(mGradient.Get());
239 map.Insert(Toolkit::GradientVisual::Property::START_POSITION, gradient->GetStartPosition());
240 map.Insert(Toolkit::GradientVisual::Property::END_POSITION, gradient->GetEndPosition());
242 else // if( &typeid( *mGradient ) == &typeid(RadialGradient) )
244 RadialGradient* gradient = static_cast<RadialGradient*>(mGradient.Get());
245 map.Insert(Toolkit::GradientVisual::Property::CENTER, gradient->GetCenter());
246 map.Insert(Toolkit::GradientVisual::Property::RADIUS, gradient->GetRadius());
250 void GradientVisual::DoCreateInstancePropertyMap(Property::Map& map) const
255 void GradientVisual::OnInitialize()
257 Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
258 Shader shader = GetShader();
260 //Set up the texture set
261 TextureSet textureSet = TextureSet::New();
262 Dali::Texture lookupTexture = mGradient->GenerateLookupTexture();
263 textureSet.SetTexture(0u, lookupTexture);
264 Dali::WrapMode::Type wrap = GetWrapMode(mGradient->GetSpreadMethod());
265 Sampler sampler = Sampler::New();
266 sampler.SetWrapMode(wrap, wrap);
267 textureSet.SetSampler(0u, sampler);
269 mImpl->mRenderer = Renderer::New(geometry, shader);
270 mImpl->mRenderer.SetTextures(textureSet);
272 // If opaque and then no need to have blending
275 mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::OFF);
278 mImpl->mRenderer.RegisterProperty(UNIFORM_ALIGNMENT_MATRIX_NAME, mGradientTransform);
280 //Register transform properties
281 mImpl->mTransform.RegisterUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
284 bool GradientVisual::NewGradient(Type gradientType, const Property::Map& propertyMap)
286 if(gradientType == LINEAR)
288 Property::Value* startPositionValue = propertyMap.Find(Toolkit::GradientVisual::Property::START_POSITION, START_POSITION_NAME);
289 Property::Value* endPositionValue = propertyMap.Find(Toolkit::GradientVisual::Property::END_POSITION, END_POSITION_NAME);
290 Vector2 startPosition;
293 if(startPositionValue && startPositionValue->Get(startPosition) && endPositionValue && endPositionValue->Get(endPosition))
295 mGradient = new LinearGradient(startPosition, endPosition);
304 Property::Value* centerValue = propertyMap.Find(Toolkit::GradientVisual::Property::CENTER, CENTER_NAME);
305 Property::Value* radiusValue = propertyMap.Find(Toolkit::GradientVisual::Property::RADIUS, RADIUS_NAME);
308 if(centerValue && centerValue->Get(center) && radiusValue && radiusValue->Get(radius))
310 mGradient = new RadialGradient(center, radius);
318 unsigned int numValidStop = 0u;
319 Property::Value* stopOffsetValue = propertyMap.Find(Toolkit::GradientVisual::Property::STOP_OFFSET, STOP_OFFSET_NAME);
320 Property::Value* stopColorValue = propertyMap.Find(Toolkit::GradientVisual::Property::STOP_COLOR, STOP_COLOR_NAME);
323 Vector<float> offsetArray;
324 Property::Array* colorArray = stopColorValue->GetArray();
327 GetStopOffsets(stopOffsetValue, offsetArray);
328 unsigned int numStop = offsetArray.Count() < colorArray->Count() ? offsetArray.Count() : colorArray->Count();
330 for(unsigned int i = 0; i < numStop; i++)
332 if((colorArray->GetElementAt(i)).Get(color))
334 mGradient->AddStop(offsetArray[i], Vector4(color.r * color.a, color.g * color.a, color.b * color.a, color.a));
336 if(!Equals(color.a, 1.0f, Math::MACHINE_EPSILON_1))
345 if(numValidStop < 1u) // no valid stop
350 Property::Value* spread = propertyMap.Find(Toolkit::GradientVisual::Property::SPREAD_METHOD, SPREAD_METHOD_NAME);
351 // The default spread method is PAD. Only need to set new spread if it's anything else.
354 Toolkit::GradientVisual::SpreadMethod::Type spreadMethod = Toolkit::GradientVisual::SpreadMethod::PAD;
355 if(Scripting::GetEnumerationProperty(*spread, SPREAD_METHOD_TABLE, SPREAD_METHOD_TABLE_COUNT, spreadMethod))
357 mGradient->SetSpreadMethod(spreadMethod);
364 Shader GradientVisual::GetShader()
366 Toolkit::GradientVisual::Units::Type gradientUnits = mGradient->GetGradientUnits();
367 int roundedCorner = IsRoundedCornerRequired() ? 1 : 0;
368 VisualFactoryCache::ShaderType shaderType = SHADER_TYPE_TABLE[mGradientType][gradientUnits + roundedCorner * 2];
369 Shader shader = mFactoryCache.GetShader(shaderType);
372 shader = Shader::New(VERTEX_SHADER[gradientUnits + roundedCorner * 2], FRAGMENT_SHADER[mGradientType + roundedCorner * 2]);
373 mFactoryCache.SaveShader(shaderType, shader);
379 void GradientVisual::GetStopOffsets(const Property::Value* value, Vector<float>& stopOffsets)
381 if(value) // Only check valve type if a valid Property has been passed in
383 switch(value->GetType())
385 case Property::VECTOR2:
389 stopOffsets.PushBack(offset2.x);
390 stopOffsets.PushBack(offset2.y);
393 case Property::VECTOR3:
397 stopOffsets.PushBack(offset3.x);
398 stopOffsets.PushBack(offset3.y);
399 stopOffsets.PushBack(offset3.z);
402 case Property::VECTOR4:
406 stopOffsets.PushBack(offset4.x);
407 stopOffsets.PushBack(offset4.y);
408 stopOffsets.PushBack(offset4.z);
409 stopOffsets.PushBack(offset4.w);
412 case Property::ARRAY:
414 const Property::Array* offsetArray = value->GetArray();
417 unsigned int numStop = offsetArray->Count();
419 for(unsigned int i = 0; i < numStop; i++)
421 if(offsetArray->GetElementAt(i).Get(offset))
423 stopOffsets.PushBack(offset);
431 DALI_LOG_WARNING("GetStopOffsets passed unsupported Property Map\n");
437 if(stopOffsets.Empty())
439 // Set default offset if none set by Property system, need a minimum and maximum
440 stopOffsets.PushBack(DEFAULT_OFFSET_MINIMUM);
441 stopOffsets.PushBack(DEFAULT_OFFSET_MAXIMUM);
445 } // namespace Internal
447 } // namespace Toolkit