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