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