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