[dali_2.3.21] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / public-api / loader / node-definition.cpp
1 /*
2  * Copyright (c) 2024 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-scene3d/public-api/loader/node-definition.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23
24 // INTERNAL INCLUDES
25 #include <dali-scene3d/internal/light/light-impl.h>
26 #include <dali-scene3d/internal/model-components/material-impl.h>
27 #include <dali-scene3d/internal/model-components/model-node-impl.h>
28 #include <dali-scene3d/internal/model-components/model-primitive-impl.h>
29 #include <dali-scene3d/public-api/loader/renderer-state.h>
30 #include <dali-scene3d/public-api/loader/utils.h>
31
32 namespace Dali
33 {
34 namespace
35 {
36 static constexpr std::string_view IBL_INTENSITY_STRING("uIblIntensity");
37 static constexpr std::string_view IBL_Y_DIRECTION("uYDirection");
38 static constexpr std::string_view IBL_MAXLOD("uMaxLOD");
39
40 static constexpr uint32_t MAX_NUMBER_OF_MATERIAL_TEXTURE = 7;
41 static constexpr uint32_t SEMANTICS[MAX_NUMBER_OF_MATERIAL_TEXTURE] =
42   {
43     Scene3D::Loader::MaterialDefinition::ALBEDO,
44     Scene3D::Loader::MaterialDefinition::METALLIC | Scene3D::Loader::MaterialDefinition::ROUGHNESS,
45     Scene3D::Loader::MaterialDefinition::NORMAL,
46     Scene3D::Loader::MaterialDefinition::OCCLUSION,
47     Scene3D::Loader::MaterialDefinition::EMISSIVE,
48     Scene3D::Loader::MaterialDefinition::SPECULAR,
49     Scene3D::Loader::MaterialDefinition::SPECULAR_COLOR,
50 };
51
52 static constexpr Scene3D::Material::TextureType TEXTURE_TYPES[MAX_NUMBER_OF_MATERIAL_TEXTURE] =
53   {
54     Scene3D::Material::TextureType::BASE_COLOR,
55     Scene3D::Material::TextureType::METALLIC_ROUGHNESS,
56     Scene3D::Material::TextureType::NORMAL,
57     Scene3D::Material::TextureType::OCCLUSION,
58     Scene3D::Material::TextureType::EMISSIVE,
59     Scene3D::Material::TextureType::SPECULAR,
60     Scene3D::Material::TextureType::SPECULAR_COLOR,
61 };
62
63 Vector4 GetTextureFactor(Scene3D::Loader::MaterialDefinition& materialDefinition, uint32_t semantic)
64 {
65   Vector4 factor = Vector4::ONE;
66   switch(semantic)
67   {
68     case Scene3D::Loader::MaterialDefinition::ALBEDO:
69       factor = materialDefinition.mBaseColorFactor;
70       break;
71     case Scene3D::Loader::MaterialDefinition::METALLIC | Scene3D::Loader::MaterialDefinition::ROUGHNESS:
72       factor = Vector4(materialDefinition.mMetallic, materialDefinition.mRoughness, 0.0f, 0.0f);
73       break;
74     case Scene3D::Loader::MaterialDefinition::NORMAL:
75       factor.x = materialDefinition.mNormalScale;
76       break;
77     case Scene3D::Loader::MaterialDefinition::OCCLUSION:
78       factor.x = materialDefinition.mOcclusionStrength;
79       break;
80     case Scene3D::Loader::MaterialDefinition::EMISSIVE:
81       factor = materialDefinition.mEmissiveFactor;
82       break;
83     case Scene3D::Loader::MaterialDefinition::SPECULAR:
84       factor.x = materialDefinition.mSpecularFactor;
85       break;
86     case Scene3D::Loader::MaterialDefinition::SPECULAR_COLOR:
87       factor = materialDefinition.mSpecularColorFactor;
88       break;
89     default:
90       break;
91   }
92   return factor;
93 }
94
95 } // namespace
96
97 namespace Scene3D
98 {
99 namespace Loader
100 {
101 bool NodeDefinition::Renderable::GetExtents(const ResourceBundle& resources, Vector3& min, Vector3& max) const
102 {
103   return false;
104 }
105
106 void NodeDefinition::Renderable::RegisterResources(IResourceReceiver& receiver) const
107 {
108   receiver.Register(ResourceType::Shader, mShaderIdx);
109 }
110
111 void NodeDefinition::Renderable::ReflectResources(IResourceReflector& reflector)
112 {
113   reflector.Reflect(ResourceType::Shader, mShaderIdx);
114 }
115
116 void NodeDefinition::Renderable::OnCreate(const NodeDefinition& nodeDefinition, CreateParams& params, ModelNode& node) const
117 {
118   DALI_ASSERT_DEBUG(mShaderIdx != INVALID_INDEX);
119   auto&  resources = params.mResources;
120   Shader shader    = resources.mShaders[mShaderIdx].second;
121
122   static Geometry defaultGeometry = Geometry::New();
123   Renderer        renderer        = Renderer::New(defaultGeometry, shader);
124
125   RendererState::Apply(resources.mShaders[mShaderIdx].first.mRendererState, renderer);
126
127   node.AddRenderer(renderer);
128 }
129
130 const char* NodeDefinition::ORIGINAL_MATRIX_PROPERTY_NAME = "originalMatrix";
131
132 ModelNode NodeDefinition::CreateModelNode(CreateParams& params)
133 {
134   ModelNode node = ModelNode::New();
135   mNodeId        = node.GetProperty<int32_t>(Dali::Actor::Property::ID);
136
137   SetActorCentered(node);
138
139   node.SetProperty(Actor::Property::NAME, mName);
140   node.SetProperty(Actor::Property::POSITION, mPosition);
141   node.SetProperty(Actor::Property::ORIENTATION, mOrientation);
142   node.SetProperty(Actor::Property::SCALE, mScale);
143   node.SetProperty(Actor::Property::SIZE, mSize);
144   node.SetProperty(Actor::Property::VISIBLE, mIsVisible);
145
146   node.RegisterProperty(ORIGINAL_MATRIX_PROPERTY_NAME, GetLocalSpace(), Property::AccessMode::READ_ONLY);
147
148   node.SetProperty(Actor::Property::COLOR_MODE, ColorMode::USE_OWN_MULTIPLY_PARENT_COLOR);
149
150   for(auto& renderable : mRenderables)
151   {
152     renderable->OnCreate(*this, params, node);
153   }
154
155   for(auto& e : mExtras)
156   {
157     node.RegisterProperty(e.mKey, e.mValue);
158   }
159
160   for(auto& c : mConstraints)
161   {
162     params.mConstrainables.push_back(ConstraintRequest{&c, node});
163   }
164
165   return node;
166 }
167
168 Matrix NodeDefinition::GetLocalSpace() const
169 {
170   Matrix localSpace{false};
171   localSpace.SetTransformComponents(mScale, mOrientation, mPosition);
172   return localSpace;
173 }
174
175 std::string_view NodeDefinition::GetIblScaleFactorUniformName()
176 {
177   return IBL_INTENSITY_STRING;
178 }
179
180 std::string_view NodeDefinition::GetIblYDirectionUniformName()
181 {
182   return IBL_Y_DIRECTION;
183 }
184
185 std::string_view NodeDefinition::GetIblMaxLodUniformName()
186 {
187   return IBL_MAXLOD;
188 }
189
190 bool NodeDefinition::GetExtents(const ResourceBundle& resources, Vector3& min, Vector3& max) const
191 {
192   if(mRenderables.empty())
193   {
194     return false;
195   }
196
197   bool useModelExtents = false;
198   for(auto& renderable : mRenderables)
199   {
200     Vector3 renderableMin(Vector3::ONE * MAXFLOAT), renderableMax(-Vector3::ONE * MAXFLOAT);
201     if(!renderable->GetExtents(resources, renderableMin, renderableMax))
202     {
203       useModelExtents = false;
204       break;
205     }
206     useModelExtents = true;
207     min.x           = std::min(min.x, renderableMin.x);
208     min.y           = std::min(min.y, renderableMin.y);
209     min.z           = std::min(min.z, renderableMin.z);
210     max.x           = std::max(max.x, renderableMax.x);
211     max.y           = std::max(max.y, renderableMax.y);
212     max.z           = std::max(max.z, renderableMax.z);
213   }
214   if(!useModelExtents)
215   {
216     // If the renderable node don't have mesh accessor, use size to compute extents.
217     min = -mSize / 2.0f;
218     max = mSize / 2.0f;
219   }
220   return true;
221 }
222
223 bool ModelRenderable::GetExtents(const ResourceBundle& resources, Vector3& min, Vector3& max) const
224 {
225   auto&    mesh    = resources.mMeshes[mMeshIdx];
226   uint32_t minSize = mesh.first.mPositions.mBlob.mMin.size();
227   uint32_t maxSize = mesh.first.mPositions.mBlob.mMax.size();
228   if(minSize == maxSize && minSize >= 2u && maxSize >= 2u)
229   {
230     min = Vector3(mesh.first.mPositions.mBlob.mMin[0], mesh.first.mPositions.mBlob.mMin[1], 0.0f);
231     max = Vector3(mesh.first.mPositions.mBlob.mMax[0], mesh.first.mPositions.mBlob.mMax[1], 0.0f);
232     if(minSize == 3u)
233     {
234       min.z = mesh.first.mPositions.mBlob.mMin[2];
235       max.z = mesh.first.mPositions.mBlob.mMax[2];
236     }
237     return true;
238   }
239   return false;
240 }
241
242 void ModelRenderable::RegisterResources(IResourceReceiver& receiver) const
243 {
244   Renderable::RegisterResources(receiver);
245   receiver.Register(ResourceType::Mesh, mMeshIdx);
246   receiver.Register(ResourceType::Material, mMaterialIdx);
247 }
248
249 void ModelRenderable::ReflectResources(IResourceReflector& reflector)
250 {
251   Renderable::ReflectResources(reflector);
252   reflector.Reflect(ResourceType::Mesh, mMeshIdx);
253   reflector.Reflect(ResourceType::Material, mMaterialIdx);
254 }
255
256 // How many shader managers are there?!
257 void ModelRenderable::OnCreate(const NodeDefinition& nodeDefinition, NodeDefinition::CreateParams& params, ModelNode& node) const
258 {
259   DALI_ASSERT_DEBUG(mMeshIdx != INVALID_INDEX);
260   ShaderOption::HashType shaderOptionHash{0u};
261   if(mShaderIdx == INVALID_INDEX)
262   {
263     ShaderOption option = params.mShaderManager->ProduceShaderOption(params.mResources.mMaterials[mMaterialIdx].first,
264                                                                      params.mResources.mMeshes[mMeshIdx].first);
265     shaderOptionHash    = option.GetOptionHash();
266     Shader shader       = params.mShaderManager->ProduceShader(option);
267
268     static Geometry defaultGeometry = Geometry::New();
269     Renderer        renderer        = Renderer::New(defaultGeometry, shader);
270
271     RendererState::Apply(params.mShaderManager->GetRendererState(params.mResources.mMaterials[mMaterialIdx].first), renderer);
272     Internal::GetImplementation(node).UpdateShader(params.mShaderManager);
273     node.AddRenderer(renderer);
274   }
275   else
276   {
277     Renderable::OnCreate(nodeDefinition, params, node);
278   }
279
280   auto& resources = params.mResources;
281   auto& mesh      = resources.mMeshes[mMeshIdx];
282
283   auto     renderer = node.GetRendererAt(node.GetRendererCount() - 1u);
284   Geometry geometry = mesh.second.geometry;
285   renderer.SetGeometry(geometry);
286
287   TextureSet textures = resources.mMaterials[mMaterialIdx].second;
288   // Set the blend shape texture.
289   if(mesh.second.blendShapeGeometry)
290   {
291     TextureSet newTextureSet = TextureSet::New();
292     newTextureSet.SetTexture(0u, mesh.second.blendShapeGeometry);
293
294     const unsigned int numberOfTextures = textures.GetTextureCount();
295     for(unsigned int index = 0u; index < numberOfTextures; ++index)
296     {
297       const unsigned int newIndex = index + 1u;
298       newTextureSet.SetTexture(newIndex, textures.GetTexture(index));
299       newTextureSet.SetSampler(newIndex, textures.GetSampler(index));
300     }
301
302     textures = newTextureSet;
303   }
304   renderer.SetTextures(textures);
305
306   {
307     mesh.first.mModelPrimitive = ModelPrimitive::New();
308     auto& primitive            = GetImplementation(mesh.first.mModelPrimitive);
309     primitive.SetRenderer(renderer);
310
311     Index    envIndex       = resources.mMaterials[mMaterialIdx].first.mEnvironmentIdx;
312     uint32_t specularMipmap = resources.mEnvironmentMaps[envIndex].second.mSpecularMipmapLevels;
313     primitive.SetImageBasedLightTexture(resources.mEnvironmentMaps[envIndex].second.mDiffuse,
314                                         resources.mEnvironmentMaps[envIndex].second.mSpecular,
315                                         resources.mEnvironmentMaps[envIndex].first.mIblIntensity,
316                                         specularMipmap);
317
318     bool hasPositions = false;
319     bool hasNormals   = false;
320     bool hasTangents  = false;
321     mesh.first.RetrieveBlendShapeComponents(hasPositions, hasNormals, hasTangents);
322     primitive.SetBlendShapeOptions(hasPositions, hasNormals, hasTangents, mesh.first.mBlendShapeVersion);
323     primitive.SetBlendShapeGeometry(mesh.second.blendShapeGeometry);
324     primitive.SetSkinned(mesh.first.IsSkinned(), mesh.first.GetNumberOfJointSets());
325     primitive.SetVertexColor(mesh.first.HasVertexColor());
326   }
327
328   auto shader = renderer.GetShader();
329   if(mesh.first.IsSkinned())
330   {
331     params.mSkinnables.push_back(SkinningShaderConfigurationRequest{mesh.first.mSkeletonIdx, shader, mesh.first.mModelPrimitive});
332   }
333
334   if(mesh.first.HasBlendShapes())
335   {
336     params.mBlendshapeRequests.push_back(BlendshapeShaderConfigurationRequest{nodeDefinition.mName, mMeshIdx, shader, mesh.first.mModelPrimitive});
337   }
338
339   auto& matDef = resources.mMaterials[mMaterialIdx].first;
340   renderer.RegisterProperty("uColorFactor", matDef.mBaseColorFactor);
341   renderer.RegisterProperty("uMetallicFactor", matDef.mMetallic);
342   renderer.RegisterProperty("uRoughnessFactor", matDef.mRoughness);
343   renderer.RegisterProperty("uDielectricSpecular", matDef.mDielectricSpecular);
344   renderer.RegisterProperty("uSpecularFactor", matDef.mSpecularFactor);
345   renderer.RegisterProperty("uSpecularColorFactor", matDef.mSpecularColorFactor);
346   renderer.RegisterProperty("uNormalScale", matDef.mNormalScale);
347   renderer.RegisterProperty("uEmissiveFactor", matDef.mEmissiveFactor);
348   if(matDef.mFlags & MaterialDefinition::OCCLUSION)
349   {
350     renderer.RegisterProperty("uOcclusionStrength", matDef.mOcclusionStrength);
351   }
352
353   renderer.RegisterProperty("uBaseColorTextureTransformAvailable", 0.0f);
354   renderer.RegisterProperty("uNormalTextureTransformAvailable", 0.0f);
355   renderer.RegisterProperty("uNormalRoughnessTextureTransformAvailable", 0.0f);
356   renderer.RegisterProperty("uMetalRoughnessTextureTransformAvailable", 0.0f);
357   renderer.RegisterProperty("uOcclusionTextureTransformAvailable", 0.0f);
358   renderer.RegisterProperty("uEmissiveTextureTransformAvailable", 0.0f);
359
360   renderer.RegisterProperty("uBaseColorTextureTransform", Matrix3::IDENTITY);
361   renderer.RegisterProperty("uNormalRoughnessTextureTransform", Matrix3::IDENTITY);
362   renderer.RegisterProperty("uNormalTextureTransform", Matrix3::IDENTITY);
363   renderer.RegisterProperty("uMetalRoughnessTextureTransform", Matrix3::IDENTITY);
364   renderer.RegisterProperty("uOcclusionTextureTransform", Matrix3::IDENTITY);
365   renderer.RegisterProperty("uEmissiveTextureTransform", Matrix3::IDENTITY);
366
367   auto iTexture   = matDef.mTextureStages.begin();
368   auto checkStage = [&](uint32_t flags) {
369     return iTexture != matDef.mTextureStages.end() && MaskMatch(iTexture->mSemantic, flags);
370   };
371
372   if(checkStage(MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC))
373   {
374     renderer.RegisterProperty("uBaseColorTextureTransformAvailable", iTexture->mTexture.mTransform != Matrix3::IDENTITY);
375     renderer.RegisterProperty("uBaseColorTextureTransform", iTexture->mTexture.mTransform);
376     ++iTexture;
377
378     if(checkStage(MaterialDefinition::NORMAL | MaterialDefinition::ROUGHNESS))
379     {
380       renderer.RegisterProperty("uNormalRoughnessTextureTransformAvailable", iTexture->mTexture.mTransform != Matrix3::IDENTITY);
381       renderer.RegisterProperty("uNormalRoughnessTextureTransform", iTexture->mTexture.mTransform);
382       ++iTexture;
383     }
384   }
385   else if(checkStage(MaterialDefinition::ALBEDO))
386   {
387     renderer.RegisterProperty("uBaseColorTextureTransformAvailable", iTexture->mTexture.mTransform != Matrix3::IDENTITY);
388     renderer.RegisterProperty("uBaseColorTextureTransform", iTexture->mTexture.mTransform);
389     ++iTexture;
390   }
391
392   if(checkStage(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS))
393   {
394     renderer.RegisterProperty("uMetalRoughnessTextureTransformAvailable", iTexture->mTexture.mTransform != Matrix3::IDENTITY);
395     renderer.RegisterProperty("uMetalRoughnessTextureTransform", iTexture->mTexture.mTransform);
396     ++iTexture;
397   }
398
399   if(checkStage(MaterialDefinition::NORMAL))
400   {
401     renderer.RegisterProperty("uNormalTextureTransformAvailable", iTexture->mTexture.mTransform != Matrix3::IDENTITY);
402     renderer.RegisterProperty("uNormalTextureTransform", iTexture->mTexture.mTransform);
403     ++iTexture;
404   }
405
406   if(checkStage(MaterialDefinition::OCCLUSION))
407   {
408     renderer.RegisterProperty("uOcclusionTextureTransformAvailable", iTexture->mTexture.mTransform != Matrix3::IDENTITY);
409     renderer.RegisterProperty("uOcclusionTextureTransform", iTexture->mTexture.mTransform);
410     ++iTexture;
411   }
412
413   if(checkStage(MaterialDefinition::EMISSIVE))
414   {
415     renderer.RegisterProperty("uEmissiveTextureTransformAvailable", iTexture->mTexture.mTransform != Matrix3::IDENTITY);
416     renderer.RegisterProperty("uEmissiveTextureTransform", iTexture->mTexture.mTransform);
417     ++iTexture;
418   }
419
420   float opaque      = matDef.mIsOpaque ? 1.0f : 0.0f;
421   float mask        = matDef.mIsMask ? 1.0f : 0.0f;
422   float alphaCutoff = matDef.GetAlphaCutoff();
423
424   renderer.RegisterProperty("uOpaque", opaque);
425   renderer.RegisterProperty("uMask", mask);
426   renderer.RegisterProperty("uAlphaThreshold", alphaCutoff);
427
428   Index    envIndex       = matDef.mEnvironmentIdx;
429   uint32_t specularMipmap = resources.mEnvironmentMaps[envIndex].second.mSpecularMipmapLevels;
430   renderer.RegisterProperty(IBL_MAXLOD.data(), static_cast<float>(specularMipmap));
431   renderer.RegisterProperty(IBL_INTENSITY_STRING.data(), resources.mEnvironmentMaps[envIndex].first.mIblIntensity);
432   renderer.RegisterProperty(IBL_Y_DIRECTION.data(), resources.mEnvironmentMaps[envIndex].first.mYDirection);
433
434   node.SetProperty(Actor::Property::COLOR, mColor);
435
436   // If user uses customshader, the properties of the shader could not be changed by Material.
437   if(mShaderIdx == INVALID_INDEX)
438   {
439     matDef.mMaterial            = Material::New();
440     auto     material           = matDef.mMaterial;
441     uint32_t textureIndexOffset = (mesh.second.blendShapeGeometry) ? 1 : 0;
442     uint32_t textureIndex       = 0;
443     for(uint32_t i = 0; i < MAX_NUMBER_OF_MATERIAL_TEXTURE; ++i)
444     {
445       Internal::Material::TextureInformation textureInformation;
446       if(matDef.CheckTextures(SEMANTICS[i]))
447       {
448         textureInformation.mTexture   = textures.GetTexture(textureIndex + textureIndexOffset);
449         textureInformation.mSampler   = textures.GetSampler(textureIndex + textureIndexOffset);
450         textureInformation.mUrl       = matDef.mTextureStages[textureIndex].mTexture.mDirectoryPath + matDef.mTextureStages[textureIndex].mTexture.mImageUri;
451         textureInformation.mTransform = matDef.mTextureStages[textureIndex].mTexture.mTransform;
452         textureIndex++;
453       }
454       textureInformation.mFactor = GetTextureFactor(matDef, SEMANTICS[i]);
455       GetImplementation(material).SetTextureInformation(TEXTURE_TYPES[i], std::move(textureInformation));
456     }
457     material.SetProperty(Scene3D::Material::Property::ALPHA_MODE, matDef.mAlphaModeType);
458     material.SetProperty(Scene3D::Material::Property::ALPHA_CUTOFF, matDef.GetAlphaCutoff());
459     material.SetProperty(Scene3D::Material::Property::DOUBLE_SIDED, matDef.mDoubleSided);
460     material.SetProperty(Scene3D::Material::Property::IOR, matDef.mIor);
461
462     // This _should_ keep the same shader as generated at the top of the method.
463     GetImplementation(mesh.first.mModelPrimitive).SetMaterial(material, false);
464     GetImplementation(material).ResetFlag();
465   }
466
467   Internal::GetImplementation(node).AddModelPrimitive(mesh.first.mModelPrimitive, shaderOptionHash);
468 }
469
470 void ArcRenderable::OnCreate(const NodeDefinition& nodeDefinition, NodeDefinition::CreateParams& params, ModelNode& node) const
471 {
472   ModelRenderable::OnCreate(nodeDefinition, params, node);
473
474   node.RegisterProperty("antiAliasing", mAntiAliasing ? 1 : 0);
475   node.RegisterProperty("arcCaps", mArcCaps);
476   node.RegisterProperty("radius", mRadius);
477
478   const float startAngleRadians = mStartAngleDegrees * Math::PI_OVER_180;
479   Vector2     startPolar{std::cos(startAngleRadians), std::sin(startAngleRadians)};
480   node.RegisterProperty("startAngle", startPolar);
481
482   const float endAngleRadians = mEndAngleDegrees * Math::PI_OVER_180;
483   Vector2     endPolar{std::cos(endAngleRadians), std::sin(endAngleRadians)};
484   node.RegisterProperty("endAngle", endPolar);
485 }
486
487 void ArcRenderable::GetEndVectorWithDiffAngle(float startAngle, float diffAngle, Vector2& endVector)
488 {
489   float endAngle = 0.f;
490
491   if(diffAngle <= 0.001f)
492   {
493     // 0.001 is used to ensure is empty arc when startAngle = endAngle + 360 * N
494     endAngle = startAngle + 0.001f;
495   }
496   else if(diffAngle >= 360.f)
497   {
498     endAngle = diffAngle + 359.99f;
499   }
500   else
501   {
502     endAngle = startAngle + 360.0f + diffAngle;
503   }
504   endVector.x = cosf(endAngle * Math::PI_OVER_180);
505   endVector.y = sinf(endAngle * Math::PI_OVER_180);
506 }
507
508 } // namespace Loader
509 } // namespace Scene3D
510 } // namespace Dali