Merge branch 'devel/master' into tizen
[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/utils.h>
34 #include <dali-scene3d/public-api/loader/shader-definition-option.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].mDefineKeyword         = Scene3D::Loader::ShaderDefinitionOption::GetDefineKeyword(Loader::ShaderDefinitionOption::Type::BASE_COLOR_TEXTURE).data();
105   mTextureInformations[METALLIC_ROUGHNESS].mDefineKeyword = Scene3D::Loader::ShaderDefinitionOption::GetDefineKeyword(Loader::ShaderDefinitionOption::Type::METALLIC_ROUGHNESS_TEXTURE).data();
106   mTextureInformations[NORMAL].mDefineKeyword             = Scene3D::Loader::ShaderDefinitionOption::GetDefineKeyword(Loader::ShaderDefinitionOption::Type::NORMAL_TEXTURE).data();
107   mTextureInformations[OCCLUSION].mDefineKeyword          = Scene3D::Loader::ShaderDefinitionOption::GetDefineKeyword(Loader::ShaderDefinitionOption::Type::OCCLUSION).data();
108   mTextureInformations[EMISSIVE].mDefineKeyword           = Scene3D::Loader::ShaderDefinitionOption::GetDefineKeyword(Loader::ShaderDefinitionOption::Type::EMISSIVE).data();
109   mTextureInformations[SPECULAR].mDefineKeyword           = Scene3D::Loader::ShaderDefinitionOption::GetDefineKeyword(Loader::ShaderDefinitionOption::Type::SPECULAR).data();
110   mTextureInformations[SPECULAR_COLOR].mDefineKeyword     = Scene3D::Loader::ShaderDefinitionOption::GetDefineKeyword(Loader::ShaderDefinitionOption::Type::SPECULAR_COLOR).data();
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 std::string Material::GetVertexShader()
521 {
522   return mShaderData.mVertexShaderSource;
523 }
524
525 std::string Material::GetFragmentShader()
526 {
527   return mShaderData.mFragmentShaderSource;
528 }
529
530 void Material::Apply()
531 {
532   if(IsResourceReady())
533   {
534     UpdateMaterialData();
535     NotifyObserver();
536     return;
537   }
538   // The cases this material is applied to primitive are,
539   // 1. material is added on Primitive.
540   // When material is added on Primitive (1 case)
541   //   1-1. when IsResourceReady() returns true,
542   //     Primitive can takes information from Material
543   //   1-2. if false.
544   //     Material will noti to primitives when all resources are ready.
545   // 2. Some properties are changed
546   //   2-1. when IsResourceReady() returns true,
547   //     Call NotifyObserver directly.
548   //   2-2. if false.
549   //     Material will noti to primitives when all resources are ready.
550 }
551
552 void Material::AddObserver(MaterialModifyObserver* observer)
553 {
554   for(auto& observerEntity : mObservers)
555   {
556     if(observerEntity.first == observer)
557     {
558       observerEntity.second = true;
559       return;
560     }
561   }
562   mObservers.push_back({observer, true});
563 }
564
565 void Material::RemoveObserver(MaterialModifyObserver* observer)
566 {
567   // Block during notifying to observer
568   if(mObserverNotifying)
569   {
570     for(uint32_t i = 0; i < mObservers.size(); ++i)
571     {
572       if(mObservers[i].first == observer)
573       {
574         mObservers[i].second = false;
575         return;
576       }
577     }
578   }
579   else
580   {
581     for(uint32_t i = 0; i < mObservers.size(); ++i)
582     {
583       if(mObservers[i].first == observer)
584       {
585         mObservers.erase(mObservers.begin() + i);
586         return;
587       }
588     }
589   }
590 }
591
592 void Material::UpdateMaterialData()
593 {
594   uint32_t materialFlag = 0u;
595   if(mAlphaMode == Dali::Scene3D::Material::AlphaModeType::BLEND)
596   {
597     mIsOpaque = false;
598     mIsMask   = false;
599     materialFlag |= Scene3D::Loader::MaterialDefinition::TRANSPARENCY;
600   }
601   else if(mAlphaMode == Dali::Scene3D::Material::AlphaModeType::MASK)
602   {
603     mIsOpaque = true;
604     mIsMask   = true;
605   }
606   const bool hasTransparency = MaskMatch(materialFlag, Scene3D::Loader::MaterialDefinition::TRANSPARENCY);
607
608   for(auto&& textureInformation : mTextureInformations)
609   {
610     if(!textureInformation.mTexture)
611     {
612       continue;
613     }
614     materialFlag |= textureInformation.mSemantic;
615   }
616
617   if(mMaterialFlag != materialFlag || mShaderData.mVertexShaderSource.empty() || mShaderData.mFragmentShaderSource.empty())
618   {
619     mModifyFlag |= MaterialModifyObserver::ModifyFlag::SHADER;
620
621     mMaterialFlag                     = materialFlag;
622     mShaderData.mVertexShaderSource   = SHADER_DEFAULT_PHYSICALLY_BASED_SHADER_VERT.data();
623     mShaderData.mFragmentShaderSource = SHADER_DEFAULT_PHYSICALLY_BASED_SHADER_FRAG.data();
624
625     std::vector<std::string> defines;
626     defines.push_back(THREE_TEX_KEYWORD.data());
627     for(auto&& textureInformation : mTextureInformations)
628     {
629       if(!textureInformation.mTexture)
630       {
631         continue;
632       }
633       defines.push_back(textureInformation.mDefineKeyword);
634     }
635     defines.push_back(GLTF_CHANNELS_KEYWORD.data());
636
637     for(const auto& define : defines)
638     {
639       Scene3D::Loader::ShaderDefinition::ApplyDefine(mShaderData.mFragmentShaderSource, define);
640     }
641   }
642
643   // Finish to make all the material flag according to the gltf2-util.
644   // Then make defines as fallowing shader-definition-factory.
645
646   // The renderer State below can be used in primitive to set renderer properties.
647
648   // for renderer setting
649   mRendererState = Scene3D::Loader::RendererState::DEPTH_TEST;
650   if(!mDoubleSided)
651   {
652     mRendererState |= Scene3D::Loader::RendererState::CULL_BACK;
653   }
654
655   if(hasTransparency)
656   {
657     mRendererState = (mRendererState | Scene3D::Loader::RendererState::ALPHA_BLEND);
658   }
659 }
660
661 bool Material::IsResourceReady()
662 {
663   for(auto&& textureInformation : mTextureInformations)
664   {
665     if(!textureInformation.IsReady())
666     {
667       return false;
668     }
669   }
670   return true;
671 }
672
673 void Material::SetRendererUniform(Dali::Renderer renderer)
674 {
675   renderer.RegisterProperty("uColorFactor", mTextureInformations[TextureIndex::BASE_COLOR].mFactor);
676   renderer.RegisterProperty("uMetallicFactor", mTextureInformations[TextureIndex::METALLIC_ROUGHNESS].mFactor.x);
677   renderer.RegisterProperty("uRoughnessFactor", mTextureInformations[TextureIndex::METALLIC_ROUGHNESS].mFactor.y);
678   renderer.RegisterProperty("uNormalScale", mTextureInformations[TextureIndex::NORMAL].mFactor.x);
679   if(mTextureInformations[TextureIndex::OCCLUSION].mTexture)
680   {
681     renderer.RegisterProperty("uOcclusionStrength", mTextureInformations[TextureIndex::OCCLUSION].mFactor.x);
682   }
683   renderer.RegisterProperty("uEmissiveFactor", Vector3(mTextureInformations[TextureIndex::EMISSIVE].mFactor));
684   float dielectricSpecular = (Dali::Equals(mIor, -1.0)) ? 0.04f : powf((mIor - 1.0f) / (mIor + 1.0f), 2.0f);
685   renderer.RegisterProperty("uDielectricSpecular", dielectricSpecular);
686   renderer.RegisterProperty("uSpecularFactor", mTextureInformations[TextureIndex::SPECULAR].mFactor.x);
687   renderer.RegisterProperty("uSpecularColorFactor", Vector3(mTextureInformations[TextureIndex::SPECULAR_COLOR].mFactor));
688
689   float opaque = mIsOpaque ? 1.0f : 0.0f;
690   float mask   = mIsMask ? 1.0f : 0.0f;
691   renderer.RegisterProperty("uOpaque", opaque);
692   renderer.RegisterProperty("uMask", mask);
693   renderer.RegisterProperty("uAlphaThreshold", mAlphaCutoff);
694
695   renderer.RegisterProperty("uCubeMatrix", Matrix::IDENTITY);
696
697   renderer.RegisterProperty(Scene3D::Loader::NodeDefinition::GetIblMaxLodUniformName().data(), 6.f);
698   renderer.RegisterProperty(Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName().data(), 1.0f);
699   renderer.RegisterProperty(Scene3D::Loader::NodeDefinition::GetIblYDirectionUniformName().data(), Vector3(1.0f, -1.0, 1.0));
700
701   std::string lightCountPropertyName(Scene3D::Internal::Light::GetLightCountUniformName());
702   renderer.RegisterProperty(lightCountPropertyName, 0);
703
704   uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
705   for(uint32_t i = 0; i < maxLightCount; ++i)
706   {
707     std::string lightDirectionPropertyName(Scene3D::Internal::Light::GetLightDirectionUniformName());
708     lightDirectionPropertyName += "[" + std::to_string(i) + "]";
709     renderer.RegisterProperty(lightDirectionPropertyName, Vector3::ZAXIS);
710
711     std::string lightColorPropertyName(Scene3D::Internal::Light::GetLightColorUniformName());
712     lightColorPropertyName += "[" + std::to_string(i) + "]";
713     renderer.RegisterProperty(lightColorPropertyName, Vector3(Color::WHITE));
714   }
715
716   Scene3D::Loader::RendererState::Apply(mRendererState, renderer);
717 }
718
719 uint32_t Material::GetSpecularImageBasedLightTextureOffset()
720 {
721   return OFFSET_FOR_SPECULAR_CUBE_TEXTURE;
722 }
723
724 uint32_t Material::GetDiffuseImageBasedLightTextureOffset()
725 {
726   return OFFSET_FOR_DIFFUSE_CUBE_TEXTURE;
727 }
728
729 std::string_view Material::GetImageBasedLightScaleFactorName()
730 {
731   return Dali::Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName();
732 }
733
734 std::string_view Material::GetImageBasedLightMaxLodUniformName()
735 {
736   return Dali::Scene3D::Loader::NodeDefinition::GetIblMaxLodUniformName();
737 }
738
739 void Material::ResetFlag()
740 {
741   mModifyFlag = MaterialModifyObserver::ModifyFlag::NONE;
742 }
743
744 void Material::NotifyObserver()
745 {
746   if(mModifyFlag != MaterialModifyObserver::ModifyFlag::NONE && IsResourceReady())
747   {
748     if(mObserverNotifying)
749     {
750       DALI_LOG_ERROR("Notify during observing is not allowed.");
751       return;
752     }
753
754     Dali::Scene3D::Material handle(this); // Keep itself's life during notify
755
756     // Copy the flag due to the flag can be changed during observe.
757     MaterialModifyObserver::ModifyFlag copiedFlag = mModifyFlag;
758     mModifyFlag                                   = MaterialModifyObserver::ModifyFlag::NONE;
759
760     // Need to block mObserver container change during observe
761     mObserverNotifying = true;
762     for(uint32_t i = 0; i < mObservers.size(); ++i)
763     {
764       if(mObservers[i].second)
765       {
766         mObservers[i].first->OnMaterialModified(handle, copiedFlag);
767       }
768     }
769     mObserverNotifying = false;
770
771     // Resolve observer queue during notify
772     mObservers.erase(std::remove_if(mObservers.begin(), mObservers.end(), [](auto& e) { return !e.second; }), mObservers.end());
773   }
774 }
775
776 void Material::RequestTextureLoad(TextureInformation& textureInformation, const std::string& url)
777 {
778   if(textureInformation.mUrl == url)
779   {
780     return;
781   }
782
783   textureInformation.mUrl = url;
784   if(textureInformation.mLoadingTaskId != INVALID_INDEX)
785   {
786     mAsyncImageLoader.Cancel(textureInformation.mLoadingTaskId);
787     textureInformation.mLoadingTaskId = INVALID_INDEX;
788   }
789
790   if(url.empty())
791   {
792     textureInformation.mTexture.Reset();
793     return;
794   }
795   textureInformation.mLoadingTaskId = mAsyncImageLoader.Load(url);
796 }
797
798 void Material::TextureLoadComplete(uint32_t loadedTaskId, PixelData pixelData)
799 {
800   for(auto&& textureInformation : mTextureInformations)
801   {
802     if(textureInformation.mLoadingTaskId != loadedTaskId)
803     {
804       continue;
805     }
806
807     if(pixelData)
808     {
809       textureInformation.mTexture = Texture::New(Dali::TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight());
810       textureInformation.mTexture.Upload(pixelData);
811     }
812     textureInformation.mLoadingTaskId = INVALID_INDEX;
813     break;
814   }
815
816   if(IsResourceReady())
817   {
818     ResourcesLoadComplete();
819   }
820 }
821
822 void Material::ResourcesLoadComplete()
823 {
824   mModifyFlag |= MaterialModifyObserver::ModifyFlag::TEXTURE;
825   Apply();
826 }
827
828 } // namespace Internal
829
830 } // namespace Scene3D
831
832 } // namespace Dali