b4f2b17ac6e75c48ff7fd889a42fcb09e9df80ae
[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     if(mBlendShapeData.version != Scene3D::Loader::BlendShapes::Version::INVALID && mBlendShapeData.mActor.GetHandle())
250     {
251       Scene3D::Loader::BlendShapes::ConfigureProperties(mBlendShapeData, mRenderer);
252     }
253
254     if(!mRenderer)
255     {
256       CreateRenderer();
257     }
258     else
259     {
260       mRenderer.SetShader(mShader);
261     }
262   }
263
264   uint32_t textureFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::TEXTURE));
265   if(mIsMaterialChanged || textureFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::TEXTURE))
266   {
267     mTextureSet = GetImplementation(mMaterial).GetTextureSet();
268
269     if(mBlendShapeGeometry)
270     {
271       TextureSet newTextureSet = TextureSet::New();
272       newTextureSet.SetTexture(0u, mBlendShapeGeometry);
273
274       const unsigned int numberOfTextures = mTextureSet.GetTextureCount();
275       for(unsigned int index = 0u; index < numberOfTextures; ++index)
276       {
277         const unsigned int newIndex = index + 1u;
278         newTextureSet.SetTexture(newIndex, mTextureSet.GetTexture(index));
279         newTextureSet.SetSampler(newIndex, mTextureSet.GetSampler(index));
280       }
281
282       mTextureSet = newTextureSet;
283     }
284
285     uint32_t textureCount = mTextureSet.GetTextureCount();
286     Texture  brdfTexture  = Scene3D::Loader::EnvironmentDefinition::GetBrdfTexture();
287     if(!mSpecularTexture || !mDiffuseTexture)
288     {
289       Scene3D::Loader::EnvironmentMapData environmentMapData;
290       environmentMapData.mPixelData.resize(6);
291       for(auto& face : environmentMapData.mPixelData)
292       {
293         face.push_back(PixelData::New(new uint8_t[3]{0xff, 0xff, 0xff}, 3, 1, 1, Pixel::RGB888, PixelData::DELETE_ARRAY));
294       }
295       environmentMapData.SetEnvironmentMapType(Dali::Scene3D::EnvironmentMapType::CUBEMAP);
296       Texture iblTexture = environmentMapData.GetTexture();
297       mDiffuseTexture    = iblTexture;
298       mSpecularTexture   = iblTexture;
299     }
300
301     mTextureSet.SetTexture(textureCount++, brdfTexture);
302     mTextureSet.SetTexture(textureCount++, mDiffuseTexture);
303     mTextureSet.SetTexture(textureCount, mSpecularTexture);
304
305     auto specularSampler = Sampler::New();
306     specularSampler.SetWrapMode(WrapMode::CLAMP_TO_EDGE, WrapMode::CLAMP_TO_EDGE, WrapMode::CLAMP_TO_EDGE);
307     specularSampler.SetFilterMode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR);
308     mTextureSet.SetSampler(textureCount, specularSampler);
309
310     if(!mRenderer)
311     {
312       CreateRenderer();
313     }
314     else
315     {
316       mRenderer.SetTextures(mTextureSet);
317     }
318   }
319
320   uint32_t uniformFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::UNIFORM));
321   if(mIsMaterialChanged || uniformFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::UNIFORM))
322   {
323     if(!mRenderer)
324     {
325       mNeedToSetRendererUniform = true;
326     }
327     else
328     {
329       UpdateRendererUniform();
330     }
331   }
332   mIsMaterialChanged = false;
333 }
334
335 void ModelPrimitive::CreateRenderer()
336 {
337   if(!mShader || !mGeometry || !mTextureSet || mRenderer)
338   {
339     return;
340   }
341
342   mRenderer = Renderer::New(mGeometry, mShader);
343   mRenderer.SetTextures(mTextureSet);
344   UpdateRendererUniform();
345   for(auto* observer : mObservers)
346   {
347     observer->OnRendererCreated(mRenderer);
348   }
349 }
350
351 void ModelPrimitive::UpdateImageBasedLightTexture()
352 {
353   if(mRenderer && mMaterial)
354   {
355     Dali::TextureSet textures = mRenderer.GetTextures();
356     if(!textures)
357     {
358       return;
359     }
360
361     uint32_t textureCount = textures.GetTextureCount();
362     if(textureCount > 2u &&
363        (textures.GetTexture(textureCount - GetImplementation(mMaterial).GetDiffuseImageBasedLightTextureOffset()) != mDiffuseTexture ||
364         textures.GetTexture(textureCount - GetImplementation(mMaterial).GetSpecularImageBasedLightTextureOffset()) != mSpecularTexture))
365     {
366       Dali::TextureSet newTextures = Dali::TextureSet::New();
367
368       for(uint32_t index = 0u; index < textureCount; ++index)
369       {
370         Dali::Texture texture = textures.GetTexture(index);
371         if(index == textureCount - GetImplementation(mMaterial).GetDiffuseImageBasedLightTextureOffset())
372         {
373           texture = mDiffuseTexture;
374         }
375         else if(index == textureCount - GetImplementation(mMaterial).GetSpecularImageBasedLightTextureOffset())
376         {
377           texture = mSpecularTexture;
378         }
379
380         newTextures.SetTexture(index, texture);
381         newTextures.SetSampler(index, textures.GetSampler(index));
382       }
383
384       mRenderer.SetTextures(newTextures);
385     }
386     mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), mIblScaleFactor);
387     mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightMaxLodUniformName().data(), static_cast<float>(mSpecularMipmapLevels));
388   }
389 }
390
391 void ModelPrimitive::UpdateRendererUniform()
392 {
393   mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), mIblScaleFactor);
394   mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightMaxLodUniformName().data(), static_cast<float>(mSpecularMipmapLevels));
395   GetImplementation(mMaterial).SetRendererUniform(mRenderer);
396 }
397
398 } // namespace Internal
399
400 } // namespace Scene3D
401
402 } // namespace Dali