Merge "Apply Light using Shader Manager" into devel/master
[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 }
83
84 void ModelPrimitive::SetRenderer(Dali::Renderer renderer)
85 {
86   mRenderer   = renderer;
87   mGeometry   = renderer.GetGeometry();
88   mTextureSet = renderer.GetTextures();
89   mShader     = renderer.GetShader();
90 }
91
92 Dali::Renderer ModelPrimitive::GetRenderer() const
93 {
94   return mRenderer;
95 }
96
97 void ModelPrimitive::SetGeometry(Dali::Geometry geometry)
98 {
99   mGeometry = geometry;
100   CreateRenderer();
101 }
102
103 Dali::Geometry ModelPrimitive::GetGeometry() const
104 {
105   return mGeometry;
106 }
107
108 void ModelPrimitive::SetMaterial(Dali::Scene3D::Material material, bool updateRenderer)
109 {
110   if(!material)
111   {
112     return;
113   }
114
115   if(mMaterial != material)
116   {
117     // Stop observe from previous material.
118     if(mMaterial)
119     {
120       GetImplementation(mMaterial).RemoveObserver(this);
121     }
122
123     mMaterial = material;
124
125     // Start observe from new material.
126
127     if(mMaterial)
128     {
129       GetImplementation(mMaterial).AddObserver(this);
130     }
131
132     if(updateRenderer)
133     {
134       mIsMaterialChanged = true;
135       if(GetImplementation(mMaterial).IsResourceReady())
136       {
137         GetImplementation(mMaterial).UpdateMaterialData();
138         ApplyMaterialToRenderer();
139       }
140     }
141     UpdateImageBasedLightTexture();
142   }
143 }
144
145 Dali::Scene3D::Material ModelPrimitive::GetMaterial() const
146 {
147   return mMaterial;
148 }
149
150 void ModelPrimitive::AddPrimitiveObserver(ModelPrimitiveModifyObserver* observer)
151 {
152   mObservers.insert(observer);
153 }
154
155 void ModelPrimitive::RemovePrimitiveObserver(ModelPrimitiveModifyObserver* observer)
156 {
157   mObservers.erase(observer);
158 }
159
160 void ModelPrimitive::SetImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
161 {
162   mDiffuseTexture       = diffuseTexture;
163   mSpecularTexture      = specularTexture;
164   mIblScaleFactor       = iblScaleFactor;
165   mSpecularMipmapLevels = specularMipmapLevels;
166
167   UpdateImageBasedLightTexture();
168 }
169
170 void ModelPrimitive::SetImageBasedLightScaleFactor(float iblScaleFactor)
171 {
172   mIblScaleFactor = iblScaleFactor;
173   if(mRenderer && mMaterial)
174   {
175     mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), iblScaleFactor);
176   }
177 }
178
179 void ModelPrimitive::UpdateShader(Scene3D::Loader::ShaderManagerPtr shaderManager)
180 {
181   if(mShaderManager != shaderManager)
182   {
183     mShaderManager = (shaderManager) ? shaderManager : new Scene3D::Loader::ShaderManager();
184     if(mMaterial && GetImplementation(mMaterial).IsResourceReady())
185     {
186       ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag::SHADER);
187     }
188   }
189 }
190
191 void ModelPrimitive::SetBlendShapeData(Scene3D::Loader::BlendShapes::BlendShapeData& data)
192 {
193   mBlendShapeData = std::move(data);
194   Scene3D::Loader::BlendShapes::ConfigureProperties(mBlendShapeData, mRenderer);
195 }
196
197 void ModelPrimitive::SetBlendShapeGeometry(Dali::Texture blendShapeGeometry)
198 {
199   mBlendShapeGeometry = blendShapeGeometry;
200 }
201
202 void ModelPrimitive::SetBlendShapeOptions(bool hasPositions, bool hasNormals, bool hasTangents, Scene3D::Loader::BlendShapes::Version version)
203 {
204   mHasPositions      = hasPositions;
205   mHasNormals        = hasNormals;
206   mHasTangents       = hasTangents;
207   mBlendShapeVersion = version;
208 }
209
210 void ModelPrimitive::SetSkinned(bool isSkinned)
211 {
212   mHasSkinning = isSkinned;
213 }
214
215 // From MaterialModifyObserver
216
217 void ModelPrimitive::OnMaterialModified(Dali::Scene3D::Material material, MaterialModifyObserver::ModifyFlag flag)
218 {
219   ApplyMaterialToRenderer(flag);
220 }
221
222 void ModelPrimitive::ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag flag)
223 {
224   if(!mMaterial)
225   {
226     return;
227   }
228
229   uint32_t shaderFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::SHADER));
230   if(mIsMaterialChanged || shaderFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::SHADER))
231   {
232     Scene3D::Loader::ShaderOption shaderOption = GetImplementation(mMaterial).GetShaderOption();
233
234     shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::VEC4_TANGENT);
235     if(mHasSkinning)
236     {
237       shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::SKINNING);
238     }
239     if(mHasPositions || mHasNormals || mHasTangents)
240     {
241       if(mHasPositions)
242       {
243         shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::MORPH_POSITION);
244       }
245       if(mHasNormals)
246       {
247         shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::MORPH_NORMAL);
248       }
249       if(mHasTangents)
250       {
251         shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::MORPH_TANGENT);
252       }
253       if(mBlendShapeVersion == Scene3D::Loader::BlendShapes::Version::VERSION_2_0)
254       {
255         shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::MORPH_VERSION_2_0);
256       }
257     }
258
259     mShader.Reset();
260     mShader = mShaderManager->ProduceShader(shaderOption);
261
262     if(!mRenderer)
263     {
264       CreateRenderer();
265     }
266     else
267     {
268       mRenderer.SetShader(mShader);
269     }
270   }
271
272   uint32_t textureFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::TEXTURE));
273   if(mIsMaterialChanged || textureFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::TEXTURE))
274   {
275     mTextureSet = GetImplementation(mMaterial).GetTextureSet();
276
277     if(mBlendShapeGeometry)
278     {
279       TextureSet newTextureSet = TextureSet::New();
280       newTextureSet.SetTexture(0u, mBlendShapeGeometry);
281
282       const unsigned int numberOfTextures = mTextureSet.GetTextureCount();
283       for(unsigned int index = 0u; index < numberOfTextures; ++index)
284       {
285         const unsigned int newIndex = index + 1u;
286         newTextureSet.SetTexture(newIndex, mTextureSet.GetTexture(index));
287         newTextureSet.SetSampler(newIndex, mTextureSet.GetSampler(index));
288       }
289
290       mTextureSet = newTextureSet;
291     }
292
293     uint32_t textureCount = mTextureSet.GetTextureCount();
294     Texture  brdfTexture  = Scene3D::Loader::EnvironmentDefinition::GetBrdfTexture();
295     if(!mSpecularTexture || !mDiffuseTexture)
296     {
297       Scene3D::Loader::EnvironmentMapData environmentMapData;
298       environmentMapData.mPixelData.resize(6);
299       for(auto& face : environmentMapData.mPixelData)
300       {
301         face.push_back(PixelData::New(new uint8_t[3]{0xff, 0xff, 0xff}, 3, 1, 1, Pixel::RGB888, PixelData::DELETE_ARRAY));
302       }
303       environmentMapData.SetEnvironmentMapType(Dali::Scene3D::EnvironmentMapType::CUBEMAP);
304       Texture iblTexture = environmentMapData.GetTexture();
305       mDiffuseTexture    = iblTexture;
306       mSpecularTexture   = iblTexture;
307     }
308
309     mTextureSet.SetTexture(textureCount++, brdfTexture);
310     mTextureSet.SetTexture(textureCount++, mDiffuseTexture);
311     mTextureSet.SetTexture(textureCount, mSpecularTexture);
312
313     auto specularSampler = Sampler::New();
314     specularSampler.SetWrapMode(WrapMode::CLAMP_TO_EDGE, WrapMode::CLAMP_TO_EDGE, WrapMode::CLAMP_TO_EDGE);
315     specularSampler.SetFilterMode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR);
316     mTextureSet.SetSampler(textureCount, specularSampler);
317
318     if(!mRenderer)
319     {
320       CreateRenderer();
321     }
322     else
323     {
324       mRenderer.SetTextures(mTextureSet);
325     }
326   }
327
328   uint32_t uniformFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::UNIFORM));
329   if(mIsMaterialChanged || uniformFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::UNIFORM))
330   {
331     if(!mRenderer)
332     {
333       mNeedToSetRendererUniform = true;
334     }
335     else
336     {
337       UpdateRendererUniform();
338     }
339   }
340   mIsMaterialChanged = false;
341 }
342
343 void ModelPrimitive::CreateRenderer()
344 {
345   if(!mShader || !mGeometry || !mTextureSet || mRenderer)
346   {
347     return;
348   }
349
350   mRenderer = Renderer::New(mGeometry, mShader);
351   mRenderer.SetTextures(mTextureSet);
352   UpdateRendererUniform();
353
354   for(auto* observer : mObservers)
355   {
356     observer->OnRendererCreated(mRenderer);
357   }
358 }
359
360 void ModelPrimitive::UpdateImageBasedLightTexture()
361 {
362   if(mRenderer && mMaterial)
363   {
364     Dali::TextureSet textures = mRenderer.GetTextures();
365     if(!textures)
366     {
367       return;
368     }
369
370     uint32_t textureCount = textures.GetTextureCount();
371     if(textureCount > 2u &&
372        (textures.GetTexture(textureCount - GetImplementation(mMaterial).GetDiffuseImageBasedLightTextureOffset()) != mDiffuseTexture ||
373         textures.GetTexture(textureCount - GetImplementation(mMaterial).GetSpecularImageBasedLightTextureOffset()) != mSpecularTexture))
374     {
375       Dali::TextureSet newTextures = Dali::TextureSet::New();
376
377       for(uint32_t index = 0u; index < textureCount; ++index)
378       {
379         Dali::Texture texture = textures.GetTexture(index);
380         if(index == textureCount - GetImplementation(mMaterial).GetDiffuseImageBasedLightTextureOffset())
381         {
382           texture = mDiffuseTexture;
383         }
384         else if(index == textureCount - GetImplementation(mMaterial).GetSpecularImageBasedLightTextureOffset())
385         {
386           texture = mSpecularTexture;
387         }
388
389         newTextures.SetTexture(index, texture);
390         newTextures.SetSampler(index, textures.GetSampler(index));
391       }
392
393       mRenderer.SetTextures(newTextures);
394     }
395     mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), mIblScaleFactor);
396     mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightMaxLodUniformName().data(), static_cast<float>(mSpecularMipmapLevels));
397   }
398 }
399
400 void ModelPrimitive::UpdateRendererUniform()
401 {
402   if(mMaterial)
403   {
404     mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), mIblScaleFactor);
405     mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightMaxLodUniformName().data(), static_cast<float>(mSpecularMipmapLevels));
406     GetImplementation(mMaterial).SetRendererUniform(mRenderer);
407   }
408 }
409
410 } // namespace Internal
411
412 } // namespace Scene3D
413
414 } // namespace Dali