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