Merge "Move Clipboard to TextClipboard" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / public-api / loader / shader-definition-factory.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/public-api/loader/shader-definition-factory.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/common/map-wrapper.h>
23 #include <cstring>
24
25 // INTERNAL INCLUDES
26 #include <dali-scene3d/internal/loader/hash.h>
27 #include <dali-scene3d/public-api/loader/blend-shape-details.h>
28 #include <dali-scene3d/public-api/loader/node-definition.h>
29 #include <dali-scene3d/public-api/loader/shader-definition-option.h>
30
31 namespace Dali::Scene3D::Loader
32 {
33 namespace
34 {
35 struct ResourceReceiver : IResourceReceiver
36 {
37   const ResourceBundle&     mResources;
38   const MeshDefinition*     mMeshDef     = nullptr;
39   const MaterialDefinition* mMaterialDef = nullptr;
40
41   ResourceReceiver(const ResourceBundle& resources)
42   : mResources(resources)
43   {
44   }
45
46   void Register(ResourceType::Value type, Index id) override
47   {
48     switch(type)
49     {
50       case ResourceType::Mesh:
51         mMeshDef = &mResources.mMeshes[id].first;
52         break;
53
54       case ResourceType::Material:
55         mMaterialDef = &mResources.mMaterials[id].first;
56         break;
57
58       default:
59         break;
60     }
61   }
62 };
63
64 ShaderDefinitionOption MakeOption(const MaterialDefinition& materialDef, const MeshDefinition& meshDef)
65 {
66   ShaderDefinitionOption option;
67
68   const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
69   if(hasTransparency)
70   {
71     option.SetTransparency();
72   }
73
74   if(hasTransparency ||
75      !materialDef.CheckTextures(MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC) ||
76      !materialDef.CheckTextures(MaterialDefinition::NORMAL | MaterialDefinition::ROUGHNESS))
77   {
78     option.AddOption(ShaderDefinitionOption::Type::THREE_TEXTURE);
79
80     // For the glTF, each of basecolor, metallic_roughness, normal texture is not essential.
81     if(MaskMatch(materialDef.mFlags, MaterialDefinition::ALBEDO))
82     {
83       option.AddOption(ShaderDefinitionOption::Type::BASE_COLOR_TEXTURE);
84     }
85
86     if(materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS))
87     {
88       option.AddOption(ShaderDefinitionOption::Type::METALLIC_ROUGHNESS_TEXTURE);
89     }
90
91     if(MaskMatch(materialDef.mFlags, MaterialDefinition::NORMAL))
92     {
93       option.AddOption(ShaderDefinitionOption::Type::NORMAL_TEXTURE);
94     }
95   }
96
97   if(materialDef.GetAlphaCutoff() > 0.f)
98   {
99     option.AddOption(ShaderDefinitionOption::Type::ALPHA_TEST);
100   }
101
102   if(MaskMatch(materialDef.mFlags, MaterialDefinition::SUBSURFACE))
103   {
104     option.AddOption(ShaderDefinitionOption::Type::SUBSURFACE);
105   }
106
107   if(MaskMatch(materialDef.mFlags, MaterialDefinition::OCCLUSION))
108   {
109     option.AddOption(ShaderDefinitionOption::Type::OCCLUSION);
110   }
111
112   if(MaskMatch(materialDef.mFlags, MaterialDefinition::EMISSIVE))
113   {
114     option.AddOption(ShaderDefinitionOption::Type::EMISSIVE);
115   }
116
117   if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR))
118   {
119     option.AddOption(ShaderDefinitionOption::Type::SPECULAR);
120   }
121
122   if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR_COLOR))
123   {
124     option.AddOption(ShaderDefinitionOption::Type::SPECULAR_COLOR);
125   }
126
127   if(MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS))
128   {
129     option.AddOption(ShaderDefinitionOption::Type::GLTF_CHANNELS);
130   }
131
132   if(meshDef.IsSkinned())
133   {
134     option.AddOption(ShaderDefinitionOption::Type::SKINNING);
135   }
136
137   if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
138   {
139     option.AddOption(ShaderDefinitionOption::Type::FLIP_UVS_VERTICAL);
140   }
141
142   if(meshDef.mColors.IsDefined())
143   {
144     option.AddOption(ShaderDefinitionOption::Type::COLOR_ATTRIBUTE);
145   }
146
147   if(meshDef.mTangentType == Property::VECTOR4)
148   {
149     option.AddOption(ShaderDefinitionOption::Type::VEC4_TANGENT);
150   }
151
152   if(meshDef.HasBlendShapes())
153   {
154     bool hasPositions = false;
155     bool hasNormals   = false;
156     bool hasTangents  = false;
157     meshDef.RetrieveBlendShapeComponents(hasPositions, hasNormals, hasTangents);
158     if(hasPositions)
159     {
160       option.AddOption(ShaderDefinitionOption::Type::MORPH_POSITION);
161     }
162
163     if(hasNormals)
164     {
165       option.AddOption(ShaderDefinitionOption::Type::MORPH_NORMAL);
166     }
167
168     if(hasTangents)
169     {
170       option.AddOption(ShaderDefinitionOption::Type::MORPH_TANGENT);
171     }
172
173     if(hasPositions || hasNormals || hasTangents)
174     {
175       if(BlendShapes::Version::VERSION_2_0 == meshDef.mBlendShapeVersion)
176       {
177         option.AddOption(ShaderDefinitionOption::Type::MORPH_VERSION_2_0);
178       }
179     }
180   }
181
182   return option;
183 }
184 } // namespace
185
186 struct ShaderDefinitionFactory::Impl
187 {
188   ResourceBundle*           mResources; // no ownership
189   std::map<uint64_t, Index> mShaderMap;
190 };
191
192 ShaderDefinitionFactory::ShaderDefinitionFactory()
193 : mImpl{new Impl()}
194 {
195 }
196
197 ShaderDefinitionFactory::~ShaderDefinitionFactory() = default;
198
199 void ShaderDefinitionFactory::SetResources(ResourceBundle& resources)
200 {
201   mImpl->mResources = &resources;
202   mImpl->mShaderMap.clear();
203 }
204
205 Index ShaderDefinitionFactory::ProduceShader(NodeDefinition::Renderable& renderable)
206 {
207   auto& resources = *mImpl->mResources;
208
209   ResourceReceiver receiver{resources};
210   renderable.RegisterResources(receiver);
211
212   if(!(receiver.mMeshDef && receiver.mMaterialDef))
213   {
214     renderable.mShaderIdx = INVALID_INDEX;
215     return INVALID_INDEX;
216   }
217
218   auto&                  shaderMap = mImpl->mShaderMap;
219   ShaderDefinitionOption option    = MakeOption(*receiver.mMaterialDef, *receiver.mMeshDef);
220   uint64_t               hash      = option.GetOptionHash();
221   auto                   iFind     = shaderMap.find(hash);
222   if(iFind != shaderMap.end())
223   {
224     renderable.mShaderIdx = iFind->second;
225   }
226   else
227   {
228     ShaderDefinition shaderDef;
229     shaderDef.mUseBuiltInShader = true;
230     shaderDef.mRendererState    = RendererState::DEPTH_TEST;
231
232     auto& materialDef = *receiver.mMaterialDef;
233     if(!materialDef.mDoubleSided)
234     {
235       shaderDef.mRendererState |= RendererState::CULL_BACK;
236     }
237
238     const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
239     if(hasTransparency)
240     {
241       // TODO: this requires more granularity
242       shaderDef.mRendererState = (shaderDef.mRendererState | RendererState::ALPHA_BLEND);
243     }
244
245     option.GetDefines(shaderDef.mDefines);
246     shaderDef.mUniforms["uCubeMatrix"] = Matrix::IDENTITY;
247
248     Index result    = resources.mShaders.size();
249     shaderMap[hash] = result;
250
251     resources.mShaders.emplace_back(std::move(shaderDef), Shader());
252
253     renderable.mShaderIdx = result;
254   }
255
256   return renderable.mShaderIdx;
257 }
258
259 } // namespace Dali::Scene3D::Loader