Makes Models use common shader manager
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / internal / model-components / model-primitive-impl.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/internal/model-components/model-primitive-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/adaptor-framework/image-loading.h>
23 #include <dali/public-api/animation/constraint.h>
24 #include <dali/public-api/object/type-registry-helper.h>
25 #include <dali/public-api/object/type-registry.h>
26
27 // INTERNAL INCLUDES
28 #include <dali-scene3d/internal/light/light-impl.h>
29 #include <dali-scene3d/internal/model-components/material-impl.h>
30 #include <dali-scene3d/public-api/loader/environment-definition.h>
31
32 #include <dali/integration-api/debug.h>
33
34 namespace Dali
35 {
36 namespace Scene3D
37 {
38 namespace Internal
39 {
40 namespace
41 {
42 /**
43  * Creates control through type registry
44  */
45 BaseHandle Create()
46 {
47   return Scene3D::ModelPrimitive::New();
48 }
49
50 // Setup properties, signals and actions using the type-registry.
51 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::ModelPrimitive, Dali::BaseHandle, Create);
52 DALI_TYPE_REGISTRATION_END()
53
54 static constexpr uint32_t INDEX_FOR_LIGHT_CONSTRAINT_TAG = 10;
55 } // unnamed namespace
56
57 ModelPrimitivePtr ModelPrimitive::New()
58 {
59   ModelPrimitivePtr primitive = new ModelPrimitive();
60
61   primitive->Initialize();
62
63   return primitive;
64 }
65
66 ModelPrimitive::ModelPrimitive()
67 : mShaderManager(new Scene3D::Loader::ShaderManager())
68 {
69 }
70
71 ModelPrimitive::~ModelPrimitive()
72 {
73   if(mMaterial)
74   {
75     GetImplementation(mMaterial).RemoveObserver(this);
76   }
77   mMaterial.Reset();
78 }
79
80 void ModelPrimitive::Initialize()
81 {
82   mLights.resize(Scene3D::Internal::Light::GetMaximumEnabledLightCount());
83 }
84
85 void ModelPrimitive::SetRenderer(Dali::Renderer renderer)
86 {
87   mRenderer   = renderer;
88   mGeometry   = renderer.GetGeometry();
89   mTextureSet = renderer.GetTextures();
90   mShader     = renderer.GetShader();
91 }
92
93 Dali::Renderer ModelPrimitive::GetRenderer() const
94 {
95   return mRenderer;
96 }
97
98 void ModelPrimitive::SetGeometry(Dali::Geometry geometry)
99 {
100   mGeometry = geometry;
101   CreateRenderer();
102 }
103
104 Dali::Geometry ModelPrimitive::GetGeometry() const
105 {
106   return mGeometry;
107 }
108
109 void ModelPrimitive::SetMaterial(Dali::Scene3D::Material material, bool updateRenderer)
110 {
111   if(!material)
112   {
113     return;
114   }
115
116   if(mMaterial != material)
117   {
118     // Stop observe from previous material.
119     if(mMaterial)
120     {
121       GetImplementation(mMaterial).RemoveObserver(this);
122     }
123
124     mMaterial = material;
125
126     // Start observe from new material.
127
128     if(mMaterial)
129     {
130       GetImplementation(mMaterial).AddObserver(this);
131     }
132
133     if(updateRenderer)
134     {
135       mIsMaterialChanged = true;
136       if(GetImplementation(mMaterial).IsResourceReady())
137       {
138         GetImplementation(mMaterial).UpdateMaterialData();
139         ApplyMaterialToRenderer();
140       }
141     }
142     UpdateImageBasedLightTexture();
143   }
144 }
145
146 Dali::Scene3D::Material ModelPrimitive::GetMaterial() const
147 {
148   return mMaterial;
149 }
150
151 void ModelPrimitive::AddPrimitiveObserver(ModelPrimitiveModifyObserver* observer)
152 {
153   mObservers.insert(observer);
154 }
155
156 void ModelPrimitive::RemovePrimitiveObserver(ModelPrimitiveModifyObserver* observer)
157 {
158   mObservers.erase(observer);
159 }
160
161 void ModelPrimitive::SetImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
162 {
163   mDiffuseTexture       = diffuseTexture;
164   mSpecularTexture      = specularTexture;
165   mIblScaleFactor       = iblScaleFactor;
166   mSpecularMipmapLevels = specularMipmapLevels;
167
168   UpdateImageBasedLightTexture();
169 }
170
171 void ModelPrimitive::SetImageBasedLightScaleFactor(float iblScaleFactor)
172 {
173   mIblScaleFactor = iblScaleFactor;
174   if(mRenderer && mMaterial)
175   {
176     mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), iblScaleFactor);
177   }
178 }
179
180 void ModelPrimitive::AddLight(Scene3D::Light light, uint32_t lightIndex)
181 {
182   if(mLights[lightIndex])
183   {
184     RemoveLight(lightIndex);
185   }
186
187   mLights[lightIndex] = light;
188   // TODO  Remove light at lightIndex if it is already set.
189   if(mRenderer && mMaterial)
190   {
191     mLightCount++;
192     std::string lightCountPropertyName(Scene3D::Internal::Light::GetLightCountUniformName());
193     mRenderer.RegisterProperty(lightCountPropertyName, mLightCount);
194
195     std::string lightDirectionPropertyName(Scene3D::Internal::Light::GetLightDirectionUniformName());
196     lightDirectionPropertyName += "[" + std::to_string(lightIndex) + "]";
197     auto             lightDirectionPropertyIndex = mRenderer.RegisterProperty(lightDirectionPropertyName, Vector3::ZAXIS);
198     Dali::Constraint lightDirectionConstraint    = Dali::Constraint::New<Vector3>(mRenderer, lightDirectionPropertyIndex, [](Vector3& output, const PropertyInputContainer& inputs)
199                                                                                { output = inputs[0]->GetQuaternion().Rotate(Vector3::ZAXIS); });
200     lightDirectionConstraint.AddSource(Source{light, Dali::Actor::Property::WORLD_ORIENTATION});
201     lightDirectionConstraint.ApplyPost();
202     lightDirectionConstraint.SetTag(INDEX_FOR_LIGHT_CONSTRAINT_TAG + lightIndex);
203
204     std::string lightColorPropertyName(Scene3D::Internal::Light::GetLightColorUniformName());
205     lightColorPropertyName += "[" + std::to_string(lightIndex) + "]";
206     auto             lightColorPropertyIndex = mRenderer.RegisterProperty(lightColorPropertyName, Vector3(Color::WHITE));
207     Dali::Constraint lightColorConstraint    = Dali::Constraint::New<Vector3>(mRenderer, lightColorPropertyIndex, [](Vector3& output, const PropertyInputContainer& inputs)
208                                                                            { output = Vector3(inputs[0]->GetVector4()); });
209     lightColorConstraint.AddSource(Source{light, Dali::Actor::Property::COLOR});
210     lightColorConstraint.ApplyPost();
211     lightColorConstraint.SetTag(INDEX_FOR_LIGHT_CONSTRAINT_TAG + lightIndex);
212   }
213 }
214
215 void ModelPrimitive::RemoveLight(uint32_t lightIndex)
216 {
217   mLightCount--;
218   std::string lightCountPropertyName(Scene3D::Internal::Light::GetLightCountUniformName());
219   mRenderer.RegisterProperty(lightCountPropertyName, mLightCount);
220
221   mRenderer.RemoveConstraints(INDEX_FOR_LIGHT_CONSTRAINT_TAG + lightIndex);
222
223   mLights[lightIndex].Reset();
224 }
225
226 void ModelPrimitive::UpdateShader(Scene3D::Loader::ShaderManagerPtr shaderManager)
227 {
228   if(mShaderManager != shaderManager)
229   {
230     mShaderManager = (shaderManager) ? shaderManager : new Scene3D::Loader::ShaderManager();
231     if(mMaterial && GetImplementation(mMaterial).IsResourceReady())
232     {
233       ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag::SHADER);
234     }
235   }
236 }
237
238 void ModelPrimitive::SetBlendShapeData(Scene3D::Loader::BlendShapes::BlendShapeData& data)
239 {
240   mBlendShapeData = std::move(data);
241   Scene3D::Loader::BlendShapes::ConfigureProperties(mBlendShapeData, mRenderer);
242 }
243
244 void ModelPrimitive::SetBlendShapeGeometry(Dali::Texture blendShapeGeometry)
245 {
246   mBlendShapeGeometry = blendShapeGeometry;
247 }
248
249 void ModelPrimitive::SetBlendShapeOptions(bool hasPositions, bool hasNormals, bool hasTangents, Scene3D::Loader::BlendShapes::Version version)
250 {
251   mHasPositions      = hasPositions;
252   mHasNormals        = hasNormals;
253   mHasTangents       = hasTangents;
254   mBlendShapeVersion = version;
255 }
256
257 void ModelPrimitive::SetSkinned(bool isSkinned)
258 {
259   mHasSkinning = isSkinned;
260 }
261
262 // From MaterialModifyObserver
263
264 void ModelPrimitive::OnMaterialModified(Dali::Scene3D::Material material, MaterialModifyObserver::ModifyFlag flag)
265 {
266   ApplyMaterialToRenderer(flag);
267 }
268
269 void ModelPrimitive::ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag flag)
270 {
271   if(!mMaterial)
272   {
273     return;
274   }
275
276   uint32_t shaderFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::SHADER));
277   if(mIsMaterialChanged || shaderFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::SHADER))
278   {
279     Scene3D::Loader::ShaderOption shaderOption = GetImplementation(mMaterial).GetShaderOption();
280
281     shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::VEC4_TANGENT);
282     if(mHasSkinning)
283     {
284       shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::SKINNING);
285     }
286     if(mHasPositions || mHasNormals || mHasTangents)
287     {
288       if(mHasPositions)
289       {
290         shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::MORPH_POSITION);
291       }
292       if(mHasNormals)
293       {
294         shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::MORPH_NORMAL);
295       }
296       if(mHasTangents)
297       {
298         shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::MORPH_TANGENT);
299       }
300       if(mBlendShapeVersion == Scene3D::Loader::BlendShapes::Version::VERSION_2_0)
301       {
302         shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::MORPH_VERSION_2_0);
303       }
304     }
305
306     mShader.Reset();
307     mShader = mShaderManager->ProduceShader(shaderOption);
308
309     if(!mRenderer)
310     {
311       CreateRenderer();
312     }
313     else
314     {
315       mRenderer.SetShader(mShader);
316     }
317   }
318
319   uint32_t textureFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::TEXTURE));
320   if(mIsMaterialChanged || textureFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::TEXTURE))
321   {
322     mTextureSet = GetImplementation(mMaterial).GetTextureSet();
323
324     if(mBlendShapeGeometry)
325     {
326       TextureSet newTextureSet = TextureSet::New();
327       newTextureSet.SetTexture(0u, mBlendShapeGeometry);
328
329       const unsigned int numberOfTextures = mTextureSet.GetTextureCount();
330       for(unsigned int index = 0u; index < numberOfTextures; ++index)
331       {
332         const unsigned int newIndex = index + 1u;
333         newTextureSet.SetTexture(newIndex, mTextureSet.GetTexture(index));
334         newTextureSet.SetSampler(newIndex, mTextureSet.GetSampler(index));
335       }
336
337       mTextureSet = newTextureSet;
338     }
339
340     uint32_t textureCount = mTextureSet.GetTextureCount();
341     Texture  brdfTexture  = Scene3D::Loader::EnvironmentDefinition::GetBrdfTexture();
342     if(!mSpecularTexture || !mDiffuseTexture)
343     {
344       Scene3D::Loader::EnvironmentMapData environmentMapData;
345       environmentMapData.mPixelData.resize(6);
346       for(auto& face : environmentMapData.mPixelData)
347       {
348         face.push_back(PixelData::New(new uint8_t[3]{0xff, 0xff, 0xff}, 3, 1, 1, Pixel::RGB888, PixelData::DELETE_ARRAY));
349       }
350       environmentMapData.SetEnvironmentMapType(Dali::Scene3D::EnvironmentMapType::CUBEMAP);
351       Texture iblTexture = environmentMapData.GetTexture();
352       mDiffuseTexture    = iblTexture;
353       mSpecularTexture   = iblTexture;
354     }
355
356     mTextureSet.SetTexture(textureCount++, brdfTexture);
357     mTextureSet.SetTexture(textureCount++, mDiffuseTexture);
358     mTextureSet.SetTexture(textureCount, mSpecularTexture);
359
360     auto specularSampler = Sampler::New();
361     specularSampler.SetWrapMode(WrapMode::CLAMP_TO_EDGE, WrapMode::CLAMP_TO_EDGE, WrapMode::CLAMP_TO_EDGE);
362     specularSampler.SetFilterMode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR);
363     mTextureSet.SetSampler(textureCount, specularSampler);
364
365     if(!mRenderer)
366     {
367       CreateRenderer();
368     }
369     else
370     {
371       mRenderer.SetTextures(mTextureSet);
372     }
373   }
374
375   uint32_t uniformFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::UNIFORM));
376   if(mIsMaterialChanged || uniformFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::UNIFORM))
377   {
378     if(!mRenderer)
379     {
380       mNeedToSetRendererUniform = true;
381     }
382     else
383     {
384       UpdateRendererUniform();
385     }
386   }
387   mIsMaterialChanged = false;
388 }
389
390 void ModelPrimitive::CreateRenderer()
391 {
392   if(!mShader || !mGeometry || !mTextureSet || mRenderer)
393   {
394     return;
395   }
396
397   mRenderer = Renderer::New(mGeometry, mShader);
398   mRenderer.SetTextures(mTextureSet);
399   UpdateRendererUniform();
400
401   uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
402   for(uint32_t i = 0; i < maxLightCount; ++i)
403   {
404     if(mLights[i])
405     {
406       AddLight(mLights[i], i);
407     }
408   }
409
410   for(auto* observer : mObservers)
411   {
412     observer->OnRendererCreated(mRenderer);
413   }
414 }
415
416 void ModelPrimitive::UpdateImageBasedLightTexture()
417 {
418   if(mRenderer && mMaterial)
419   {
420     Dali::TextureSet textures = mRenderer.GetTextures();
421     if(!textures)
422     {
423       return;
424     }
425
426     uint32_t textureCount = textures.GetTextureCount();
427     if(textureCount > 2u &&
428        (textures.GetTexture(textureCount - GetImplementation(mMaterial).GetDiffuseImageBasedLightTextureOffset()) != mDiffuseTexture ||
429         textures.GetTexture(textureCount - GetImplementation(mMaterial).GetSpecularImageBasedLightTextureOffset()) != mSpecularTexture))
430     {
431       Dali::TextureSet newTextures = Dali::TextureSet::New();
432
433       for(uint32_t index = 0u; index < textureCount; ++index)
434       {
435         Dali::Texture texture = textures.GetTexture(index);
436         if(index == textureCount - GetImplementation(mMaterial).GetDiffuseImageBasedLightTextureOffset())
437         {
438           texture = mDiffuseTexture;
439         }
440         else if(index == textureCount - GetImplementation(mMaterial).GetSpecularImageBasedLightTextureOffset())
441         {
442           texture = mSpecularTexture;
443         }
444
445         newTextures.SetTexture(index, texture);
446         newTextures.SetSampler(index, textures.GetSampler(index));
447       }
448
449       mRenderer.SetTextures(newTextures);
450     }
451     mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), mIblScaleFactor);
452     mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightMaxLodUniformName().data(), static_cast<float>(mSpecularMipmapLevels));
453   }
454 }
455
456 void ModelPrimitive::UpdateRendererUniform()
457 {
458   if(mMaterial)
459   {
460     mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), mIblScaleFactor);
461     mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightMaxLodUniformName().data(), static_cast<float>(mSpecularMipmapLevels));
462     GetImplementation(mMaterial).SetRendererUniform(mRenderer);
463   }
464 }
465
466 } // namespace Internal
467
468 } // namespace Scene3D
469
470 } // namespace Dali