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