BlendMode::ON_WITHOUT_CULL bug fix
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / visual-base-data-impl.cpp
1 /*
2  * Copyright (c) 2021 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 <dali-toolkit/internal/visuals/visual-base-data-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali-toolkit/public-api/dali-toolkit-common.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
27 // INTERNAL INCLUDES
28 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
29 #include <dali-toolkit/internal/helpers/property-helper.h>
30 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
31 #include <dali-toolkit/public-api/visuals/visual-properties.h>
32
33 namespace Dali
34 {
35 namespace Toolkit
36 {
37 namespace Internal
38 {
39 namespace
40 {
41 DALI_ENUM_TO_STRING_TABLE_BEGIN(SHADER_HINT)
42   DALI_ENUM_TO_STRING_WITH_SCOPE(Shader::Hint, NONE)
43   DALI_ENUM_TO_STRING_WITH_SCOPE(Shader::Hint, OUTPUT_IS_TRANSPARENT)
44   DALI_ENUM_TO_STRING_WITH_SCOPE(Shader::Hint, MODIFIES_GEOMETRY)
45 DALI_ENUM_TO_STRING_TABLE_END(SHADER_HINT)
46
47 DALI_ENUM_TO_STRING_TABLE_BEGIN(ALIGN)
48   DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Align, TOP_BEGIN)
49   DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Align, TOP_CENTER)
50   DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Align, TOP_END)
51   DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Align, CENTER_BEGIN)
52   DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Align, CENTER)
53   DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Align, CENTER_END)
54   DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Align, BOTTOM_BEGIN)
55   DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Align, BOTTOM_CENTER)
56   DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Align, BOTTOM_END)
57 DALI_ENUM_TO_STRING_TABLE_END(ALIGN)
58
59 DALI_ENUM_TO_STRING_TABLE_BEGIN(POLICY)
60   DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Visual::Transform::Policy, RELATIVE)
61   DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Visual::Transform::Policy, ABSOLUTE)
62 DALI_ENUM_TO_STRING_TABLE_END(POLICY)
63
64 Dali::Vector2 PointToVector2(Toolkit::Align::Type point, Toolkit::Direction::Type direction)
65 {
66   // clang-format off
67   static const float pointToVector2[] = {0.0f,0.0f,
68                                          0.5f,0.0f,
69                                          1.0f,0.0f,
70                                          0.0f,0.5f,
71                                          0.5f,0.5f,
72                                          1.0f,0.5f,
73                                          0.0f,1.0f,
74                                          0.5f,1.0f,
75                                          1.0f,1.0f};
76   // clang-format on
77
78   Vector2 result(&pointToVector2[point * 2]);
79   if(direction == Direction::RIGHT_TO_LEFT)
80   {
81     result.x = 1.0f - result.x;
82   }
83
84   return result;
85 }
86
87 bool GetPolicyFromValue(const Property::Value& value, Vector2& policy)
88 {
89   bool success = false;
90   if(value.Get(policy))
91   {
92     success = true;
93   }
94   else
95   {
96     const Property::Array* array = value.GetArray();
97     if(array && array->Size() == 2)
98     {
99       Toolkit::Visual::Transform::Policy::Type xPolicy = static_cast<Toolkit::Visual::Transform::Policy::Type>(-1); // Assign an invalid value so definitely changes
100       Toolkit::Visual::Transform::Policy::Type yPolicy = static_cast<Toolkit::Visual::Transform::Policy::Type>(-1); // Assign an invalid value so definitely changes
101
102       if(Scripting::GetEnumerationProperty<Toolkit::Visual::Transform::Policy::Type>(array->GetElementAt(0), POLICY_TABLE, POLICY_TABLE_COUNT, xPolicy) &&
103          Scripting::GetEnumerationProperty<Toolkit::Visual::Transform::Policy::Type>(array->GetElementAt(1), POLICY_TABLE, POLICY_TABLE_COUNT, yPolicy))
104       {
105         policy.x = xPolicy;
106         policy.y = yPolicy;
107         success  = true;
108       }
109     }
110   }
111   return success;
112 }
113
114 } // unnamed namespace
115
116 Internal::Visual::Base::Impl::Impl(FittingMode fittingMode, Toolkit::Visual::Type type)
117 : mCustomShader(NULL),
118   mEventObserver(NULL),
119   mTransform(),
120   mMixColor(Color::WHITE),
121   mControlSize(Vector2::ZERO),
122   mBorderlineWidth(0.0f),
123   mBorderlineColor(Color::BLACK),
124   mBorderlineOffset(0.0f),
125   mCornerRadius(Vector4::ZERO),
126   mCornerRadiusPolicy(1.0f),
127   mDepthIndex(0.0f),
128   mMixColorIndex(Property::INVALID_INDEX),
129   mBorderlineWidthIndex(Property::INVALID_INDEX),
130   mBorderlineColorIndex(Property::INVALID_INDEX),
131   mBorderlineOffsetIndex(Property::INVALID_INDEX),
132   mCornerRadiusIndex(Property::INVALID_INDEX),
133   mFittingMode(fittingMode),
134   mFlags(0),
135   mResourceStatus(Toolkit::Visual::ResourceStatus::PREPARING),
136   mType(type),
137   mAlwaysUsingBorderline(false),
138   mAlwaysUsingCornerRadius(false)
139 {
140 }
141
142 Internal::Visual::Base::Impl::~Impl()
143 {
144   delete mCustomShader;
145 }
146
147 Internal::Visual::Base::Impl::CustomShader::CustomShader(const Property::Map& map)
148 : mGridSize(1, 1),
149   mHints(Shader::Hint::NONE)
150 {
151   SetPropertyMap(map);
152 }
153
154 void Internal::Visual::Base::Impl::CustomShader::SetPropertyMap(const Property::Map& shaderMap)
155 {
156   mVertexShader.clear();
157   mFragmentShader.clear();
158   mGridSize = ImageDimensions(1, 1);
159   mHints    = Shader::Hint::NONE;
160
161   Property::Value* vertexShaderValue = shaderMap.Find(Toolkit::Visual::Shader::Property::VERTEX_SHADER, CUSTOM_VERTEX_SHADER);
162   if(vertexShaderValue)
163   {
164     if(!GetStringFromProperty(*vertexShaderValue, mVertexShader))
165     {
166       DALI_LOG_ERROR("'%s' parameter does not correctly specify a string\n", CUSTOM_VERTEX_SHADER);
167     }
168   }
169
170   Property::Value* fragmentShaderValue = shaderMap.Find(Toolkit::Visual::Shader::Property::FRAGMENT_SHADER, CUSTOM_FRAGMENT_SHADER);
171   if(fragmentShaderValue)
172   {
173     if(!GetStringFromProperty(*fragmentShaderValue, mFragmentShader))
174     {
175       DALI_LOG_ERROR("'%s' parameter does not correctly specify a string\n", CUSTOM_FRAGMENT_SHADER);
176     }
177   }
178
179   Property::Value* subdivideXValue = shaderMap.Find(Toolkit::Visual::Shader::Property::SUBDIVIDE_GRID_X, CUSTOM_SUBDIVIDE_GRID_X);
180   if(subdivideXValue)
181   {
182     int subdivideX;
183     if(!subdivideXValue->Get(subdivideX) || subdivideX < 1)
184     {
185       DALI_LOG_ERROR("'%s' parameter does not correctly specify a value greater than 1\n", CUSTOM_SUBDIVIDE_GRID_X);
186     }
187     else
188     {
189       mGridSize = ImageDimensions(subdivideX, mGridSize.GetY());
190     }
191   }
192
193   Property::Value* subdivideYValue = shaderMap.Find(Toolkit::Visual::Shader::Property::SUBDIVIDE_GRID_Y, CUSTOM_SUBDIVIDE_GRID_Y);
194   if(subdivideYValue)
195   {
196     int subdivideY;
197     if(!subdivideYValue->Get(subdivideY) || subdivideY < 1)
198     {
199       DALI_LOG_ERROR("'%s' parameter does not correctly specify a value greater than 1\n", CUSTOM_SUBDIVIDE_GRID_Y);
200     }
201     else
202     {
203       mGridSize = ImageDimensions(mGridSize.GetX(), subdivideY);
204     }
205   }
206
207   Property::Value* hintsValue = shaderMap.Find(Toolkit::Visual::Shader::Property::HINTS, CUSTOM_SHADER_HINTS);
208   if(hintsValue)
209   {
210     if(!Scripting::GetBitmaskEnumerationProperty(*hintsValue, SHADER_HINT_TABLE, SHADER_HINT_TABLE_COUNT, mHints))
211     {
212       DALI_LOG_ERROR("'%s' parameter does not correctly specify a hint or an array of hint strings\n", CUSTOM_SHADER_HINTS);
213     }
214   }
215 }
216
217 void Internal::Visual::Base::Impl::CustomShader::CreatePropertyMap(Property::Map& map) const
218 {
219   if(!mVertexShader.empty() || !mFragmentShader.empty())
220   {
221     Property::Map customShader;
222     if(!mVertexShader.empty())
223     {
224       customShader.Insert(Toolkit::Visual::Shader::Property::VERTEX_SHADER, mVertexShader);
225     }
226     if(!mFragmentShader.empty())
227     {
228       customShader.Insert(Toolkit::Visual::Shader::Property::FRAGMENT_SHADER, mFragmentShader);
229     }
230
231     if(mGridSize.GetWidth() != 1)
232     {
233       customShader.Insert(Toolkit::Visual::Shader::Property::SUBDIVIDE_GRID_X, mGridSize.GetWidth());
234     }
235     if(mGridSize.GetHeight() != 1)
236     {
237       customShader.Insert(Toolkit::Visual::Shader::Property::SUBDIVIDE_GRID_Y, mGridSize.GetHeight());
238     }
239
240     if(mHints != Dali::Shader::Hint::NONE)
241     {
242       customShader.Insert(Toolkit::Visual::Shader::Property::HINTS, static_cast<int>(mHints));
243     }
244
245     map.Insert(Toolkit::Visual::Property::SHADER, customShader);
246   }
247 }
248
249 Internal::Visual::Base::Impl::Transform::Transform()
250 : mOffset(0.0f, 0.0f),
251   mSize(1.0f, 1.0f),
252   mExtraSize(0.0f, 0.0f),
253   mOffsetSizeMode(0.0f, 0.0f, 0.0f, 0.0f),
254   mOrigin(Toolkit::Align::TOP_BEGIN),
255   mAnchorPoint(Toolkit::Align::TOP_BEGIN),
256   mOffsetIndex(Property::INVALID_INDEX),
257   mSizeIndex(Property::INVALID_INDEX)
258 {
259 }
260
261 void Internal::Visual::Base::Impl::Transform::SetPropertyMap(const Property::Map& map)
262 {
263   // Set default values
264   mOffset         = Vector2(0.0f, 0.0f);
265   mSize           = Vector2(1.0f, 1.0f);
266   mExtraSize      = Vector2(0.0f, 0.0f);
267   mOffsetSizeMode = Vector4(0.0f, 0.0f, 0.0f, 0.0f);
268   mOrigin         = Toolkit::Align::TOP_BEGIN;
269   mAnchorPoint    = Toolkit::Align::TOP_BEGIN;
270
271   UpdatePropertyMap(map);
272 }
273
274 void Internal::Visual::Base::Impl::Transform::UpdatePropertyMap(const Property::Map& map)
275 {
276   for(Property::Map::SizeType i(0); i < map.Count(); ++i)
277   {
278     KeyValuePair keyValue = map.GetKeyValue(i);
279     if(keyValue.first.type == Property::Key::INDEX)
280     {
281       switch(keyValue.first.indexKey)
282       {
283         case Toolkit::Visual::Transform::Property::OFFSET:
284         {
285           keyValue.second.Get(mOffset);
286           break;
287         }
288         case Toolkit::Visual::Transform::Property::SIZE:
289         {
290           keyValue.second.Get(mSize);
291           break;
292         }
293         case Toolkit::Visual::Transform::Property::ORIGIN:
294         {
295           Scripting::GetEnumerationProperty<Toolkit::Align::Type>(keyValue.second, ALIGN_TABLE, ALIGN_TABLE_COUNT, mOrigin);
296           break;
297         }
298         case Toolkit::Visual::Transform::Property::ANCHOR_POINT:
299         {
300           Scripting::GetEnumerationProperty<Toolkit::Align::Type>(keyValue.second, ALIGN_TABLE, ALIGN_TABLE_COUNT, mAnchorPoint);
301           break;
302         }
303         case Toolkit::Visual::Transform::Property::OFFSET_POLICY:
304         {
305           Vector2 policy;
306           if(GetPolicyFromValue(keyValue.second, policy))
307           {
308             mOffsetSizeMode.x = policy.x;
309             mOffsetSizeMode.y = policy.y;
310           }
311           break;
312         }
313         case Toolkit::Visual::Transform::Property::SIZE_POLICY:
314         {
315           Vector2 policy;
316           if(GetPolicyFromValue(keyValue.second, policy))
317           {
318             mOffsetSizeMode.z = policy.x;
319             mOffsetSizeMode.w = policy.y;
320           }
321           break;
322         }
323         case Toolkit::DevelVisual::Transform::Property::EXTRA_SIZE:
324         {
325           keyValue.second.Get(mExtraSize);
326           break;
327         }
328       }
329     }
330     else // Key type is STRING
331     {
332       if(keyValue.first == "offset")
333       {
334         keyValue.second.Get(mOffset);
335       }
336       else if(keyValue.first == "size")
337       {
338         keyValue.second.Get(mSize);
339       }
340       else if(keyValue.first == "origin")
341       {
342         Scripting::GetEnumerationProperty<Toolkit::Align::Type>(keyValue.second, ALIGN_TABLE, ALIGN_TABLE_COUNT, mOrigin);
343       }
344       else if(keyValue.first == "anchorPoint")
345       {
346         Scripting::GetEnumerationProperty<Toolkit::Align::Type>(keyValue.second, ALIGN_TABLE, ALIGN_TABLE_COUNT, mAnchorPoint);
347       }
348       else if(keyValue.first == "offsetPolicy")
349       {
350         Vector2 policy;
351         if(GetPolicyFromValue(keyValue.second, policy))
352         {
353           mOffsetSizeMode.x = policy.x;
354           mOffsetSizeMode.y = policy.y;
355         }
356       }
357       else if(keyValue.first == "sizePolicy")
358       {
359         Vector2 policy;
360         if(GetPolicyFromValue(keyValue.second, policy))
361         {
362           mOffsetSizeMode.z = policy.x;
363           mOffsetSizeMode.w = policy.y;
364         }
365       }
366       else if(keyValue.first == "extraSize")
367       {
368         keyValue.second.Get(mExtraSize);
369       }
370     }
371   }
372 }
373
374 void Internal::Visual::Base::Impl::Transform::GetPropertyMap(Property::Map& map) const
375 {
376   map.Clear();
377   map.Add(Toolkit::Visual::Transform::Property::OFFSET, mOffset)
378     .Add(Toolkit::Visual::Transform::Property::SIZE, mSize)
379     .Add(Toolkit::Visual::Transform::Property::ORIGIN, mOrigin)
380     .Add(Toolkit::Visual::Transform::Property::ANCHOR_POINT, mAnchorPoint)
381     .Add(Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2(mOffsetSizeMode.x, mOffsetSizeMode.y))
382     .Add(Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2(mOffsetSizeMode.z, mOffsetSizeMode.w))
383     .Add(Toolkit::DevelVisual::Transform::Property::EXTRA_SIZE, mExtraSize);
384 }
385
386 void Internal::Visual::Base::Impl::Transform::RegisterUniforms(Dali::Renderer renderer, Toolkit::Direction::Type direction)
387 {
388   mSizeIndex   = renderer.RegisterProperty(SIZE, mSize);
389   mOffsetIndex = renderer.RegisterProperty(OFFSET, direction == Toolkit::Direction::LEFT_TO_RIGHT ? mOffset : mOffset * Vector2(-1.0f, 1.0f));
390   renderer.RegisterProperty(OFFSET_SIZE_MODE, mOffsetSizeMode);
391   renderer.RegisterProperty(ORIGIN, PointToVector2(mOrigin, direction) - Vector2(0.5, 0.5));
392   renderer.RegisterProperty(ANCHOR_POINT, Vector2(0.5, 0.5) - PointToVector2(mAnchorPoint, direction));
393   renderer.RegisterProperty(EXTRA_SIZE, mExtraSize);
394 }
395
396 Vector2 Internal::Visual::Base::Impl::Transform::GetVisualSize(const Vector2& controlSize)
397 {
398   return Vector2(Lerp(mOffsetSizeMode.z, mSize.x * controlSize.x, mSize.x),
399                  Lerp(mOffsetSizeMode.w, mSize.y * controlSize.y, mSize.y)) +
400          mExtraSize;
401 }
402
403 } // namespace Internal
404
405 } // namespace Toolkit
406
407 } // namespace Dali