[dali_2.3.5] Merge branch '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     case Dali::Scene3D::Material::Property::DEPTH_INDEX:
328     {
329       int32_t depthIndex = 0;
330       if(propertyValue.Get(depthIndex) && mDepthIndex != depthIndex)
331       {
332         mDepthIndex = depthIndex;
333         mModifyFlag |= MaterialModifyObserver::ModifyFlag::PROPERTY;
334       }
335       break;
336     }
337   }
338
339   if(needToApply)
340   {
341     Apply();
342   }
343 }
344
345 Dali::Property::Value Material::GetProperty(Dali::Property::Index index) const
346 {
347   Dali::Property::Value value;
348   switch(index)
349   {
350     case Dali::Scene3D::Material::Property::NAME:
351     {
352       value = mName;
353       break;
354     }
355     case Dali::Scene3D::Material::Property::BASE_COLOR_URL:
356     {
357       value = mTextureInformations[TextureIndex::BASE_COLOR].mUrl;
358       break;
359     }
360     case Dali::Scene3D::Material::Property::BASE_COLOR_FACTOR:
361     {
362       value = mTextureInformations[TextureIndex::BASE_COLOR].mFactor;
363       break;
364     }
365     case Dali::Scene3D::Material::Property::METALLIC_ROUGHNESS_URL:
366     {
367       value = mTextureInformations[TextureIndex::METALLIC_ROUGHNESS].mUrl;
368       break;
369     }
370     case Dali::Scene3D::Material::Property::METALLIC_FACTOR:
371     {
372       value = mTextureInformations[TextureIndex::METALLIC_ROUGHNESS].mFactor.x;
373       break;
374     }
375     case Dali::Scene3D::Material::Property::ROUGHNESS_FACTOR:
376     {
377       value = mTextureInformations[TextureIndex::METALLIC_ROUGHNESS].mFactor.y;
378       break;
379     }
380     case Dali::Scene3D::Material::Property::NORMAL_URL:
381     {
382       value = mTextureInformations[TextureIndex::NORMAL].mUrl;
383       break;
384     }
385     case Dali::Scene3D::Material::Property::NORMAL_SCALE:
386     {
387       value = mTextureInformations[TextureIndex::NORMAL].mFactor.x;
388       break;
389     }
390     case Dali::Scene3D::Material::Property::OCCLUSION_URL:
391     {
392       value = mTextureInformations[TextureIndex::OCCLUSION].mUrl;
393       break;
394     }
395     case Dali::Scene3D::Material::Property::OCCLUSION_STRENGTH:
396     {
397       value = mTextureInformations[TextureIndex::OCCLUSION].mFactor.x;
398       break;
399     }
400     case Dali::Scene3D::Material::Property::EMISSIVE_URL:
401     {
402       value = mTextureInformations[TextureIndex::EMISSIVE].mUrl;
403       break;
404     }
405     case Dali::Scene3D::Material::Property::EMISSIVE_FACTOR:
406     {
407       value = Vector3(mTextureInformations[TextureIndex::EMISSIVE].mFactor);
408       break;
409     }
410     case Dali::Scene3D::Material::Property::ALPHA_MODE:
411     {
412       value = mAlphaMode;
413       break;
414     }
415     case Dali::Scene3D::Material::Property::ALPHA_CUTOFF:
416     {
417       value = mAlphaCutoff;
418       break;
419     }
420     case Dali::Scene3D::Material::Property::DOUBLE_SIDED:
421     {
422       value = mDoubleSided;
423       break;
424     }
425     case Dali::Scene3D::Material::Property::IOR:
426     {
427       value = mIor;
428       break;
429     }
430     case Dali::Scene3D::Material::Property::SPECULAR_URL:
431     {
432       value = mTextureInformations[TextureIndex::SPECULAR].mUrl;
433       break;
434     }
435     case Dali::Scene3D::Material::Property::SPECULAR_FACTOR:
436     {
437       value = mTextureInformations[TextureIndex::SPECULAR].mFactor.x;
438       break;
439     }
440     case Dali::Scene3D::Material::Property::SPECULAR_COLOR_URL:
441     {
442       value = mTextureInformations[TextureIndex::SPECULAR_COLOR].mUrl;
443       break;
444     }
445     case Dali::Scene3D::Material::Property::SPECULAR_COLOR_FACTOR:
446     {
447       value = Vector3(mTextureInformations[TextureIndex::SPECULAR_COLOR].mFactor);
448       break;
449     }
450     case Dali::Scene3D::Material::Property::DEPTH_INDEX:
451     {
452       value = mDepthIndex;
453       break;
454     }
455   }
456   return value;
457 }
458
459 void Material::SetTextureInformation(Scene3D::Material::TextureType index, TextureInformation&& textureInformation)
460 {
461   mTextureInformations[index].mFactor  = textureInformation.mFactor;
462   mTextureInformations[index].mSampler = textureInformation.mSampler;
463   mTextureInformations[index].mTexture = textureInformation.mTexture;
464   mTextureInformations[index].mUrl     = std::move(textureInformation.mUrl);
465 }
466
467 void Material::SetTexture(Scene3D::Material::TextureType index, Dali::Texture texture)
468 {
469   if(static_cast<uint32_t>(index) < static_cast<uint32_t>(TextureIndex::TEXTURE_TYPE_NUMBER))
470   {
471     if(mTextureInformations[index].mTexture != texture)
472     {
473       if(mTextureInformations[index].mLoadingTaskId != INVALID_INDEX)
474       {
475         mAsyncImageLoader.Cancel(mTextureInformations[index].mLoadingTaskId);
476         mTextureInformations[index].mLoadingTaskId = INVALID_INDEX;
477       }
478       mTextureInformations[index].mTexture = texture;
479       if(IsResourceReady())
480       {
481         ResourcesLoadComplete();
482       }
483     }
484   }
485 }
486
487 Dali::Texture Material::GetTexture(Scene3D::Material::TextureType index)
488 {
489   if(static_cast<uint32_t>(index) < static_cast<uint32_t>(TextureIndex::TEXTURE_TYPE_NUMBER))
490   {
491     return mTextureInformations[index].mTexture;
492   }
493   return Dali::Texture();
494 }
495
496 TextureSet Material::GetTextureSet()
497 {
498   TextureSet textures = TextureSet::New();
499   for(uint32_t i = 0, count = 0; i < TEXTURE_TYPE_NUMBER; ++i)
500   {
501     if(!mTextureInformations[i].mTexture)
502     {
503       continue;
504     }
505     textures.SetTexture(count, mTextureInformations[i].mTexture);
506     Sampler sampler = mTextureInformations[i].mSampler;
507     if(!sampler)
508     {
509       auto samplerFlag = Scene3D::Loader::SamplerFlags::FILTER_LINEAR | (Scene3D::Loader::SamplerFlags::FILTER_LINEAR << Scene3D::Loader::SamplerFlags::FILTER_MAG_SHIFT) |
510                          (Scene3D::Loader::SamplerFlags::WRAP_REPEAT << Scene3D::Loader::SamplerFlags::WRAP_S_SHIFT) | (Scene3D::Loader::SamplerFlags::WRAP_REPEAT << Scene3D::Loader::SamplerFlags::WRAP_T_SHIFT);
511       sampler = Scene3D::Loader::SamplerFlags::MakeSampler(samplerFlag);
512     }
513     textures.SetSampler(count, sampler);
514     count++;
515   }
516   return textures;
517 }
518
519 void Material::SetSampler(Scene3D::Material::TextureType index, Dali::Sampler sampler)
520 {
521   if(static_cast<uint32_t>(index) < static_cast<uint32_t>(TextureIndex::TEXTURE_TYPE_NUMBER))
522   {
523     mTextureInformations[index].mSampler = sampler;
524   }
525 }
526
527 Dali::Sampler Material::GetSampler(Scene3D::Material::TextureType index)
528 {
529   if(static_cast<uint32_t>(index) < static_cast<uint32_t>(TextureIndex::TEXTURE_TYPE_NUMBER))
530   {
531     return mTextureInformations[index].mSampler;
532   }
533   return Dali::Sampler();
534 }
535
536 Scene3D::Loader::ShaderOption Material::GetShaderOption() const
537 {
538   return mShaderOption;
539 }
540
541 void Material::Apply()
542 {
543   if(IsResourceReady())
544   {
545     UpdateMaterialData();
546     NotifyObserver();
547     return;
548   }
549   // The cases this material is applied to primitive are,
550   // 1. material is added on Primitive.
551   // When material is added on Primitive (1 case)
552   //   1-1. when IsResourceReady() returns true,
553   //     Primitive can takes information from Material
554   //   1-2. if false.
555   //     Material will noti to primitives when all resources are ready.
556   // 2. Some properties are changed
557   //   2-1. when IsResourceReady() returns true,
558   //     Call NotifyObserver directly.
559   //   2-2. if false.
560   //     Material will noti to primitives when all resources are ready.
561 }
562
563 void Material::AddObserver(MaterialModifyObserver* observer)
564 {
565   for(auto& observerEntity : mObservers)
566   {
567     if(observerEntity.first == observer)
568     {
569       observerEntity.second = true;
570       return;
571     }
572   }
573   mObservers.push_back({observer, true});
574 }
575
576 void Material::RemoveObserver(MaterialModifyObserver* observer)
577 {
578   // Block during notifying to observer
579   if(mObserverNotifying)
580   {
581     for(uint32_t i = 0; i < mObservers.size(); ++i)
582     {
583       if(mObservers[i].first == observer)
584       {
585         mObservers[i].second = false;
586         return;
587       }
588     }
589   }
590   else
591   {
592     for(uint32_t i = 0; i < mObservers.size(); ++i)
593     {
594       if(mObservers[i].first == observer)
595       {
596         mObservers.erase(mObservers.begin() + i);
597         return;
598       }
599     }
600   }
601 }
602
603 void Material::UpdateMaterialData()
604 {
605   uint32_t materialFlag = 0u;
606   if(mAlphaMode == Dali::Scene3D::Material::AlphaModeType::BLEND)
607   {
608     mIsOpaque = false;
609     mIsMask   = false;
610     materialFlag |= Scene3D::Loader::MaterialDefinition::TRANSPARENCY;
611   }
612   else if(mAlphaMode == Dali::Scene3D::Material::AlphaModeType::MASK)
613   {
614     mIsOpaque = true;
615     mIsMask   = true;
616   }
617   const bool hasTransparency = MaskMatch(materialFlag, Scene3D::Loader::MaterialDefinition::TRANSPARENCY);
618
619   for(auto&& textureInformation : mTextureInformations)
620   {
621     if(!textureInformation.mTexture)
622     {
623       continue;
624     }
625     materialFlag |= textureInformation.mSemantic;
626   }
627
628   if(mMaterialFlag != materialFlag)
629   {
630     mModifyFlag |= MaterialModifyObserver::ModifyFlag::SHADER;
631
632     mMaterialFlag = materialFlag;
633
634     mShaderOption = Loader::ShaderOption();
635     for(auto&& textureInformation : mTextureInformations)
636     {
637       if(!textureInformation.mTexture)
638       {
639         continue;
640       }
641       mShaderOption.AddOption(textureInformation.mShaderOptionType);
642     }
643     mShaderOption.AddOption(Loader::ShaderOption::Type::THREE_TEXTURE);
644     mShaderOption.AddOption(Loader::ShaderOption::Type::GLTF_CHANNELS);
645     if(materialFlag & Scene3D::Loader::MaterialDefinition::TRANSPARENCY)
646     {
647       mShaderOption.SetTransparency();
648     }
649   }
650
651   // Finish to make all the material flag according to the gltf2-util.
652   // Then make defines as fallowing shader-manager.
653
654   // The renderer State below can be used in primitive to set renderer properties.
655
656   // for renderer setting
657   mRendererState = Scene3D::Loader::RendererState::DEPTH_TEST;
658   if(!mDoubleSided)
659   {
660     mRendererState |= Scene3D::Loader::RendererState::CULL_BACK;
661   }
662
663   if(hasTransparency)
664   {
665     mRendererState = (mRendererState | Scene3D::Loader::RendererState::ALPHA_BLEND);
666   }
667 }
668
669 bool Material::IsResourceReady()
670 {
671   for(auto&& textureInformation : mTextureInformations)
672   {
673     if(!textureInformation.IsReady())
674     {
675       return false;
676     }
677   }
678   return true;
679 }
680
681 void Material::SetRendererUniform(Dali::Renderer renderer)
682 {
683   renderer.RegisterProperty("uColorFactor", mTextureInformations[TextureIndex::BASE_COLOR].mFactor);
684   renderer.RegisterProperty("uMetallicFactor", mTextureInformations[TextureIndex::METALLIC_ROUGHNESS].mFactor.x);
685   renderer.RegisterProperty("uRoughnessFactor", mTextureInformations[TextureIndex::METALLIC_ROUGHNESS].mFactor.y);
686   renderer.RegisterProperty("uNormalScale", mTextureInformations[TextureIndex::NORMAL].mFactor.x);
687   if(mTextureInformations[TextureIndex::OCCLUSION].mTexture)
688   {
689     renderer.RegisterProperty("uOcclusionStrength", mTextureInformations[TextureIndex::OCCLUSION].mFactor.x);
690   }
691   renderer.RegisterProperty("uEmissiveFactor", Vector3(mTextureInformations[TextureIndex::EMISSIVE].mFactor));
692   float dielectricSpecular = (Dali::Equals(mIor, -1.0)) ? 0.04f : powf((mIor - 1.0f) / (mIor + 1.0f), 2.0f);
693   renderer.RegisterProperty("uDielectricSpecular", dielectricSpecular);
694   renderer.RegisterProperty("uSpecularFactor", mTextureInformations[TextureIndex::SPECULAR].mFactor.x);
695   renderer.RegisterProperty("uSpecularColorFactor", Vector3(mTextureInformations[TextureIndex::SPECULAR_COLOR].mFactor));
696
697   // No requirement to use texture transform for runtime generated models.
698   renderer.RegisterProperty("uBaseColorTextureTransformAvailable", 0.0f);
699   renderer.RegisterProperty("uNormalTextureTransformAvailable", 0.0f);
700   renderer.RegisterProperty("uNormalRoughnessTextureTransformAvailable", 0.0f);
701   renderer.RegisterProperty("uMetalRoughnessTextureTransformAvailable", 0.0f);
702   renderer.RegisterProperty("uOcclusionTextureTransformAvailable", 0.0f);
703   renderer.RegisterProperty("uEmissiveTextureTransformAvailable", 0.0f);
704
705   float opaque = mIsOpaque ? 1.0f : 0.0f;
706   float mask   = mIsMask ? 1.0f : 0.0f;
707   renderer.RegisterProperty("uOpaque", opaque);
708   renderer.RegisterProperty("uMask", mask);
709   renderer.RegisterProperty("uAlphaThreshold", mAlphaCutoff);
710
711   renderer.RegisterProperty("uCubeMatrix", Matrix::IDENTITY);
712
713   renderer.RegisterProperty(Scene3D::Loader::NodeDefinition::GetIblMaxLodUniformName().data(), 6.f);
714   renderer.RegisterProperty(Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName().data(), 1.0f);
715   renderer.RegisterProperty(Scene3D::Loader::NodeDefinition::GetIblYDirectionUniformName().data(), Vector3(1.0f, -1.0, 1.0));
716
717   Scene3D::Loader::RendererState::Apply(mRendererState, renderer);
718 }
719
720 void Material::SetRendererProperty(Dali::Renderer renderer)
721 {
722   renderer.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, mDepthIndex);
723 }
724
725 uint32_t Material::GetShadowMapTextureOffset()
726 {
727   return OFFSET_FOR_SHADOW_MAP_TEXTURE;
728 }
729
730 uint32_t Material::GetSpecularImageBasedLightTextureOffset()
731 {
732   return OFFSET_FOR_SPECULAR_CUBE_TEXTURE;
733 }
734
735 uint32_t Material::GetDiffuseImageBasedLightTextureOffset()
736 {
737   return OFFSET_FOR_DIFFUSE_CUBE_TEXTURE;
738 }
739
740 std::string_view Material::GetImageBasedLightScaleFactorName()
741 {
742   return Dali::Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName();
743 }
744
745 std::string_view Material::GetImageBasedLightMaxLodUniformName()
746 {
747   return Dali::Scene3D::Loader::NodeDefinition::GetIblMaxLodUniformName();
748 }
749
750 void Material::ResetFlag()
751 {
752   mModifyFlag = MaterialModifyObserver::ModifyFlag::NONE;
753 }
754
755 void Material::NotifyObserver()
756 {
757   if(mModifyFlag != MaterialModifyObserver::ModifyFlag::NONE && IsResourceReady())
758   {
759     if(mObserverNotifying)
760     {
761       DALI_LOG_ERROR("Notify during observing is not allowed.");
762       return;
763     }
764
765     Dali::Scene3D::Material handle(this); // Keep itself's life during notify
766
767     // Copy the flag due to the flag can be changed during observe.
768     MaterialModifyObserver::ModifyFlag copiedFlag = mModifyFlag;
769     mModifyFlag                                   = MaterialModifyObserver::ModifyFlag::NONE;
770
771     // Need to block mObserver container change during observe
772     mObserverNotifying = true;
773     for(uint32_t i = 0; i < mObservers.size(); ++i)
774     {
775       if(mObservers[i].second)
776       {
777         mObservers[i].first->OnMaterialModified(handle, copiedFlag);
778       }
779     }
780     mObserverNotifying = false;
781
782     // Resolve observer queue during notify
783     mObservers.erase(std::remove_if(mObservers.begin(), mObservers.end(), [](auto& e) { return !e.second; }),
784                      mObservers.end());
785   }
786 }
787
788 void Material::RequestTextureLoad(TextureInformation& textureInformation, const std::string& url)
789 {
790   if(textureInformation.mUrl == url)
791   {
792     return;
793   }
794
795   textureInformation.mUrl = url;
796   if(textureInformation.mLoadingTaskId != INVALID_INDEX)
797   {
798     mAsyncImageLoader.Cancel(textureInformation.mLoadingTaskId);
799     textureInformation.mLoadingTaskId = INVALID_INDEX;
800   }
801
802   if(url.empty())
803   {
804     textureInformation.mTexture.Reset();
805     return;
806   }
807   textureInformation.mLoadingTaskId = mAsyncImageLoader.Load(url);
808 }
809
810 void Material::TextureLoadComplete(uint32_t loadedTaskId, PixelData pixelData)
811 {
812   for(auto&& textureInformation : mTextureInformations)
813   {
814     if(textureInformation.mLoadingTaskId != loadedTaskId)
815     {
816       continue;
817     }
818
819     if(pixelData)
820     {
821       textureInformation.mTexture = Texture::New(Dali::TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight());
822       textureInformation.mTexture.Upload(pixelData);
823     }
824     textureInformation.mLoadingTaskId = INVALID_INDEX;
825     break;
826   }
827
828   if(IsResourceReady())
829   {
830     ResourcesLoadComplete();
831   }
832 }
833
834 void Material::ResourcesLoadComplete()
835 {
836   mModifyFlag |= MaterialModifyObserver::ModifyFlag::TEXTURE;
837   Apply();
838 }
839
840 } // namespace Internal
841
842 } // namespace Scene3D
843
844 } // namespace Dali