2 * Copyright (c) 2022 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "dali-scene-loader/public-api/shader-definition-factory.h"
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"
30 struct ResourceReceiver : IResourceReceiver
32 const ResourceBundle& mResources;
33 const MeshDefinition* mMeshDef = nullptr;
34 const MaterialDefinition* mMaterialDef = nullptr;
36 ResourceReceiver(const ResourceBundle& resources)
37 : mResources(resources)
41 void Register(ResourceType::Value type, Index id) override
45 case ResourceType::Mesh:
46 mMeshDef = &mResources.mMeshes[id].first;
49 case ResourceType::Material:
50 mMaterialDef = &mResources.mMaterials[id].first;
59 void RetrieveBlendShapeComponents(const std::vector<MeshDefinition::BlendShape>& blendShapes, bool& hasPositions, bool& hasNormals, bool& hasTangents)
61 for(const auto& blendShape : blendShapes)
63 hasPositions = hasPositions || blendShape.deltas.IsDefined();
64 hasNormals = hasNormals || blendShape.normals.IsDefined();
65 hasTangents = hasTangents || blendShape.tangents.IsDefined();
69 uint64_t HashNode(const NodeDefinition& nodeDef, const MaterialDefinition& materialDef, const MeshDefinition& meshDef)
73 const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
74 hash.Add(hasTransparency);
77 materialDef.CheckTextures(MaterialDefinition::ALBEDO) ||
78 materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS) ||
79 materialDef.CheckTextures(MaterialDefinition::NORMAL))
84 if(materialDef.GetAlphaCutoff() > 0.f)
86 hash.Add("ALPH" /*A_TEST*/);
89 if(MaskMatch(materialDef.mFlags, MaterialDefinition::SUBSURFACE))
94 if(MaskMatch(materialDef.mFlags, MaterialDefinition::OCCLUSION))
96 hash.Add("OCCL" /*USION*/);
99 if(MaskMatch(materialDef.mFlags, MaterialDefinition::EMISSIVE))
101 hash.Add("EMIS" /*SIVE*/);
104 if(MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS))
106 hash.Add("GLTF" /*_CHANNELS*/);
109 if(meshDef.IsSkinned())
111 hash.Add("SKIN" /*NING*/);
114 if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
116 hash.Add("FLIP" /*_V*/);
119 if(meshDef.HasBlendShapes())
121 bool hasPositions = false;
122 bool hasNormals = false;
123 bool hasTangents = false;
124 RetrieveBlendShapeComponents(meshDef.mBlendShapes, hasPositions, hasNormals, hasTangents);
127 hash.Add("MORPHPOS");
132 hash.Add("MORPHNOR");
137 hash.Add("MORPHTAN");
140 if(hasPositions || hasNormals || hasTangents)
144 if(BlendShapes::Version::VERSION_2_0 == meshDef.mBlendShapeVersion)
155 struct ShaderDefinitionFactory::Impl
157 ResourceBundle* mResources; // no ownership
158 std::map<uint64_t, Index> mShaderMap;
161 ShaderDefinitionFactory::ShaderDefinitionFactory()
166 ShaderDefinitionFactory::~ShaderDefinitionFactory() = default;
168 void ShaderDefinitionFactory::SetResources(ResourceBundle& resources)
170 mImpl->mResources = &resources;
171 mImpl->mShaderMap.clear();
174 Index ShaderDefinitionFactory::ProduceShader(const NodeDefinition& nodeDef)
176 DALI_ASSERT_DEBUG(nodeDef.mRenderable);
178 auto& resources = *mImpl->mResources;
179 ResourceReceiver receiver{resources};
180 nodeDef.mRenderable->RegisterResources(receiver);
181 if(!(receiver.mMeshDef && receiver.mMaterialDef))
183 return INVALID_INDEX;
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())
191 return iFind->second;
194 ShaderDefinition shaderDef;
195 shaderDef.mUseBuiltInShader = true;
196 shaderDef.mRendererState = RendererState::DEPTH_TEST | RendererState::DEPTH_WRITE | RendererState::CULL_BACK;
198 auto& materialDef = *receiver.mMaterialDef;
199 const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
202 // TODO: this requires more granularity
203 shaderDef.mRendererState = (shaderDef.mRendererState | RendererState::ALPHA_BLEND) & ~RendererState::DEPTH_WRITE;
206 if(hasTransparency ||
207 materialDef.CheckTextures(MaterialDefinition::ALBEDO) ||
208 materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS) ||
209 materialDef.CheckTextures(MaterialDefinition::NORMAL))
211 shaderDef.mDefines.push_back("THREE_TEX");
214 if(materialDef.GetAlphaCutoff() > 0.f)
216 shaderDef.mDefines.push_back("ALPHA_TEST");
219 if(MaskMatch(materialDef.mFlags, MaterialDefinition::SUBSURFACE))
221 shaderDef.mDefines.push_back("SSS");
224 if(MaskMatch(materialDef.mFlags, MaterialDefinition::OCCLUSION))
226 shaderDef.mDefines.push_back("OCCLUSION");
229 if(MaskMatch(materialDef.mFlags, MaterialDefinition::EMISSIVE))
231 shaderDef.mDefines.push_back("EMISSIVE");
234 if(MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS))
236 shaderDef.mDefines.push_back("GLTF_CHANNELS");
239 const auto& meshDef = *receiver.mMeshDef;
240 if(meshDef.IsSkinned())
242 shaderDef.mDefines.push_back("SKINNING");
245 if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
247 shaderDef.mDefines.push_back("FLIP_V");
250 if(meshDef.HasBlendShapes())
252 bool hasPositions = false;
253 bool hasNormals = false;
254 bool hasTangents = false;
255 RetrieveBlendShapeComponents(meshDef.mBlendShapes, hasPositions, hasNormals, hasTangents);
259 shaderDef.mDefines.push_back("MORPH_POSITION");
264 shaderDef.mDefines.push_back("MORPH_NORMAL");
269 shaderDef.mDefines.push_back("MORPH_TANGENT");
272 if(hasPositions || hasNormals || hasTangents)
274 shaderDef.mDefines.push_back("MORPH");
276 if(BlendShapes::Version::VERSION_2_0 == meshDef.mBlendShapeVersion)
278 shaderDef.mDefines.push_back("MORPH_VERSION_2_0");
283 shaderDef.mUniforms["uMaxLOD"] = 6.f;
284 shaderDef.mUniforms["uCubeMatrix"] = Matrix::IDENTITY;
286 Index result = resources.mShaders.size();
287 shaderMap[hash] = result;
289 resources.mShaders.emplace_back(std::move(shaderDef), Shader());
294 } // namespace SceneLoader