Adding chipmunk implementation for physics adaptor
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / public-api / loader / shader-manager.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-manager.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/common/map-wrapper.h>
23 #include <dali/public-api/animation/constraint.h>
24 #include <cstring>
25
26 // INTERNAL INCLUDES
27 #include <dali-scene3d/internal/light/light-impl.h>
28 #include <dali-scene3d/internal/loader/hash.h>
29 #include <dali-scene3d/public-api/loader/blend-shape-details.h>
30 #include <dali-scene3d/public-api/loader/node-definition.h>
31
32 namespace Dali::Scene3D::Loader
33 {
34 namespace
35 {
36 static constexpr uint32_t INDEX_FOR_LIGHT_CONSTRAINT_TAG = 10;
37
38 ShaderOption MakeOption(const MaterialDefinition& materialDef, const MeshDefinition& meshDef)
39 {
40   ShaderOption option;
41
42   const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
43   if(hasTransparency)
44   {
45     option.SetTransparency();
46   }
47
48   if(hasTransparency ||
49      !materialDef.CheckTextures(MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC) ||
50      !materialDef.CheckTextures(MaterialDefinition::NORMAL | MaterialDefinition::ROUGHNESS))
51   {
52     option.AddOption(ShaderOption::Type::THREE_TEXTURE);
53
54     // For the glTF, each of basecolor, metallic_roughness, normal texture is not essential.
55     if(MaskMatch(materialDef.mFlags, MaterialDefinition::ALBEDO))
56     {
57       option.AddOption(ShaderOption::Type::BASE_COLOR_TEXTURE);
58     }
59
60     if(materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS))
61     {
62       option.AddOption(ShaderOption::Type::METALLIC_ROUGHNESS_TEXTURE);
63     }
64
65     if(MaskMatch(materialDef.mFlags, MaterialDefinition::NORMAL))
66     {
67       option.AddOption(ShaderOption::Type::NORMAL_TEXTURE);
68     }
69   }
70
71   if(materialDef.GetAlphaCutoff() > 0.f)
72   {
73     option.AddOption(ShaderOption::Type::ALPHA_TEST);
74   }
75
76   if(MaskMatch(materialDef.mFlags, MaterialDefinition::SUBSURFACE))
77   {
78     option.AddOption(ShaderOption::Type::SUBSURFACE);
79   }
80
81   if(MaskMatch(materialDef.mFlags, MaterialDefinition::OCCLUSION))
82   {
83     option.AddOption(ShaderOption::Type::OCCLUSION);
84   }
85
86   if(MaskMatch(materialDef.mFlags, MaterialDefinition::EMISSIVE))
87   {
88     option.AddOption(ShaderOption::Type::EMISSIVE);
89   }
90
91   if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR))
92   {
93     option.AddOption(ShaderOption::Type::SPECULAR);
94   }
95
96   if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR_COLOR))
97   {
98     option.AddOption(ShaderOption::Type::SPECULAR_COLOR);
99   }
100
101   if(MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS))
102   {
103     option.AddOption(ShaderOption::Type::GLTF_CHANNELS);
104   }
105
106   if(meshDef.IsSkinned())
107   {
108     option.AddOption(ShaderOption::Type::SKINNING);
109   }
110
111   if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
112   {
113     option.AddOption(ShaderOption::Type::FLIP_UVS_VERTICAL);
114   }
115
116   if(meshDef.mColors.IsDefined())
117   {
118     option.AddOption(ShaderOption::Type::COLOR_ATTRIBUTE);
119   }
120
121   if(meshDef.mTangentType == Property::VECTOR4)
122   {
123     option.AddOption(ShaderOption::Type::VEC4_TANGENT);
124   }
125
126   if(meshDef.HasBlendShapes())
127   {
128     bool hasPositions = false;
129     bool hasNormals   = false;
130     bool hasTangents  = false;
131     meshDef.RetrieveBlendShapeComponents(hasPositions, hasNormals, hasTangents);
132     if(hasPositions)
133     {
134       option.AddOption(ShaderOption::Type::MORPH_POSITION);
135     }
136
137     if(hasNormals)
138     {
139       option.AddOption(ShaderOption::Type::MORPH_NORMAL);
140     }
141
142     if(hasTangents)
143     {
144       option.AddOption(ShaderOption::Type::MORPH_TANGENT);
145     }
146
147     if(hasPositions || hasNormals || hasTangents)
148     {
149       if(BlendShapes::Version::VERSION_2_0 == meshDef.mBlendShapeVersion)
150       {
151         option.AddOption(ShaderOption::Type::MORPH_VERSION_2_0);
152       }
153     }
154   }
155
156   return option;
157 }
158 } // namespace
159
160 struct ShaderManager::Impl
161 {
162   std::map<uint64_t, Index>   mShaderMap;
163   std::vector<Dali::Shader>   mShaders;
164   std::vector<Scene3D::Light> mLights;
165 };
166
167 ShaderManager::ShaderManager()
168 : mImpl{new Impl()}
169 {
170 }
171
172 ShaderManager::~ShaderManager() = default;
173
174 Dali::Shader ShaderManager::ProduceShader(const MaterialDefinition& materialDefinition, const MeshDefinition& meshDefinition)
175 {
176   ShaderOption option = MakeOption(materialDefinition, meshDefinition);
177   return ProduceShader(option);
178 }
179
180 Dali::Shader ShaderManager::ProduceShader(const ShaderOption& shaderOption)
181 {
182   Dali::Shader result;
183
184   auto&    shaderMap = mImpl->mShaderMap;
185   uint64_t hash      = shaderOption.GetOptionHash();
186   auto     iFind     = shaderMap.find(hash);
187   if(iFind != shaderMap.end())
188   {
189     result = mImpl->mShaders[iFind->second];
190   }
191   else
192   {
193     ShaderDefinition shaderDef;
194     shaderDef.mUseBuiltInShader = true;
195
196     shaderOption.GetDefines(shaderDef.mDefines);
197     shaderDef.mUniforms["uCubeMatrix"] = Matrix::IDENTITY;
198
199     shaderMap[hash] = mImpl->mShaders.size();
200
201     auto raw = shaderDef.LoadRaw("");
202     mImpl->mShaders.emplace_back(shaderDef.Load(std::move(raw)));
203     result = mImpl->mShaders.back();
204
205     std::string lightCountPropertyName(Scene3D::Internal::Light::GetLightCountUniformName());
206     result.RegisterProperty(lightCountPropertyName, static_cast<int32_t>(mImpl->mLights.size()));
207
208     for(uint32_t index = 0; index < mImpl->mLights.size(); ++index)
209     {
210       SetLightConstraintToShader(index, result);
211     }
212   }
213
214   return result;
215 }
216
217 RendererState::Type ShaderManager::GetRendererState(const MaterialDefinition& materialDefinition)
218 {
219   RendererState::Type rendererState = RendererState::DEPTH_TEST;
220
221   if(!materialDefinition.mDoubleSided)
222   {
223     rendererState |= RendererState::CULL_BACK;
224   }
225
226   const bool hasTransparency = MaskMatch(materialDefinition.mFlags, MaterialDefinition::TRANSPARENCY);
227   if(hasTransparency)
228   {
229     // TODO: this requires more granularity
230     rendererState = (rendererState | RendererState::ALPHA_BLEND);
231   }
232   return rendererState;
233 }
234
235 bool ShaderManager::AddLight(Scene3D::Light light)
236 {
237   if(!light || mImpl->mLights.size() >= Scene3D::Internal::Light::GetMaximumEnabledLightCount())
238   {
239     return false;
240   }
241
242   uint32_t lightIndex = mImpl->mLights.size();
243   mImpl->mLights.push_back(light);
244
245   for(auto&& shader : mImpl->mShaders)
246   {
247     std::string lightCountPropertyName(Scene3D::Internal::Light::GetLightCountUniformName());
248     shader.RegisterProperty(lightCountPropertyName, static_cast<int32_t>(mImpl->mLights.size()));
249   }
250
251   SetLightConstraint(lightIndex);
252
253   return true;
254 }
255
256 void ShaderManager::RemoveLight(Scene3D::Light light)
257 {
258   uint32_t lightCount = mImpl->mLights.size();
259   for(uint32_t index = 0; index < lightCount; ++index)
260   {
261     if(mImpl->mLights[index] != light)
262     {
263       continue;
264     }
265
266     RemoveLightConstraint(index);
267
268     if(!mImpl->mLights.empty() && light != mImpl->mLights.back())
269     {
270       RemoveLightConstraint(mImpl->mLights.size() - 1);
271       mImpl->mLights[index] = mImpl->mLights.back();
272       SetLightConstraint(index);
273     }
274
275     mImpl->mLights.pop_back();
276
277     for(auto&& shader : mImpl->mShaders)
278     {
279       std::string lightCountPropertyName(Scene3D::Internal::Light::GetLightCountUniformName());
280       shader.RegisterProperty(lightCountPropertyName, static_cast<int32_t>(mImpl->mLights.size()));
281     }
282     break;
283   }
284 }
285
286 uint32_t ShaderManager::GetLightCount() const
287 {
288   return mImpl->mLights.size();
289 }
290
291 void ShaderManager::SetLightConstraint(uint32_t lightIndex)
292 {
293   for(auto&& shader : mImpl->mShaders)
294   {
295     SetLightConstraintToShader(lightIndex, shader);
296   }
297 }
298
299 void ShaderManager::SetLightConstraintToShader(uint32_t lightIndex, Dali::Shader shader)
300 {
301   std::string lightDirectionPropertyName(Scene3D::Internal::Light::GetLightDirectionUniformName());
302   lightDirectionPropertyName += "[" + std::to_string(lightIndex) + "]";
303   auto             lightDirectionPropertyIndex = shader.RegisterProperty(lightDirectionPropertyName, Vector3::ZAXIS);
304   Dali::Constraint lightDirectionConstraint    = Dali::Constraint::New<Vector3>(shader, lightDirectionPropertyIndex, [](Vector3& output, const PropertyInputContainer& inputs) { output = inputs[0]->GetQuaternion().Rotate(Vector3::ZAXIS); });
305   lightDirectionConstraint.AddSource(Source{mImpl->mLights[lightIndex], Dali::Actor::Property::WORLD_ORIENTATION});
306   lightDirectionConstraint.ApplyPost();
307   lightDirectionConstraint.SetTag(INDEX_FOR_LIGHT_CONSTRAINT_TAG + lightIndex);
308
309   std::string lightColorPropertyName(Scene3D::Internal::Light::GetLightColorUniformName());
310   lightColorPropertyName += "[" + std::to_string(lightIndex) + "]";
311   auto             lightColorPropertyIndex = shader.RegisterProperty(lightColorPropertyName, Vector3(Color::WHITE));
312   Dali::Constraint lightColorConstraint    = Dali::Constraint::New<Vector3>(shader, lightColorPropertyIndex, [](Vector3& output, const PropertyInputContainer& inputs) { output = Vector3(inputs[0]->GetVector4()); });
313   lightColorConstraint.AddSource(Source{mImpl->mLights[lightIndex], Dali::Actor::Property::COLOR});
314   lightColorConstraint.ApplyPost();
315   lightColorConstraint.SetTag(INDEX_FOR_LIGHT_CONSTRAINT_TAG + lightIndex);
316 }
317
318 void ShaderManager::RemoveLightConstraint(uint32_t lightIndex)
319 {
320   for(auto&& shader : mImpl->mShaders)
321   {
322     shader.RemoveConstraints(INDEX_FOR_LIGHT_CONSTRAINT_TAG + lightIndex);
323   }
324 }
325
326 } // namespace Dali::Scene3D::Loader