Merge "Fix bug when we use bitmap font." into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / gradient / gradient-visual.cpp
1 /*
2  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include "gradient-visual.h"
20
21 // EXTERNAL INCLUDES
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>
28 #include <dali/public-api/rendering/decorated-visual-renderer.h>
29 #include <typeinfo>
30
31 // INTERNAL INCLUDES
32 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
33 #include <dali-toolkit/internal/visuals/gradient/linear-gradient.h>
34 #include <dali-toolkit/internal/visuals/gradient/radial-gradient.h>
35 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
36 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
37 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
38 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
39 #include <dali-toolkit/public-api/visuals/gradient-visual-properties.h>
40 #include <dali-toolkit/public-api/visuals/visual-properties.h>
41
42 namespace Dali
43 {
44 namespace Toolkit
45 {
46 namespace Internal
47 {
48 namespace
49 {
50 const int CUSTOM_PROPERTY_COUNT(1); // alignment
51
52 DALI_ENUM_TO_STRING_TABLE_BEGIN(UNITS)
53   DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::GradientVisual::Units, OBJECT_BOUNDING_BOX)
54   DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::GradientVisual::Units, USER_SPACE)
55 DALI_ENUM_TO_STRING_TABLE_END(UNITS)
56
57 DALI_ENUM_TO_STRING_TABLE_BEGIN(SPREAD_METHOD)
58   DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::GradientVisual::SpreadMethod, PAD)
59   DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::GradientVisual::SpreadMethod, REFLECT)
60   DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::GradientVisual::SpreadMethod, REPEAT)
61 DALI_ENUM_TO_STRING_TABLE_END(SPREAD_METHOD)
62
63 // uniform names
64 const char* const UNIFORM_ALIGNMENT_MATRIX_NAME("uAlignmentMatrix");
65
66 // default offset value
67 const unsigned int DEFAULT_OFFSET_MINIMUM = 0.0f;
68 const unsigned int DEFAULT_OFFSET_MAXIMUM = 1.0f;
69
70 VisualFactoryCache::ShaderType SHADER_TYPE_TABLE[16] =
71   {
72     VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX,
73     VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX_ROUNDED_CORNER,
74     VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX_BORDERLINE,
75     VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX_ROUNDED_BORDERLINE,
76     VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE,
77     VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE_ROUNDED_CORNER,
78     VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE_BORDERLINE,
79     VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE_ROUNDED_BORDERLINE,
80     VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX,
81     VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX_ROUNDED_CORNER,
82     VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX_BORDERLINE,
83     VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX_ROUNDED_BORDERLINE,
84     VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE,
85     VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE_ROUNDED_CORNER,
86     VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE_BORDERLINE,
87     VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE_ROUNDED_BORDERLINE,
88 };
89
90 // enum of required list when we select shader
91 enum GradientVisualRequireFlag
92 {
93   DEFAULT        = 0,
94   ROUNDED_CORNER = 1 << 0,
95   BORDERLINE     = 1 << 1,
96   USER_SPACE     = 1 << 2,
97   RADIAL         = 1 << 3,
98 };
99
100 Dali::WrapMode::Type GetWrapMode(Toolkit::GradientVisual::SpreadMethod::Type spread)
101 {
102   switch(spread)
103   {
104     case Toolkit::GradientVisual::SpreadMethod::REPEAT:
105     {
106       return Dali::WrapMode::REPEAT;
107     }
108     case Toolkit::GradientVisual::SpreadMethod::REFLECT:
109     {
110       return Dali::WrapMode::MIRRORED_REPEAT;
111     }
112     case Toolkit::GradientVisual::SpreadMethod::PAD:
113     default:
114     {
115       return Dali::WrapMode::CLAMP_TO_EDGE;
116     }
117   }
118 }
119
120 } // unnamed namespace
121
122 GradientVisualPtr GradientVisual::New(VisualFactoryCache& factoryCache, const Property::Map& properties)
123 {
124   GradientVisualPtr gradientVisualPtr(new GradientVisual(factoryCache));
125   gradientVisualPtr->SetProperties(properties);
126   gradientVisualPtr->Initialize();
127   return gradientVisualPtr;
128 }
129
130 GradientVisual::GradientVisual(VisualFactoryCache& factoryCache)
131 : Visual::Base(factoryCache, Visual::FittingMode::FILL, Toolkit::Visual::GRADIENT),
132   mGradientType(LINEAR),
133   mIsOpaque(true)
134 {
135   mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
136 }
137
138 GradientVisual::~GradientVisual()
139 {
140 }
141
142 void GradientVisual::DoSetProperties(const Property::Map& propertyMap)
143 {
144   Toolkit::GradientVisual::Units::Type gradientUnits = Toolkit::GradientVisual::Units::OBJECT_BOUNDING_BOX;
145
146   Property::Value* unitsValue = propertyMap.Find(Toolkit::GradientVisual::Property::UNITS, UNITS_NAME);
147   if(unitsValue)
148   {
149     Scripting::GetEnumerationProperty(*unitsValue, UNITS_TABLE, UNITS_TABLE_COUNT, gradientUnits);
150   }
151
152   mGradientType = Type::LINEAR;
153   if(propertyMap.Find(Toolkit::GradientVisual::Property::RADIUS, RADIUS_NAME))
154   {
155     mGradientType = Type::RADIAL;
156   }
157
158   if(NewGradient(mGradientType, propertyMap))
159   {
160     mGradient->SetGradientUnits(gradientUnits);
161     mGradientTransform = mGradient->GetAlignmentTransform();
162   }
163   else
164   {
165     DALI_LOG_ERROR("Fail to provide valid properties to create a GradientVisual object\n");
166   }
167 }
168
169 void GradientVisual::OnSetTransform()
170 {
171   if(mImpl->mRenderer)
172   {
173     mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
174   }
175 }
176
177 void GradientVisual::DoSetOnScene(Actor& actor)
178 {
179   actor.AddRenderer(mImpl->mRenderer);
180
181   // Gradient Visual generated and ready to display
182   ResourceReady(Toolkit::Visual::ResourceStatus::READY);
183 }
184
185 void GradientVisual::UpdateShader()
186 {
187   if(mImpl->mRenderer)
188   {
189     Shader shader = GenerateShader();
190     mImpl->mRenderer.SetShader(shader);
191   }
192 }
193
194 void GradientVisual::DoCreatePropertyMap(Property::Map& map) const
195 {
196   map.Clear();
197   map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::GRADIENT);
198   map.Insert(Toolkit::GradientVisual::Property::UNITS, mGradient->GetGradientUnits());
199   map.Insert(Toolkit::GradientVisual::Property::SPREAD_METHOD, mGradient->GetSpreadMethod());
200
201   const Vector<Gradient::GradientStop>& stops(mGradient->GetStops());
202   Property::Array                       offsets;
203   Property::Array                       colors;
204   for(unsigned int i = 0; i < stops.Count(); i++)
205   {
206     offsets.PushBack(stops[i].mOffset);
207     if(EqualsZero(stops[i].mStopColor.a))
208     {
209       colors.PushBack(Vector4::ZERO);
210     }
211     else
212     {
213       colors.PushBack(Vector4(stops[i].mStopColor.r / stops[i].mStopColor.a,
214                               stops[i].mStopColor.g / stops[i].mStopColor.a,
215                               stops[i].mStopColor.b / stops[i].mStopColor.a,
216                               stops[i].mStopColor.a));
217     }
218   }
219
220   map.Insert(Toolkit::GradientVisual::Property::STOP_OFFSET, offsets);
221   map.Insert(Toolkit::GradientVisual::Property::STOP_COLOR, colors);
222
223   if(&typeid(*mGradient) == &typeid(LinearGradient))
224   {
225     LinearGradient* gradient = static_cast<LinearGradient*>(mGradient.Get());
226     map.Insert(Toolkit::GradientVisual::Property::START_POSITION, gradient->GetStartPosition());
227     map.Insert(Toolkit::GradientVisual::Property::END_POSITION, gradient->GetEndPosition());
228   }
229   else // if( &typeid( *mGradient ) == &typeid(RadialGradient) )
230   {
231     RadialGradient* gradient = static_cast<RadialGradient*>(mGradient.Get());
232     map.Insert(Toolkit::GradientVisual::Property::CENTER, gradient->GetCenter());
233     map.Insert(Toolkit::GradientVisual::Property::RADIUS, gradient->GetRadius());
234   }
235 }
236
237 void GradientVisual::DoCreateInstancePropertyMap(Property::Map& map) const
238 {
239   // Do nothing
240 }
241
242 void GradientVisual::EnablePreMultipliedAlpha(bool preMultiplied)
243 {
244   // Make always enable pre multiplied alpha whether preMultiplied value is false.
245   if(!preMultiplied)
246   {
247     DALI_LOG_WARNING("Note : GradientVisual cannot disable PreMultipliedAlpha\n");
248   }
249 }
250
251 void GradientVisual::OnInitialize()
252 {
253   Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
254   Shader   shader   = GenerateShader();
255
256   //Set up the texture set
257   TextureSet    textureSet    = TextureSet::New();
258   Dali::Texture lookupTexture = mGradient->GenerateLookupTexture();
259   textureSet.SetTexture(0u, lookupTexture);
260   Dali::WrapMode::Type wrap    = GetWrapMode(mGradient->GetSpreadMethod());
261   Sampler              sampler = Sampler::New();
262   sampler.SetWrapMode(wrap, wrap);
263   textureSet.SetSampler(0u, sampler);
264
265   mImpl->mRenderer = DecoratedVisualRenderer::New(geometry, shader);
266   mImpl->mRenderer.ReserveCustomProperties(CUSTOM_PROPERTY_COUNT);
267   mImpl->mRenderer.SetTextures(textureSet);
268
269   // If opaque and then no need to have blending
270   if(mIsOpaque)
271   {
272     mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::OFF);
273   }
274
275   mImpl->mRenderer.RegisterUniqueProperty(UNIFORM_ALIGNMENT_MATRIX_NAME, mGradientTransform);
276
277   //Register transform properties
278   mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
279 }
280
281 bool GradientVisual::NewGradient(Type gradientType, const Property::Map& propertyMap)
282 {
283   if(gradientType == Type::LINEAR)
284   {
285     Property::Value* startPositionValue = propertyMap.Find(Toolkit::GradientVisual::Property::START_POSITION, START_POSITION_NAME);
286     Property::Value* endPositionValue   = propertyMap.Find(Toolkit::GradientVisual::Property::END_POSITION, END_POSITION_NAME);
287     Vector2          startPosition;
288     Vector2          endPosition;
289
290     if(startPositionValue && startPositionValue->Get(startPosition) && endPositionValue && endPositionValue->Get(endPosition))
291     {
292       mGradient = new LinearGradient(startPosition, endPosition);
293     }
294     else
295     {
296       return false;
297     }
298   }
299   else // type==Type::RADIAL
300   {
301     Property::Value* centerValue = propertyMap.Find(Toolkit::GradientVisual::Property::CENTER, CENTER_NAME);
302     Property::Value* radiusValue = propertyMap.Find(Toolkit::GradientVisual::Property::RADIUS, RADIUS_NAME);
303     Vector2          center;
304     float            radius;
305     if(centerValue && centerValue->Get(center) && radiusValue && radiusValue->Get(radius))
306     {
307       mGradient = new RadialGradient(center, radius);
308     }
309     else
310     {
311       return false;
312     }
313   }
314
315   unsigned int     numValidStop    = 0u;
316   Property::Value* stopOffsetValue = propertyMap.Find(Toolkit::GradientVisual::Property::STOP_OFFSET, STOP_OFFSET_NAME);
317   Property::Value* stopColorValue  = propertyMap.Find(Toolkit::GradientVisual::Property::STOP_COLOR, STOP_COLOR_NAME);
318   if(stopColorValue)
319   {
320     Vector<float>    offsetArray;
321     Property::Array* colorArray = stopColorValue->GetArray();
322     if(colorArray)
323     {
324       GetStopOffsets(stopOffsetValue, offsetArray);
325       unsigned int numStop = offsetArray.Count() < colorArray->Count() ? offsetArray.Count() : colorArray->Count();
326       Vector4      color;
327       for(unsigned int i = 0; i < numStop; i++)
328       {
329         if((colorArray->GetElementAt(i)).Get(color))
330         {
331           mGradient->AddStop(offsetArray[i], Vector4(color.r * color.a, color.g * color.a, color.b * color.a, color.a));
332           numValidStop++;
333           if(!Equals(color.a, 1.0f, Math::MACHINE_EPSILON_1))
334           {
335             mIsOpaque = false;
336           }
337         }
338       }
339     }
340   }
341
342   if(numValidStop < 1u) // no valid stop
343   {
344     return false;
345   }
346
347   Property::Value* spread = propertyMap.Find(Toolkit::GradientVisual::Property::SPREAD_METHOD, SPREAD_METHOD_NAME);
348   // The default spread method is PAD. Only need to set new spread if it's anything else.
349   if(spread)
350   {
351     Toolkit::GradientVisual::SpreadMethod::Type spreadMethod = Toolkit::GradientVisual::SpreadMethod::PAD;
352     if(Scripting::GetEnumerationProperty(*spread, SPREAD_METHOD_TABLE, SPREAD_METHOD_TABLE_COUNT, spreadMethod))
353     {
354       mGradient->SetSpreadMethod(spreadMethod);
355     }
356   }
357
358   return true;
359 }
360
361 Shader GradientVisual::GenerateShader() const
362 {
363   bool userspaceUnit  = (mGradient->GetGradientUnits() == Toolkit::GradientVisual::Units::USER_SPACE);
364   bool roundedCorner  = IsRoundedCornerRequired();
365   bool borderline     = IsBorderlineRequired();
366   bool radialGradient = (mGradientType == Type::RADIAL);
367
368   int shaderTypeFlag = GradientVisualRequireFlag::DEFAULT;
369   if(roundedCorner)
370   {
371     shaderTypeFlag |= GradientVisualRequireFlag::ROUNDED_CORNER;
372   }
373   if(borderline)
374   {
375     shaderTypeFlag |= GradientVisualRequireFlag::BORDERLINE;
376   }
377   if(userspaceUnit)
378   {
379     shaderTypeFlag |= GradientVisualRequireFlag::USER_SPACE;
380   }
381   if(radialGradient)
382   {
383     shaderTypeFlag |= GradientVisualRequireFlag::RADIAL;
384   }
385
386   VisualFactoryCache::ShaderType shaderType = SHADER_TYPE_TABLE[shaderTypeFlag];
387   Shader                         shader     = mFactoryCache.GetShader(shaderType);
388   if(!shader)
389   {
390     std::string vertexShaderPrefixList;
391     std::string fragmentShaderPrefixList;
392
393     if(roundedCorner)
394     {
395       vertexShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER\n";
396       fragmentShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER\n";
397     }
398     if(borderline)
399     {
400       vertexShaderPrefixList += "#define IS_REQUIRED_BORDERLINE\n";
401       fragmentShaderPrefixList += "#define IS_REQUIRED_BORDERLINE\n";
402     }
403     if(radialGradient)
404     {
405       fragmentShaderPrefixList += "#define RADIAL\n";
406     }
407     if(userspaceUnit)
408     {
409       vertexShaderPrefixList += "#define USER_SPACE\n";
410     }
411
412     shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + vertexShaderPrefixList + SHADER_GRADIENT_VISUAL_SHADER_VERT.data(),
413                          Dali::Shader::GetFragmentShaderPrefix() + fragmentShaderPrefixList + SHADER_GRADIENT_VISUAL_SHADER_FRAG.data());
414     mFactoryCache.SaveShader(shaderType, shader);
415   }
416
417   return shader;
418 }
419
420 void GradientVisual::GetStopOffsets(const Property::Value* value, Vector<float>& stopOffsets)
421 {
422   if(value) // Only check valve type if a valid Property has been passed in
423   {
424     switch(value->GetType())
425     {
426       case Property::VECTOR2:
427       {
428         Vector2 offset2;
429         value->Get(offset2);
430         stopOffsets.PushBack(offset2.x);
431         stopOffsets.PushBack(offset2.y);
432         break;
433       }
434       case Property::VECTOR3:
435       {
436         Vector3 offset3;
437         value->Get(offset3);
438         stopOffsets.PushBack(offset3.x);
439         stopOffsets.PushBack(offset3.y);
440         stopOffsets.PushBack(offset3.z);
441         break;
442       }
443       case Property::VECTOR4:
444       {
445         Vector4 offset4;
446         value->Get(offset4);
447         stopOffsets.PushBack(offset4.x);
448         stopOffsets.PushBack(offset4.y);
449         stopOffsets.PushBack(offset4.z);
450         stopOffsets.PushBack(offset4.w);
451         break;
452       }
453       case Property::ARRAY:
454       {
455         const Property::Array* offsetArray = value->GetArray();
456         if(offsetArray)
457         {
458           unsigned int numStop = offsetArray->Count();
459           float        offset;
460           for(unsigned int i = 0; i < numStop; i++)
461           {
462             if(offsetArray->GetElementAt(i).Get(offset))
463             {
464               stopOffsets.PushBack(offset);
465             }
466           }
467         }
468         break;
469       }
470       default:
471       {
472         DALI_LOG_WARNING("GetStopOffsets passed unsupported Property Map\n");
473         // Unsupported Type
474       }
475     }
476   }
477
478   if(stopOffsets.Empty())
479   {
480     // Set default offset if none set by Property system, need a minimum and maximum
481     stopOffsets.PushBack(DEFAULT_OFFSET_MINIMUM);
482     stopOffsets.PushBack(DEFAULT_OFFSET_MAXIMUM);
483   }
484 }
485
486 } // namespace Internal
487
488 } // namespace Toolkit
489
490 } // namespace Dali