2 * Copyright (c) 2023 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.
19 #include <dali-scene3d/public-api/loader/shader-definition-factory.h>
22 #include <dali/devel-api/common/map-wrapper.h>
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>
31 namespace Dali::Scene3D::Loader
35 struct ResourceReceiver : IResourceReceiver
37 const ResourceBundle& mResources;
38 const MeshDefinition* mMeshDef = nullptr;
39 const MaterialDefinition* mMaterialDef = nullptr;
41 ResourceReceiver(const ResourceBundle& resources)
42 : mResources(resources)
46 void Register(ResourceType::Value type, Index id) override
50 case ResourceType::Mesh:
51 mMeshDef = &mResources.mMeshes[id].first;
54 case ResourceType::Material:
55 mMaterialDef = &mResources.mMaterials[id].first;
64 ShaderDefinitionOption MakeOption(const MaterialDefinition& materialDef, const MeshDefinition& meshDef)
66 ShaderDefinitionOption option;
68 const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
71 option.SetTransparency();
75 !materialDef.CheckTextures(MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC) ||
76 !materialDef.CheckTextures(MaterialDefinition::NORMAL | MaterialDefinition::ROUGHNESS))
78 option.AddOption(ShaderDefinitionOption::Type::THREE_TEXTURE);
80 // For the glTF, each of basecolor, metallic_roughness, normal texture is not essential.
81 if(MaskMatch(materialDef.mFlags, MaterialDefinition::ALBEDO))
83 option.AddOption(ShaderDefinitionOption::Type::BASE_COLOR_TEXTURE);
86 if(materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS))
88 option.AddOption(ShaderDefinitionOption::Type::METALLIC_ROUGHNESS_TEXTURE);
91 if(MaskMatch(materialDef.mFlags, MaterialDefinition::NORMAL))
93 option.AddOption(ShaderDefinitionOption::Type::NORMAL_TEXTURE);
97 if(materialDef.GetAlphaCutoff() > 0.f)
99 option.AddOption(ShaderDefinitionOption::Type::ALPHA_TEST);
102 if(MaskMatch(materialDef.mFlags, MaterialDefinition::SUBSURFACE))
104 option.AddOption(ShaderDefinitionOption::Type::SUBSURFACE);
107 if(MaskMatch(materialDef.mFlags, MaterialDefinition::OCCLUSION))
109 option.AddOption(ShaderDefinitionOption::Type::OCCLUSION);
112 if(MaskMatch(materialDef.mFlags, MaterialDefinition::EMISSIVE))
114 option.AddOption(ShaderDefinitionOption::Type::EMISSIVE);
117 if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR))
119 option.AddOption(ShaderDefinitionOption::Type::SPECULAR);
122 if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR_COLOR))
124 option.AddOption(ShaderDefinitionOption::Type::SPECULAR_COLOR);
127 if(MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS))
129 option.AddOption(ShaderDefinitionOption::Type::GLTF_CHANNELS);
132 if(meshDef.IsSkinned())
134 option.AddOption(ShaderDefinitionOption::Type::SKINNING);
137 if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
139 option.AddOption(ShaderDefinitionOption::Type::FLIP_UVS_VERTICAL);
142 if(meshDef.mColors.IsDefined())
144 option.AddOption(ShaderDefinitionOption::Type::COLOR_ATTRIBUTE);
147 if(meshDef.mTangentType == Property::VECTOR4)
149 option.AddOption(ShaderDefinitionOption::Type::VEC4_TANGENT);
152 if(meshDef.HasBlendShapes())
154 bool hasPositions = false;
155 bool hasNormals = false;
156 bool hasTangents = false;
157 meshDef.RetrieveBlendShapeComponents(hasPositions, hasNormals, hasTangents);
160 option.AddOption(ShaderDefinitionOption::Type::MORPH_POSITION);
165 option.AddOption(ShaderDefinitionOption::Type::MORPH_NORMAL);
170 option.AddOption(ShaderDefinitionOption::Type::MORPH_TANGENT);
173 if(hasPositions || hasNormals || hasTangents)
175 if(BlendShapes::Version::VERSION_2_0 == meshDef.mBlendShapeVersion)
177 option.AddOption(ShaderDefinitionOption::Type::MORPH_VERSION_2_0);
186 struct ShaderDefinitionFactory::Impl
188 ResourceBundle* mResources; // no ownership
189 std::map<uint64_t, Index> mShaderMap;
192 ShaderDefinitionFactory::ShaderDefinitionFactory()
197 ShaderDefinitionFactory::~ShaderDefinitionFactory() = default;
199 void ShaderDefinitionFactory::SetResources(ResourceBundle& resources)
201 mImpl->mResources = &resources;
202 mImpl->mShaderMap.clear();
205 Index ShaderDefinitionFactory::ProduceShader(NodeDefinition::Renderable& renderable)
207 auto& resources = *mImpl->mResources;
209 ResourceReceiver receiver{resources};
210 renderable.RegisterResources(receiver);
212 if(!(receiver.mMeshDef && receiver.mMaterialDef))
214 renderable.mShaderIdx = INVALID_INDEX;
215 return INVALID_INDEX;
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())
224 renderable.mShaderIdx = iFind->second;
228 ShaderDefinition shaderDef;
229 shaderDef.mUseBuiltInShader = true;
230 shaderDef.mRendererState = RendererState::DEPTH_TEST;
232 auto& materialDef = *receiver.mMaterialDef;
233 if(!materialDef.mDoubleSided)
235 shaderDef.mRendererState |= RendererState::CULL_BACK;
238 const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
241 // TODO: this requires more granularity
242 shaderDef.mRendererState = (shaderDef.mRendererState | RendererState::ALPHA_BLEND);
245 option.GetDefines(shaderDef.mDefines);
246 shaderDef.mUniforms["uCubeMatrix"] = Matrix::IDENTITY;
248 Index result = resources.mShaders.size();
249 shaderMap[hash] = result;
251 resources.mShaders.emplace_back(std::move(shaderDef), Shader());
253 renderable.mShaderIdx = result;
256 return renderable.mShaderIdx;
259 } // namespace Dali::Scene3D::Loader