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