Merge branch 'devel/master' into tizen
[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/object/type-registry-helper.h>
24 #include <dali/public-api/object/type-registry.h>
25
26 // INTERNAL INCLUDES
27 #include <dali-scene3d/internal/model-components/material-impl.h>
28 #include <dali-scene3d/public-api/loader/environment-definition.h>
29
30 namespace Dali
31 {
32 namespace Scene3D
33 {
34 namespace Internal
35 {
36 namespace
37 {
38 /**
39  * Creates control through type registry
40  */
41 BaseHandle Create()
42 {
43   return Scene3D::ModelPrimitive::New();
44 }
45
46 // Setup properties, signals and actions using the type-registry.
47 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::ModelPrimitive, Dali::BaseHandle, Create);
48 DALI_TYPE_REGISTRATION_END()
49
50 constexpr std::string_view MORPH_KEYWORD             = "MORPH";
51 constexpr std::string_view MORPH_POSITION_KEYWORD    = "MORPH_POSITION";
52 constexpr std::string_view MORPH_NORMAL_KEYWORD      = "MORPH_NORMAL";
53 constexpr std::string_view MORPH_TANGENT_KEYWORD     = "MORPH_TANGENT";
54 constexpr std::string_view MORPH_VERSION_2_0_KEYWORD = "MORPH_VERSION_2_0";
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 {
68 }
69
70 ModelPrimitive::~ModelPrimitive()
71 {
72   if(mMaterial)
73   {
74     GetImplementation(mMaterial).RemoveObserver(this);
75   }
76   mMaterial.Reset();
77 }
78
79 void ModelPrimitive::Initialize()
80 {
81 }
82
83 void ModelPrimitive::SetRenderer(Dali::Renderer renderer)
84 {
85   mRenderer   = renderer;
86   mGeometry   = renderer.GetGeometry();
87   mTextureSet = renderer.GetTextures();
88   mShader     = renderer.GetShader();
89 }
90
91 Dali::Renderer ModelPrimitive::GetRenderer() const
92 {
93   return mRenderer;
94 }
95
96 void ModelPrimitive::SetGeometry(Dali::Geometry geometry)
97 {
98   mGeometry = geometry;
99   CreateRenderer();
100 }
101
102 Dali::Geometry ModelPrimitive::GetGeometry() const
103 {
104   return mGeometry;
105 }
106
107 void ModelPrimitive::SetMaterial(Dali::Scene3D::Material material, bool updateRenderer)
108 {
109   if(!material)
110   {
111     return;
112   }
113
114   if(mMaterial != material)
115   {
116     // Stop observe from previous material.
117     if(mMaterial)
118     {
119       GetImplementation(mMaterial).RemoveObserver(this);
120     }
121
122     mMaterial = material;
123
124     // Start observe from new material.
125
126     if(mMaterial)
127     {
128       GetImplementation(mMaterial).AddObserver(this);
129     }
130
131     if(updateRenderer)
132     {
133       mIsMaterialChanged = true;
134       if(GetImplementation(mMaterial).IsResourceReady())
135       {
136         GetImplementation(mMaterial).UpdateMaterialData();
137         ApplyMaterialToRenderer();
138       }
139     }
140     UpdateImageBasedLightTexture();
141   }
142 }
143
144 Dali::Scene3D::Material ModelPrimitive::GetMaterial() const
145 {
146   return mMaterial;
147 }
148
149 void ModelPrimitive::AddPrimitiveObserver(ModelPrimitiveModifyObserver* observer)
150 {
151   mObservers.insert(observer);
152 }
153
154 void ModelPrimitive::RemovePrimitiveObserver(ModelPrimitiveModifyObserver* observer)
155 {
156   mObservers.erase(observer);
157 }
158
159 void ModelPrimitive::SetImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
160 {
161   mDiffuseTexture       = diffuseTexture;
162   mSpecularTexture      = specularTexture;
163   mIblScaleFactor       = iblScaleFactor;
164   mSpecularMipmapLevels = specularMipmapLevels;
165
166   UpdateImageBasedLightTexture();
167 }
168
169 void ModelPrimitive::SetImageBasedLightScaleFactor(float iblScaleFactor)
170 {
171   mIblScaleFactor = iblScaleFactor;
172   if(mRenderer && mMaterial)
173   {
174     mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), iblScaleFactor);
175   }
176 }
177
178 void ModelPrimitive::SetBlendShapeData(Scene3D::Loader::BlendShapes::BlendShapeData& data)
179 {
180   mBlendShapeData = std::move(data);
181   Scene3D::Loader::BlendShapes::ConfigureProperties(mBlendShapeData, mRenderer);
182 }
183
184 void ModelPrimitive::SetBlendShapeGeometry(Dali::Texture blendShapeGeometry)
185 {
186   mBlendShapeGeometry = blendShapeGeometry;
187 }
188
189 void ModelPrimitive::SetBlendShapeOptions(bool hasPositions, bool hasNormals, bool hasTangents)
190 {
191   mHasPositions = hasPositions;
192   mHasNormals   = hasNormals;
193   mHasTangents  = hasTangents;
194 }
195
196 void ModelPrimitive::SetSkinned(bool isSkinned)
197 {
198   mHasSkinning = isSkinned;
199 }
200
201 // From MaterialModifyObserver
202
203 void ModelPrimitive::OnMaterialModified(Dali::Scene3D::Material material, MaterialModifyObserver::ModifyFlag flag)
204 {
205   ApplyMaterialToRenderer(flag);
206 }
207
208 void ModelPrimitive::ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag flag)
209 {
210   uint32_t shaderFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::SHADER));
211   if(mIsMaterialChanged || shaderFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::SHADER))
212   {
213     std::string vertexShader   = GetImplementation(mMaterial).GetVertexShader();
214     std::string fragmentShader = GetImplementation(mMaterial).GetFragmentShader();
215
216     std::vector<std::string> defines;
217     defines.push_back("VEC4_TANGENT");
218     if(mHasSkinning)
219     {
220       defines.push_back("SKINNING");
221     }
222     if(mHasPositions || mHasNormals || mHasTangents)
223     {
224       if(mHasPositions)
225       {
226         defines.push_back(MORPH_POSITION_KEYWORD.data());
227       }
228       if(mHasNormals)
229       {
230         defines.push_back(MORPH_NORMAL_KEYWORD.data());
231       }
232       if(mHasTangents)
233       {
234         defines.push_back(MORPH_TANGENT_KEYWORD.data());
235       }
236       defines.push_back(MORPH_KEYWORD.data());
237       if(mBlendShapeData.version == Scene3D::Loader::BlendShapes::Version::VERSION_2_0)
238       {
239         defines.push_back(MORPH_VERSION_2_0_KEYWORD.data());
240       }
241     }
242     for(const auto& define : defines)
243     {
244       Scene3D::Loader::ShaderDefinition::ApplyDefine(vertexShader, define);
245     }
246
247     mShader.Reset();
248     mShader = Shader::New(vertexShader, fragmentShader);
249
250     if(!mRenderer)
251     {
252       CreateRenderer();
253     }
254     else
255     {
256       mRenderer.SetShader(mShader);
257     }
258   }
259
260   uint32_t textureFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::TEXTURE));
261   if(mIsMaterialChanged || textureFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::TEXTURE))
262   {
263     mTextureSet = GetImplementation(mMaterial).GetTextureSet();
264
265     if(mBlendShapeGeometry)
266     {
267       TextureSet newTextureSet = TextureSet::New();
268       newTextureSet.SetTexture(0u, mBlendShapeGeometry);
269
270       const unsigned int numberOfTextures = mTextureSet.GetTextureCount();
271       for(unsigned int index = 0u; index < numberOfTextures; ++index)
272       {
273         const unsigned int newIndex = index + 1u;
274         newTextureSet.SetTexture(newIndex, mTextureSet.GetTexture(index));
275         newTextureSet.SetSampler(newIndex, mTextureSet.GetSampler(index));
276       }
277
278       mTextureSet = newTextureSet;
279     }
280
281     uint32_t textureCount = mTextureSet.GetTextureCount();
282     Texture  brdfTexture  = Scene3D::Loader::EnvironmentDefinition::GetBrdfTexture();
283     if(!mSpecularTexture || !mDiffuseTexture)
284     {
285       Scene3D::Loader::EnvironmentMapData environmentMapData;
286       environmentMapData.mPixelData.resize(6);
287       for(auto& face : environmentMapData.mPixelData)
288       {
289         face.push_back(PixelData::New(new uint8_t[3]{0xff, 0xff, 0xff}, 3, 1, 1, Pixel::RGB888, PixelData::DELETE_ARRAY));
290       }
291       environmentMapData.SetEnvironmentMapType(Dali::Scene3D::EnvironmentMapType::CUBEMAP);
292       Texture iblTexture = environmentMapData.GetTexture();
293       mDiffuseTexture    = iblTexture;
294       mSpecularTexture   = iblTexture;
295     }
296
297     mTextureSet.SetTexture(textureCount++, brdfTexture);
298     mTextureSet.SetTexture(textureCount++, mDiffuseTexture);
299     mTextureSet.SetTexture(textureCount, mSpecularTexture);
300
301     auto specularSampler = Sampler::New();
302     specularSampler.SetWrapMode(WrapMode::CLAMP_TO_EDGE, WrapMode::CLAMP_TO_EDGE, WrapMode::CLAMP_TO_EDGE);
303     specularSampler.SetFilterMode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR);
304     mTextureSet.SetSampler(textureCount, specularSampler);
305
306     if(!mRenderer)
307     {
308       CreateRenderer();
309     }
310     else
311     {
312       mRenderer.SetTextures(mTextureSet);
313     }
314   }
315
316   uint32_t uniformFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::UNIFORM));
317   if(mIsMaterialChanged || uniformFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::UNIFORM))
318   {
319     if(!mRenderer)
320     {
321       mNeedToSetRendererUniform = true;
322     }
323     else
324     {
325       UpdateRendererUniform();
326     }
327   }
328   mIsMaterialChanged = false;
329 }
330
331 void ModelPrimitive::CreateRenderer()
332 {
333   if(!mShader || !mGeometry || !mTextureSet || mRenderer)
334   {
335     return;
336   }
337
338   mRenderer = Renderer::New(mGeometry, mShader);
339   mRenderer.SetTextures(mTextureSet);
340   UpdateRendererUniform();
341   for(auto* observer : mObservers)
342   {
343     observer->OnRendererCreated(mRenderer);
344   }
345 }
346
347 void ModelPrimitive::UpdateImageBasedLightTexture()
348 {
349   if(mRenderer && mMaterial)
350   {
351     Dali::TextureSet textures = mRenderer.GetTextures();
352     if(!textures)
353     {
354       return;
355     }
356
357     uint32_t textureCount = textures.GetTextureCount();
358     if(textureCount > 2u &&
359        (textures.GetTexture(textureCount - GetImplementation(mMaterial).GetDiffuseImageBasedLightTextureOffset()) != mDiffuseTexture ||
360         textures.GetTexture(textureCount - GetImplementation(mMaterial).GetSpecularImageBasedLightTextureOffset()) != mSpecularTexture))
361     {
362       Dali::TextureSet newTextures = Dali::TextureSet::New();
363
364       for(uint32_t index = 0u; index < textureCount; ++index)
365       {
366         Dali::Texture texture = textures.GetTexture(index);
367         if(index == textureCount - GetImplementation(mMaterial).GetDiffuseImageBasedLightTextureOffset())
368         {
369           texture = mDiffuseTexture;
370         }
371         else if(index == textureCount - GetImplementation(mMaterial).GetSpecularImageBasedLightTextureOffset())
372         {
373           texture = mSpecularTexture;
374         }
375
376         newTextures.SetTexture(index, texture);
377         newTextures.SetSampler(index, textures.GetSampler(index));
378       }
379
380       mRenderer.SetTextures(newTextures);
381     }
382     mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), mIblScaleFactor);
383     mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightMaxLodUniformName().data(), static_cast<float>(mSpecularMipmapLevels));
384   }
385 }
386
387 void ModelPrimitive::UpdateRendererUniform()
388 {
389   mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), mIblScaleFactor);
390   mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightMaxLodUniformName().data(), static_cast<float>(mSpecularMipmapLevels));
391   GetImplementation(mMaterial).SetRendererUniform(mRenderer);
392 }
393
394 } // namespace Internal
395
396 } // namespace Scene3D
397
398 } // namespace Dali