2 * Copyright (c) 2020 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/internal/hash.h"
18 #include "dali-scene-loader/public-api/shader-definition-factory.h"
19 #include "dali-scene-loader/public-api/node-definition.h"
20 #include "dali-scene-loader/public-api/blend-shape-details.h"
21 #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)
40 void Register(ResourceType::Value type, Index id) override
44 case ResourceType::Mesh:
45 mMeshDef = &mResources.mMeshes[id].first;
48 case ResourceType::Material:
49 mMaterialDef = &mResources.mMaterials[id].first;
58 const std::string PBR_SHADER_NAME = "dli_pbr";
60 void RetrieveBlendShapeComponents(const std::vector<MeshDefinition::BlendShape>& blendShapes, bool& hasPositions, bool& hasNormals, bool& hasTangents)
62 for (const auto& blendShape : blendShapes)
64 hasPositions = hasPositions || blendShape.deltas.IsDefined();
65 hasNormals = hasNormals || blendShape.normals.IsDefined();
66 hasTangents = hasTangents || blendShape.tangents.IsDefined();
70 uint64_t HashNode(const NodeDefinition& nodeDef, const MaterialDefinition& materialDef, const MeshDefinition& meshDef)
74 // note: could be per vertex / fragment component - in WatchViewer, these have the same name.
75 hash.Add(PBR_SHADER_NAME);
77 const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
78 hash.Add(hasTransparency);
80 if (hasTransparency ||
81 materialDef.CheckTextures(MaterialDefinition::ALBEDO) ||
82 materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS) ||
83 materialDef.CheckTextures(MaterialDefinition::NORMAL))
88 if (materialDef.GetAlphaCutoff() > 0.f)
90 hash.Add("ALPH"/*A_TEST*/);
93 if (MaskMatch(materialDef.mFlags, MaterialDefinition::SUBSURFACE))
98 if (MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS))
100 hash.Add("GLTF"/*_CHANNELS*/);
103 if (meshDef.IsSkinned())
105 hash.Add("SKIN"/*NING*/);
108 if (MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
110 hash.Add("FLIP"/*_V*/);
113 if (meshDef.HasBlendShapes())
115 bool hasPositions = false;
116 bool hasNormals = false;
117 bool hasTangents = false;
118 RetrieveBlendShapeComponents(meshDef.mBlendShapes, hasPositions, hasNormals, hasTangents);
121 hash.Add("MORPHPOS");
126 hash.Add("MORPHNOR");
131 hash.Add("MORPHTAN");
134 if (hasPositions || hasNormals || hasTangents)
138 if (BlendShapes::Version::VERSION_2_0 == meshDef.mBlendShapeVersion)
149 struct ShaderDefinitionFactory::Impl
151 ResourceBundle* mResources; // no ownership
152 std::map<uint64_t, Index> mShaderMap;
155 ShaderDefinitionFactory::ShaderDefinitionFactory()
156 : mImpl{ new Impl() }
159 ShaderDefinitionFactory::~ShaderDefinitionFactory() = default;
161 void ShaderDefinitionFactory::SetResources(ResourceBundle& resources)
163 mImpl->mResources = &resources;
164 mImpl->mShaderMap.clear();
167 Index ShaderDefinitionFactory::ProduceShader(const NodeDefinition& nodeDef)
169 DALI_ASSERT_DEBUG(nodeDef.mRenderable);
171 auto& resources = *mImpl->mResources;
172 ResourceReceiver receiver{ resources };
173 nodeDef.mRenderable->RegisterResources(receiver);
174 if (!(receiver.mMeshDef && receiver.mMaterialDef))
176 return INVALID_INDEX;
179 auto& shaderMap = mImpl->mShaderMap;
180 uint64_t hash = HashNode(nodeDef, *receiver.mMaterialDef, *receiver.mMeshDef);
181 auto iFind = shaderMap.find(hash);
182 if (iFind != shaderMap.end())
184 return iFind->second;
187 ShaderDefinition shaderDef;
188 shaderDef.mVertexShaderPath = PBR_SHADER_NAME + ".vsh";
189 shaderDef.mFragmentShaderPath = PBR_SHADER_NAME + ".fsh";
190 shaderDef.mRendererState = RendererState::DEPTH_TEST | RendererState::DEPTH_WRITE | RendererState::CULL_BACK;
192 auto& materialDef = *receiver.mMaterialDef;
193 const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
196 // TODO: this requires more granularity
197 shaderDef.mRendererState = (shaderDef.mRendererState | RendererState::ALPHA_BLEND) & ~RendererState::DEPTH_WRITE;
200 if (hasTransparency ||
201 materialDef.CheckTextures(MaterialDefinition::ALBEDO) ||
202 materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS) ||
203 materialDef.CheckTextures(MaterialDefinition::NORMAL))
205 shaderDef.mDefines.push_back("THREE_TEX");
208 if (materialDef.GetAlphaCutoff() > 0.f)
210 shaderDef.mDefines.push_back("ALPHA_TEST");
213 if (MaskMatch(materialDef.mFlags, MaterialDefinition::SUBSURFACE))
215 shaderDef.mDefines.push_back("SSS");
218 if (MaskMatch(receiver.mMaterialDef->mFlags, MaterialDefinition::GLTF_CHANNELS))
220 shaderDef.mDefines.push_back("GLTF_CHANNELS");
223 const auto& meshDef = *receiver.mMeshDef;
224 if (meshDef.IsSkinned())
226 shaderDef.mDefines.push_back("SKINNING");
229 if (MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
231 shaderDef.mDefines.push_back("FLIP_V");
234 if (meshDef.HasBlendShapes())
236 bool hasPositions = false;
237 bool hasNormals = false;
238 bool hasTangents = false;
239 RetrieveBlendShapeComponents(meshDef.mBlendShapes, hasPositions, hasNormals, hasTangents);
243 shaderDef.mDefines.push_back("MORPH_POSITION");
248 shaderDef.mDefines.push_back("MORPH_NORMAL");
253 shaderDef.mDefines.push_back("MORPH_TANGENT");
256 if (hasPositions || hasNormals || hasTangents)
258 shaderDef.mDefines.push_back("MORPH");
260 if (BlendShapes::Version::VERSION_2_0 == meshDef.mBlendShapeVersion)
262 shaderDef.mDefines.push_back("MORPH_VERSION_2_0");
267 shaderDef.mUniforms["uMaxLOD"] = 6.f;
268 shaderDef.mUniforms["uCubeMatrix"] = Matrix::IDENTITY;
270 Index result = resources.mShaders.size();
271 shaderMap[hash] = result;
273 resources.mShaders.emplace_back(std::move(shaderDef), Shader());