Merge "Change trace tag for text dorelayout" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / internal / model-components / material-impl.cpp
1 /*
2  * Copyright (c) 2023 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/internal/model-components/material-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <dali/public-api/object/type-registry-helper.h>
24 #include <dali/public-api/object/type-registry.h>
25 #include <dali/public-api/rendering/sampler.h>
26
27 // INTERNAL INCLUDES
28 #include <dali-scene3d/internal/graphics/builtin-shader-extern-gen.h>
29 #include <dali-scene3d/internal/light/light-impl.h>
30 #include <dali-scene3d/internal/model-components/material-modify-observer.h>
31 #include <dali-scene3d/public-api/loader/node-definition.h>
32 #include <dali-scene3d/public-api/loader/renderer-state.h>
33 #include <dali-scene3d/public-api/loader/utils.h>
34
35 namespace Dali
36 {
37 namespace Scene3D
38 {
39 namespace Internal
40 {
41 namespace
42 {
43 /**
44  * Creates Material through type registry
45  */
46 BaseHandle Create()
47 {
48   return Scene3D::Material::New();
49 }
50
51 // Setup properties, signals and actions using the type-registry.
52 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::Material, Dali::BaseHandle, Create);
53 DALI_TYPE_REGISTRATION_END()
54
55 static constexpr uint32_t         OFFSET_FOR_DIFFUSE_CUBE_TEXTURE  = 2u;
56 static constexpr uint32_t         OFFSET_FOR_SPECULAR_CUBE_TEXTURE = 1u;
57 static constexpr uint32_t         INVALID_INDEX                    = 0u;
58 static constexpr uint32_t         ALPHA_CUTOFF_FLAG                = Scene3D::Loader::MaterialDefinition::Flags::SUBSURFACE << 1;
59 static constexpr std::string_view THREE_TEX_KEYWORD                = "THREE_TEX";
60 static constexpr std::string_view GLTF_CHANNELS_KEYWORD            = "GLTF_CHANNELS";
61
62 enum TextureIndex
63 {
64   BASE_COLOR,
65   METALLIC_ROUGHNESS,
66   NORMAL,
67   OCCLUSION,
68   EMISSIVE,
69   SPECULAR,
70   SPECULAR_COLOR,
71   TEXTURE_TYPE_NUMBER,
72 };
73
74 } // unnamed namespace
75
76 MaterialPtr Material::New()
77 {
78   MaterialPtr material = new Material();
79
80   material->Initialize();
81
82   return material;
83 }
84
85 Material::Material()
86 : mName(),
87   mModifyFlag(MaterialModifyObserver::ModifyFlag::NONE),
88   mObserverNotifying(false)
89 {
90   mAsyncImageLoader = Dali::Toolkit::AsyncImageLoader::New();
91   mAsyncImageLoader.ImageLoadedSignal().Connect(this, &Material::TextureLoadComplete);
92   mTextureInformations.assign(TEXTURE_TYPE_NUMBER, TextureInformation());
93   mTextureInformations[BASE_COLOR].mSemantic = Scene3D::Loader::MaterialDefinition::ALBEDO;
94   // TODO : How we support dli manner
95   mTextureInformations[METALLIC_ROUGHNESS].mSemantic = Scene3D::Loader::MaterialDefinition::METALLIC | Scene3D::Loader::MaterialDefinition::ROUGHNESS |
96                                                        Scene3D::Loader::MaterialDefinition::GLTF_CHANNELS;
97   mTextureInformations[NORMAL].mSemantic         = Scene3D::Loader::MaterialDefinition::NORMAL;
98   mTextureInformations[OCCLUSION].mSemantic      = Scene3D::Loader::MaterialDefinition::OCCLUSION;
99   mTextureInformations[EMISSIVE].mSemantic       = Scene3D::Loader::MaterialDefinition::EMISSIVE;
100   mTextureInformations[SPECULAR].mSemantic       = Scene3D::Loader::MaterialDefinition::SPECULAR;
101   mTextureInformations[SPECULAR_COLOR].mSemantic = Scene3D::Loader::MaterialDefinition::SPECULAR_COLOR;
102
103   mTextureInformations[BASE_COLOR].mDefineKeyword         = "BASECOLOR_TEX";
104   mTextureInformations[METALLIC_ROUGHNESS].mDefineKeyword = "METALLIC_ROUGHNESS_TEX";
105   mTextureInformations[NORMAL].mDefineKeyword             = "NORMAL_TEX";
106   mTextureInformations[OCCLUSION].mDefineKeyword          = "OCCLUSION";
107   mTextureInformations[EMISSIVE].mDefineKeyword           = "EMISSIVE";
108   mTextureInformations[SPECULAR].mDefineKeyword           = "MATERIAL_SPECULAR_TEXTURE";
109   mTextureInformations[SPECULAR_COLOR].mDefineKeyword     = "MATERIAL_SPECULAR_COLOR_TEXTURE";
110
111   mTextureInformations[TextureIndex::EMISSIVE].mFactor = Vector4::ZERO;
112 }
113
114 Material::~Material() = default;
115
116 void Material::Initialize()
117 {
118 }
119
120 void Material::SetProperty(Dali::Property::Index index, Dali::Property::Value propertyValue)
121 {
122   bool needToApply = true;
123   switch(index)
124   {
125     case Dali::Scene3D::Material::Property::NAME:
126     {
127       std::string name;
128       if(propertyValue.Get(name))
129       {
130         mName = name;
131       }
132       needToApply = false;
133       break;
134     }
135     case Dali::Scene3D::Material::Property::BASE_COLOR_URL:
136     {
137       std::string baseColorUrl;
138       if(propertyValue.Get(baseColorUrl))
139       {
140         RequestTextureLoad(mTextureInformations[TextureIndex::BASE_COLOR], baseColorUrl);
141         needToApply = false;
142       }
143       break;
144     }
145     case Dali::Scene3D::Material::Property::BASE_COLOR_FACTOR:
146     {
147       Vector4 baseColorFactor;
148       if(propertyValue.Get(baseColorFactor))
149       {
150         mTextureInformations[TextureIndex::BASE_COLOR].mFactor = baseColorFactor;
151         mModifyFlag |= MaterialModifyObserver::ModifyFlag::UNIFORM;
152       }
153       break;
154     }
155     case Dali::Scene3D::Material::Property::METALLIC_ROUGHNESS_URL:
156     {
157       std::string metallicRoughnessUrl;
158       if(propertyValue.Get(metallicRoughnessUrl))
159       {
160         RequestTextureLoad(mTextureInformations[TextureIndex::METALLIC_ROUGHNESS], metallicRoughnessUrl);
161         needToApply = false;
162       }
163       break;
164     }
165     case Dali::Scene3D::Material::Property::METALLIC_FACTOR:
166     {
167       float metallicFactor;
168       if(propertyValue.Get(metallicFactor))
169       {
170         mTextureInformations[TextureIndex::METALLIC_ROUGHNESS].mFactor.x = metallicFactor;
171         mModifyFlag |= MaterialModifyObserver::ModifyFlag::UNIFORM;
172       }
173       break;
174     }
175     case Dali::Scene3D::Material::Property::ROUGHNESS_FACTOR:
176     {
177       float roughnessFactor;
178       if(propertyValue.Get(roughnessFactor))
179       {
180         mTextureInformations[TextureIndex::METALLIC_ROUGHNESS].mFactor.y = roughnessFactor;
181         mModifyFlag |= MaterialModifyObserver::ModifyFlag::UNIFORM;
182       }
183       break;
184     }
185     case Dali::Scene3D::Material::Property::NORMAL_URL:
186     {
187       std::string normalUrl;
188       if(propertyValue.Get(normalUrl))
189       {
190         RequestTextureLoad(mTextureInformations[TextureIndex::NORMAL], normalUrl);
191         needToApply = false;
192       }
193       break;
194     }
195     case Dali::Scene3D::Material::Property::NORMAL_SCALE:
196     {
197       float normalScale;
198       if(propertyValue.Get(normalScale))
199       {
200         mTextureInformations[TextureIndex::NORMAL].mFactor.x = normalScale;
201         mModifyFlag |= MaterialModifyObserver::ModifyFlag::UNIFORM;
202       }
203       break;
204     }
205     case Dali::Scene3D::Material::Property::OCCLUSION_URL:
206     {
207       std::string occlusionUrl;
208       if(propertyValue.Get(occlusionUrl))
209       {
210         RequestTextureLoad(mTextureInformations[TextureIndex::OCCLUSION], occlusionUrl);
211         needToApply = false;
212       }
213       break;
214     }
215     case Dali::Scene3D::Material::Property::OCCLUSION_STRENGTH:
216     {
217       float occlusionStrength;
218       if(propertyValue.Get(occlusionStrength))
219       {
220         mTextureInformations[TextureIndex::OCCLUSION].mFactor.x = occlusionStrength;
221         mModifyFlag |= MaterialModifyObserver::ModifyFlag::UNIFORM;
222       }
223       break;
224     }
225     case Dali::Scene3D::Material::Property::EMISSIVE_URL:
226     {
227       std::string emissiveUrl;
228       if(propertyValue.Get(emissiveUrl))
229       {
230         RequestTextureLoad(mTextureInformations[TextureIndex::EMISSIVE], emissiveUrl);
231         needToApply = false;
232       }
233       break;
234     }
235     case Dali::Scene3D::Material::Property::EMISSIVE_FACTOR:
236     {
237       Vector3 emissiveFactor;
238       if(propertyValue.Get(emissiveFactor))
239       {
240         mTextureInformations[TextureIndex::EMISSIVE].mFactor = emissiveFactor;
241         mModifyFlag |= MaterialModifyObserver::ModifyFlag::UNIFORM;
242       }
243       break;
244     }
245     case Dali::Scene3D::Material::Property::ALPHA_MODE:
246     {
247       Dali::Scene3D::Material::AlphaModeType alphaMode;
248       if(propertyValue.Get(alphaMode))
249       {
250         mAlphaMode = alphaMode;
251         mModifyFlag |= MaterialModifyObserver::ModifyFlag::UNIFORM;
252       }
253       break;
254     }
255     case Dali::Scene3D::Material::Property::ALPHA_CUTOFF:
256     {
257       float alphaCutoff;
258       if(propertyValue.Get(alphaCutoff))
259       {
260         mAlphaCutoff = alphaCutoff;
261         mModifyFlag |= MaterialModifyObserver::ModifyFlag::UNIFORM;
262       }
263       break;
264     }
265     case Dali::Scene3D::Material::Property::DOUBLE_SIDED:
266     {
267       bool doubleSided;
268       if(propertyValue.Get(doubleSided))
269       {
270         mDoubleSided = doubleSided;
271         mModifyFlag |= MaterialModifyObserver::ModifyFlag::UNIFORM;
272       }
273       break;
274     }
275     case Dali::Scene3D::Material::Property::IOR:
276     {
277       float ior;
278       if(propertyValue.Get(ior))
279       {
280         mIor = ior;
281         mModifyFlag |= MaterialModifyObserver::ModifyFlag::UNIFORM;
282       }
283       break;
284     }
285     case Dali::Scene3D::Material::Property::SPECULAR_URL:
286     {
287       std::string specularUrl;
288       if(propertyValue.Get(specularUrl))
289       {
290         RequestTextureLoad(mTextureInformations[TextureIndex::SPECULAR], specularUrl);
291         needToApply = false;
292       }
293       break;
294     }
295     case Dali::Scene3D::Material::Property::SPECULAR_FACTOR:
296     {
297       float specularFactor;
298       if(propertyValue.Get(specularFactor))
299       {
300         mTextureInformations[TextureIndex::SPECULAR].mFactor.x = specularFactor;
301         mModifyFlag |= MaterialModifyObserver::ModifyFlag::UNIFORM;
302       }
303       break;
304     }
305     case Dali::Scene3D::Material::Property::SPECULAR_COLOR_URL:
306     {
307       std::string specularColorUrl;
308       if(propertyValue.Get(specularColorUrl))
309       {
310         RequestTextureLoad(mTextureInformations[TextureIndex::SPECULAR_COLOR], specularColorUrl);
311         needToApply = false;
312       }
313       break;
314     }
315     case Dali::Scene3D::Material::Property::SPECULAR_COLOR_FACTOR:
316     {
317       Vector3 specularColorFactor;
318       if(propertyValue.Get(specularColorFactor))
319       {
320         mTextureInformations[TextureIndex::SPECULAR_COLOR].mFactor = specularColorFactor;
321         mModifyFlag |= MaterialModifyObserver::ModifyFlag::UNIFORM;
322       }
323       break;
324     }
325   }
326
327   if(needToApply)
328   {
329     Apply();
330   }
331 }
332
333 Dali::Property::Value Material::GetProperty(Dali::Property::Index index) const
334 {
335   Dali::Property::Value value;
336   switch(index)
337   {
338     case Dali::Scene3D::Material::Property::NAME:
339     {
340       value = mName;
341       break;
342     }
343     case Dali::Scene3D::Material::Property::BASE_COLOR_URL:
344     {
345       value = mTextureInformations[TextureIndex::BASE_COLOR].mUrl;
346       break;
347     }
348     case Dali::Scene3D::Material::Property::BASE_COLOR_FACTOR:
349     {
350       value = mTextureInformations[TextureIndex::BASE_COLOR].mFactor;
351       break;
352     }
353     case Dali::Scene3D::Material::Property::METALLIC_ROUGHNESS_URL:
354     {
355       value = mTextureInformations[TextureIndex::METALLIC_ROUGHNESS].mUrl;
356       break;
357     }
358     case Dali::Scene3D::Material::Property::METALLIC_FACTOR:
359     {
360       value = mTextureInformations[TextureIndex::METALLIC_ROUGHNESS].mFactor.x;
361       break;
362     }
363     case Dali::Scene3D::Material::Property::ROUGHNESS_FACTOR:
364     {
365       value = mTextureInformations[TextureIndex::METALLIC_ROUGHNESS].mFactor.y;
366       break;
367     }
368     case Dali::Scene3D::Material::Property::NORMAL_URL:
369     {
370       value = mTextureInformations[TextureIndex::NORMAL].mUrl;
371       break;
372     }
373     case Dali::Scene3D::Material::Property::NORMAL_SCALE:
374     {
375       value = mTextureInformations[TextureIndex::NORMAL].mFactor.x;
376       break;
377     }
378     case Dali::Scene3D::Material::Property::OCCLUSION_URL:
379     {
380       value = mTextureInformations[TextureIndex::OCCLUSION].mUrl;
381       break;
382     }
383     case Dali::Scene3D::Material::Property::OCCLUSION_STRENGTH:
384     {
385       value = mTextureInformations[TextureIndex::OCCLUSION].mFactor.x;
386       break;
387     }
388     case Dali::Scene3D::Material::Property::EMISSIVE_URL:
389     {
390       value = mTextureInformations[TextureIndex::EMISSIVE].mUrl;
391       break;
392     }
393     case Dali::Scene3D::Material::Property::EMISSIVE_FACTOR:
394     {
395       value = Vector3(mTextureInformations[TextureIndex::EMISSIVE].mFactor);
396       break;
397     }
398     case Dali::Scene3D::Material::Property::ALPHA_MODE:
399     {
400       value = mAlphaMode;
401       break;
402     }
403     case Dali::Scene3D::Material::Property::ALPHA_CUTOFF:
404     {
405       value = mAlphaCutoff;
406       break;
407     }
408     case Dali::Scene3D::Material::Property::DOUBLE_SIDED:
409     {
410       value = mDoubleSided;
411       break;
412     }
413     case Dali::Scene3D::Material::Property::IOR:
414     {
415       value = mIor;
416       break;
417     }
418     case Dali::Scene3D::Material::Property::SPECULAR_URL:
419     {
420       value = mTextureInformations[TextureIndex::SPECULAR].mUrl;
421       break;
422     }
423     case Dali::Scene3D::Material::Property::SPECULAR_FACTOR:
424     {
425       value = mTextureInformations[TextureIndex::SPECULAR].mFactor.x;
426       break;
427     }
428     case Dali::Scene3D::Material::Property::SPECULAR_COLOR_URL:
429     {
430       value = mTextureInformations[TextureIndex::SPECULAR_COLOR].mUrl;
431       break;
432     }
433     case Dali::Scene3D::Material::Property::SPECULAR_COLOR_FACTOR:
434     {
435       value = Vector3(mTextureInformations[TextureIndex::SPECULAR_COLOR].mFactor);
436       break;
437     }
438   }
439   return value;
440 }
441
442 void Material::SetTextureInformation(Scene3D::Material::TextureType index, TextureInformation&& textureInformation)
443 {
444   mTextureInformations[index].mFactor  = textureInformation.mFactor;
445   mTextureInformations[index].mSampler = textureInformation.mSampler;
446   mTextureInformations[index].mTexture = textureInformation.mTexture;
447   mTextureInformations[index].mUrl     = std::move(textureInformation.mUrl);
448 }
449
450 void Material::SetTexture(Scene3D::Material::TextureType index, Dali::Texture texture)
451 {
452   if(static_cast<uint32_t>(index) < static_cast<uint32_t>(TextureIndex::TEXTURE_TYPE_NUMBER))
453   {
454     if(mTextureInformations[index].mTexture != texture)
455     {
456       if(mTextureInformations[index].mLoadingTaskId != INVALID_INDEX)
457       {
458         mAsyncImageLoader.Cancel(mTextureInformations[index].mLoadingTaskId);
459         mTextureInformations[index].mLoadingTaskId = INVALID_INDEX;
460       }
461       mTextureInformations[index].mTexture = texture;
462       if(IsResourceReady())
463       {
464         ResourcesLoadComplete();
465       }
466     }
467   }
468 }
469
470 Dali::Texture Material::GetTexture(Scene3D::Material::TextureType index)
471 {
472   if(static_cast<uint32_t>(index) < static_cast<uint32_t>(TextureIndex::TEXTURE_TYPE_NUMBER))
473   {
474     return mTextureInformations[index].mTexture;
475   }
476   return Dali::Texture();
477 }
478
479 TextureSet Material::GetTextureSet()
480 {
481   TextureSet textures = TextureSet::New();
482   for(uint32_t i = 0, count = 0; i < TEXTURE_TYPE_NUMBER; ++i)
483   {
484     if(!mTextureInformations[i].mTexture)
485     {
486       continue;
487     }
488     textures.SetTexture(count, mTextureInformations[i].mTexture);
489     Sampler sampler = mTextureInformations[i].mSampler;
490     if(!sampler)
491     {
492       auto samplerFlag = Scene3D::Loader::SamplerFlags::FILTER_LINEAR | (Scene3D::Loader::SamplerFlags::FILTER_LINEAR << Scene3D::Loader::SamplerFlags::FILTER_MAG_SHIFT) |
493                          (Scene3D::Loader::SamplerFlags::WRAP_REPEAT << Scene3D::Loader::SamplerFlags::WRAP_S_SHIFT) | (Scene3D::Loader::SamplerFlags::WRAP_REPEAT << Scene3D::Loader::SamplerFlags::WRAP_T_SHIFT);
494       sampler = Scene3D::Loader::SamplerFlags::MakeSampler(samplerFlag);
495     }
496     textures.SetSampler(count, sampler);
497     count++;
498   }
499   return textures;
500 }
501
502 void Material::SetSampler(Scene3D::Material::TextureType index, Dali::Sampler sampler)
503 {
504   if(static_cast<uint32_t>(index) < static_cast<uint32_t>(TextureIndex::TEXTURE_TYPE_NUMBER))
505   {
506     mTextureInformations[index].mSampler = sampler;
507   }
508 }
509
510 Dali::Sampler Material::GetSampler(Scene3D::Material::TextureType index)
511 {
512   if(static_cast<uint32_t>(index) < static_cast<uint32_t>(TextureIndex::TEXTURE_TYPE_NUMBER))
513   {
514     return mTextureInformations[index].mSampler;
515   }
516   return Dali::Sampler();
517 }
518
519 std::string Material::GetVertexShader()
520 {
521   return mShaderData.mVertexShaderSource;
522 }
523
524 std::string Material::GetFragmentShader()
525 {
526   return mShaderData.mFragmentShaderSource;
527 }
528
529 void Material::Apply()
530 {
531   if(IsResourceReady())
532   {
533     UpdateMaterialData();
534     NotifyObserver();
535     return;
536   }
537   // The cases this material is applied to primitive are,
538   // 1. material is added on Primitive.
539   // When material is added on Primitive (1 case)
540   //   1-1. when IsResourceReady() returns true,
541   //     Primitive can takes information from Material
542   //   1-2. if false.
543   //     Material will noti to primitives when all resources are ready.
544   // 2. Some properties are changed
545   //   2-1. when IsResourceReady() returns true,
546   //     Call NotifyObserver directly.
547   //   2-2. if false.
548   //     Material will noti to primitives when all resources are ready.
549 }
550
551 void Material::AddObserver(MaterialModifyObserver* observer)
552 {
553   for(auto& observerEntity : mObservers)
554   {
555     if(observerEntity.first == observer)
556     {
557       observerEntity.second = true;
558       return;
559     }
560   }
561   mObservers.push_back({observer, true});
562 }
563
564 void Material::RemoveObserver(MaterialModifyObserver* observer)
565 {
566   // Block during notifying to observer
567   if(mObserverNotifying)
568   {
569     for(uint32_t i = 0; i < mObservers.size(); ++i)
570     {
571       if(mObservers[i].first == observer)
572       {
573         mObservers[i].second = false;
574         return;
575       }
576     }
577   }
578   else
579   {
580     for(uint32_t i = 0; i < mObservers.size(); ++i)
581     {
582       if(mObservers[i].first == observer)
583       {
584         mObservers.erase(mObservers.begin() + i);
585         return;
586       }
587     }
588   }
589 }
590
591 void Material::UpdateMaterialData()
592 {
593   uint32_t materialFlag = 0u;
594   if(mAlphaMode == Dali::Scene3D::Material::AlphaModeType::BLEND)
595   {
596     mIsOpaque = false;
597     mIsMask   = false;
598     materialFlag |= Scene3D::Loader::MaterialDefinition::TRANSPARENCY;
599   }
600   else if(mAlphaMode == Dali::Scene3D::Material::AlphaModeType::MASK)
601   {
602     mIsOpaque = true;
603     mIsMask   = true;
604   }
605   const bool hasTransparency = MaskMatch(materialFlag, Scene3D::Loader::MaterialDefinition::TRANSPARENCY);
606
607   for(auto&& textureInformation : mTextureInformations)
608   {
609     if(!textureInformation.mTexture)
610     {
611       continue;
612     }
613     materialFlag |= textureInformation.mSemantic;
614   }
615
616   if(mMaterialFlag != materialFlag || mShaderData.mVertexShaderSource.empty() || mShaderData.mFragmentShaderSource.empty())
617   {
618     mModifyFlag |= MaterialModifyObserver::ModifyFlag::SHADER;
619
620     mMaterialFlag                     = materialFlag;
621     mShaderData.mVertexShaderSource   = SHADER_DEFAULT_PHYSICALLY_BASED_SHADER_VERT.data();
622     mShaderData.mFragmentShaderSource = SHADER_DEFAULT_PHYSICALLY_BASED_SHADER_FRAG.data();
623
624     std::vector<std::string> defines;
625     defines.push_back(THREE_TEX_KEYWORD.data());
626     for(auto&& textureInformation : mTextureInformations)
627     {
628       if(!textureInformation.mTexture)
629       {
630         continue;
631       }
632       defines.push_back(textureInformation.mDefineKeyword);
633     }
634     defines.push_back(GLTF_CHANNELS_KEYWORD.data());
635
636     for(const auto& define : defines)
637     {
638       Scene3D::Loader::ShaderDefinition::ApplyDefine(mShaderData.mFragmentShaderSource, define);
639     }
640   }
641
642   // Finish to make all the material flag according to the gltf2-util.
643   // Then make defines as fallowing shader-definition-factory.
644
645   // The renderer State below can be used in primitive to set renderer properties.
646
647   // for renderer setting
648   mRendererState = Scene3D::Loader::RendererState::DEPTH_TEST;
649   if(!mDoubleSided)
650   {
651     mRendererState |= Scene3D::Loader::RendererState::CULL_BACK;
652   }
653
654   if(hasTransparency)
655   {
656     mRendererState = (mRendererState | Scene3D::Loader::RendererState::ALPHA_BLEND);
657   }
658 }
659
660 bool Material::IsResourceReady()
661 {
662   for(auto&& textureInformation : mTextureInformations)
663   {
664     if(!textureInformation.IsReady())
665     {
666       return false;
667     }
668   }
669   return true;
670 }
671
672 void Material::SetRendererUniform(Dali::Renderer renderer)
673 {
674   renderer.RegisterProperty("uColorFactor", mTextureInformations[TextureIndex::BASE_COLOR].mFactor);
675   renderer.RegisterProperty("uMetallicFactor", mTextureInformations[TextureIndex::METALLIC_ROUGHNESS].mFactor.x);
676   renderer.RegisterProperty("uRoughnessFactor", mTextureInformations[TextureIndex::METALLIC_ROUGHNESS].mFactor.y);
677   renderer.RegisterProperty("uNormalScale", mTextureInformations[TextureIndex::NORMAL].mFactor.x);
678   if(mTextureInformations[TextureIndex::OCCLUSION].mTexture)
679   {
680     renderer.RegisterProperty("uOcclusionStrength", mTextureInformations[TextureIndex::OCCLUSION].mFactor.x);
681   }
682   renderer.RegisterProperty("uEmissiveFactor", Vector3(mTextureInformations[TextureIndex::EMISSIVE].mFactor));
683   float dielectricSpecular = (Dali::Equals(mIor, -1.0)) ? 0.04f : powf((mIor - 1.0f) / (mIor + 1.0f), 2.0f);
684   renderer.RegisterProperty("uDielectricSpecular", dielectricSpecular);
685   renderer.RegisterProperty("uSpecularFactor", mTextureInformations[TextureIndex::SPECULAR].mFactor.x);
686   renderer.RegisterProperty("uSpecularColorFactor", Vector3(mTextureInformations[TextureIndex::SPECULAR_COLOR].mFactor));
687
688   float opaque = mIsOpaque ? 1.0f : 0.0f;
689   float mask   = mIsMask ? 1.0f : 0.0f;
690   renderer.RegisterProperty("uOpaque", opaque);
691   renderer.RegisterProperty("uMask", mask);
692   renderer.RegisterProperty("uAlphaThreshold", mAlphaCutoff);
693
694   renderer.RegisterProperty("uCubeMatrix", Matrix::IDENTITY);
695
696   renderer.RegisterProperty(Scene3D::Loader::NodeDefinition::GetIblMaxLodUniformName().data(), 6.f);
697   renderer.RegisterProperty(Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName().data(), 1.0f);
698   renderer.RegisterProperty(Scene3D::Loader::NodeDefinition::GetIblYDirectionUniformName().data(), Vector3(1.0f, -1.0, 1.0));
699
700   std::string lightCountPropertyName(Scene3D::Internal::Light::GetLightCountUniformName());
701   renderer.RegisterProperty(lightCountPropertyName, 0);
702
703   uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
704   for(uint32_t i = 0; i < maxLightCount; ++i)
705   {
706     std::string lightDirectionPropertyName(Scene3D::Internal::Light::GetLightDirectionUniformName());
707     lightDirectionPropertyName += "[" + std::to_string(i) + "]";
708     renderer.RegisterProperty(lightDirectionPropertyName, Vector3::ZAXIS);
709
710     std::string lightColorPropertyName(Scene3D::Internal::Light::GetLightColorUniformName());
711     lightColorPropertyName += "[" + std::to_string(i) + "]";
712     renderer.RegisterProperty(lightColorPropertyName, Vector3(Color::WHITE));
713   }
714
715   Scene3D::Loader::RendererState::Apply(mRendererState, renderer);
716 }
717
718 uint32_t Material::GetSpecularImageBasedLightTextureOffset()
719 {
720   return OFFSET_FOR_SPECULAR_CUBE_TEXTURE;
721 }
722
723 uint32_t Material::GetDiffuseImageBasedLightTextureOffset()
724 {
725   return OFFSET_FOR_DIFFUSE_CUBE_TEXTURE;
726 }
727
728 std::string_view Material::GetImageBasedLightScaleFactorName()
729 {
730   return Dali::Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName();
731 }
732
733 std::string_view Material::GetImageBasedLightMaxLodUniformName()
734 {
735   return Dali::Scene3D::Loader::NodeDefinition::GetIblMaxLodUniformName();
736 }
737
738 void Material::ResetFlag()
739 {
740   mModifyFlag = MaterialModifyObserver::ModifyFlag::NONE;
741 }
742
743 void Material::NotifyObserver()
744 {
745   if(mModifyFlag != MaterialModifyObserver::ModifyFlag::NONE && IsResourceReady())
746   {
747     if(mObserverNotifying)
748     {
749       DALI_LOG_ERROR("Notify during observing is not allowed.");
750       return;
751     }
752
753     Dali::Scene3D::Material handle(this); // Keep itself's life during notify
754
755     // Copy the flag due to the flag can be changed during observe.
756     MaterialModifyObserver::ModifyFlag copiedFlag = mModifyFlag;
757     mModifyFlag                                   = MaterialModifyObserver::ModifyFlag::NONE;
758
759     // Need to block mObserver container change during observe
760     mObserverNotifying = true;
761     for(uint32_t i = 0; i < mObservers.size(); ++i)
762     {
763       if(mObservers[i].second)
764       {
765         mObservers[i].first->OnMaterialModified(handle, copiedFlag);
766       }
767     }
768     mObserverNotifying = false;
769
770     // Resolve observer queue during notify
771     mObservers.erase(std::remove_if(mObservers.begin(), mObservers.end(), [](auto& e) { return !e.second; }), mObservers.end());
772   }
773 }
774
775 void Material::RequestTextureLoad(TextureInformation& textureInformation, const std::string& url)
776 {
777   if(textureInformation.mUrl == url)
778   {
779     return;
780   }
781
782   textureInformation.mUrl = url;
783   if(textureInformation.mLoadingTaskId != INVALID_INDEX)
784   {
785     mAsyncImageLoader.Cancel(textureInformation.mLoadingTaskId);
786     textureInformation.mLoadingTaskId = INVALID_INDEX;
787   }
788
789   if(url.empty())
790   {
791     textureInformation.mTexture.Reset();
792     return;
793   }
794   textureInformation.mLoadingTaskId = mAsyncImageLoader.Load(url);
795 }
796
797 void Material::TextureLoadComplete(uint32_t loadedTaskId, PixelData pixelData)
798 {
799   for(auto&& textureInformation : mTextureInformations)
800   {
801     if(textureInformation.mLoadingTaskId != loadedTaskId)
802     {
803       continue;
804     }
805
806     if(pixelData)
807     {
808       textureInformation.mTexture = Texture::New(Dali::TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight());
809       textureInformation.mTexture.Upload(pixelData);
810     }
811     textureInformation.mLoadingTaskId = INVALID_INDEX;
812     break;
813   }
814
815   if(IsResourceReady())
816   {
817     ResourcesLoadComplete();
818   }
819 }
820
821 void Material::ResourcesLoadComplete()
822 {
823   mModifyFlag |= MaterialModifyObserver::ModifyFlag::TEXTURE;
824   Apply();
825 }
826
827 } // namespace Internal
828
829 } // namespace Scene3D
830
831 } // namespace Dali