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