Use default PBR shader to the scene-loader
[platform/core/uifw/dali-toolkit.git] / dali-scene-loader / public-api / shader-definition-factory.cpp
1 /*
2  * Copyright (c) 2022 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 #include "dali-scene-loader/public-api/shader-definition-factory.h"
18 #include <cstring>
19 #include "dali-scene-loader/internal/hash.h"
20 #include "dali-scene-loader/public-api/blend-shape-details.h"
21 #include "dali-scene-loader/public-api/node-definition.h"
22 #include "dali/devel-api/common/map-wrapper.h"
23
24 namespace Dali
25 {
26 namespace SceneLoader
27 {
28 namespace
29 {
30 struct ResourceReceiver : IResourceReceiver
31 {
32   const ResourceBundle&     mResources;
33   const MeshDefinition*     mMeshDef     = nullptr;
34   const MaterialDefinition* mMaterialDef = nullptr;
35
36   ResourceReceiver(const ResourceBundle& resources)
37   : mResources(resources)
38   {
39   }
40
41   void Register(ResourceType::Value type, Index id) override
42   {
43     switch(type)
44     {
45       case ResourceType::Mesh:
46         mMeshDef = &mResources.mMeshes[id].first;
47         break;
48
49       case ResourceType::Material:
50         mMaterialDef = &mResources.mMaterials[id].first;
51         break;
52
53       default:
54         break;
55     }
56   }
57 };
58
59 void RetrieveBlendShapeComponents(const std::vector<MeshDefinition::BlendShape>& blendShapes, bool& hasPositions, bool& hasNormals, bool& hasTangents)
60 {
61   for(const auto& blendShape : blendShapes)
62   {
63     hasPositions = hasPositions || blendShape.deltas.IsDefined();
64     hasNormals   = hasNormals || blendShape.normals.IsDefined();
65     hasTangents  = hasTangents || blendShape.tangents.IsDefined();
66   }
67 }
68
69 uint64_t HashNode(const NodeDefinition& nodeDef, const MaterialDefinition& materialDef, const MeshDefinition& meshDef)
70 {
71   Hash hash;
72
73   const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
74   hash.Add(hasTransparency);
75
76   if(hasTransparency ||
77      materialDef.CheckTextures(MaterialDefinition::ALBEDO) ||
78      materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS) ||
79      materialDef.CheckTextures(MaterialDefinition::NORMAL))
80   {
81     hash.Add("3TEX");
82   }
83
84   if(materialDef.GetAlphaCutoff() > 0.f)
85   {
86     hash.Add("ALPH" /*A_TEST*/);
87   }
88
89   if(MaskMatch(materialDef.mFlags, MaterialDefinition::SUBSURFACE))
90   {
91     hash.Add("SSS");
92   }
93
94   if(MaskMatch(materialDef.mFlags, MaterialDefinition::OCCLUSION))
95   {
96     hash.Add("OCCL" /*USION*/);
97   }
98
99   if(MaskMatch(materialDef.mFlags, MaterialDefinition::EMISSIVE))
100   {
101     hash.Add("EMIS" /*SIVE*/);
102   }
103
104   if(MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS))
105   {
106     hash.Add("GLTF" /*_CHANNELS*/);
107   }
108
109   if(meshDef.IsSkinned())
110   {
111     hash.Add("SKIN" /*NING*/);
112   }
113
114   if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
115   {
116     hash.Add("FLIP" /*_V*/);
117   }
118
119   if(meshDef.HasBlendShapes())
120   {
121     bool hasPositions = false;
122     bool hasNormals   = false;
123     bool hasTangents  = false;
124     RetrieveBlendShapeComponents(meshDef.mBlendShapes, hasPositions, hasNormals, hasTangents);
125     if(hasPositions)
126     {
127       hash.Add("MORPHPOS");
128     }
129
130     if(hasNormals)
131     {
132       hash.Add("MORPHNOR");
133     }
134
135     if(hasTangents)
136     {
137       hash.Add("MORPHTAN");
138     }
139
140     if(hasPositions || hasNormals || hasTangents)
141     {
142       hash.Add("MORPH");
143
144       if(BlendShapes::Version::VERSION_2_0 == meshDef.mBlendShapeVersion)
145       {
146         hash.Add("MORPHV2");
147       }
148     }
149   }
150
151   return hash;
152 }
153 } // namespace
154
155 struct ShaderDefinitionFactory::Impl
156 {
157   ResourceBundle*           mResources; // no ownership
158   std::map<uint64_t, Index> mShaderMap;
159 };
160
161 ShaderDefinitionFactory::ShaderDefinitionFactory()
162 : mImpl{new Impl()}
163 {
164 }
165
166 ShaderDefinitionFactory::~ShaderDefinitionFactory() = default;
167
168 void ShaderDefinitionFactory::SetResources(ResourceBundle& resources)
169 {
170   mImpl->mResources = &resources;
171   mImpl->mShaderMap.clear();
172 }
173
174 Index ShaderDefinitionFactory::ProduceShader(const NodeDefinition& nodeDef)
175 {
176   DALI_ASSERT_DEBUG(nodeDef.mRenderable);
177
178   auto&            resources = *mImpl->mResources;
179   ResourceReceiver receiver{resources};
180   nodeDef.mRenderable->RegisterResources(receiver);
181   if(!(receiver.mMeshDef && receiver.mMaterialDef))
182   {
183     return INVALID_INDEX;
184   }
185
186   auto&    shaderMap = mImpl->mShaderMap;
187   uint64_t hash      = HashNode(nodeDef, *receiver.mMaterialDef, *receiver.mMeshDef);
188   auto     iFind     = shaderMap.find(hash);
189   if(iFind != shaderMap.end())
190   {
191     return iFind->second;
192   }
193
194   ShaderDefinition shaderDef;
195   shaderDef.mUseBuiltInShader = true;
196   shaderDef.mRendererState      = RendererState::DEPTH_TEST | RendererState::DEPTH_WRITE | RendererState::CULL_BACK;
197
198   auto&      materialDef     = *receiver.mMaterialDef;
199   const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
200   if(hasTransparency)
201   {
202     // TODO: this requires more granularity
203     shaderDef.mRendererState = (shaderDef.mRendererState | RendererState::ALPHA_BLEND) & ~RendererState::DEPTH_WRITE;
204   }
205
206   if(hasTransparency ||
207      materialDef.CheckTextures(MaterialDefinition::ALBEDO) ||
208      materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS) ||
209      materialDef.CheckTextures(MaterialDefinition::NORMAL))
210   {
211     shaderDef.mDefines.push_back("THREE_TEX");
212   }
213
214   if(materialDef.GetAlphaCutoff() > 0.f)
215   {
216     shaderDef.mDefines.push_back("ALPHA_TEST");
217   }
218
219   if(MaskMatch(materialDef.mFlags, MaterialDefinition::SUBSURFACE))
220   {
221     shaderDef.mDefines.push_back("SSS");
222   }
223
224   if(MaskMatch(materialDef.mFlags, MaterialDefinition::OCCLUSION))
225   {
226     shaderDef.mDefines.push_back("OCCLUSION");
227   }
228
229   if(MaskMatch(materialDef.mFlags, MaterialDefinition::EMISSIVE))
230   {
231     shaderDef.mDefines.push_back("EMISSIVE");
232   }
233
234   if(MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS))
235   {
236     shaderDef.mDefines.push_back("GLTF_CHANNELS");
237   }
238
239   const auto& meshDef = *receiver.mMeshDef;
240   if(meshDef.IsSkinned())
241   {
242     shaderDef.mDefines.push_back("SKINNING");
243   }
244
245   if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
246   {
247     shaderDef.mDefines.push_back("FLIP_V");
248   }
249
250   if(meshDef.HasBlendShapes())
251   {
252     bool hasPositions = false;
253     bool hasNormals   = false;
254     bool hasTangents  = false;
255     RetrieveBlendShapeComponents(meshDef.mBlendShapes, hasPositions, hasNormals, hasTangents);
256
257     if(hasPositions)
258     {
259       shaderDef.mDefines.push_back("MORPH_POSITION");
260     }
261
262     if(hasNormals)
263     {
264       shaderDef.mDefines.push_back("MORPH_NORMAL");
265     }
266
267     if(hasTangents)
268     {
269       shaderDef.mDefines.push_back("MORPH_TANGENT");
270     }
271
272     if(hasPositions || hasNormals || hasTangents)
273     {
274       shaderDef.mDefines.push_back("MORPH");
275
276       if(BlendShapes::Version::VERSION_2_0 == meshDef.mBlendShapeVersion)
277       {
278         shaderDef.mDefines.push_back("MORPH_VERSION_2_0");
279       }
280     }
281   }
282
283   shaderDef.mUniforms["uMaxLOD"]     = 6.f;
284   shaderDef.mUniforms["uCubeMatrix"] = Matrix::IDENTITY;
285
286   Index result    = resources.mShaders.size();
287   shaderMap[hash] = result;
288
289   resources.mShaders.emplace_back(std::move(shaderDef), Shader());
290
291   return result;
292 }
293
294 } // namespace SceneLoader
295 } // namespace Dali