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