[dali_2.2.4] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / model3d-view / model3d-view-impl.cpp
1 /*
2  * Copyright (c) 2021 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 "model3d-view-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali-toolkit/public-api/controls/model3d-view/model3d-view.h>
23 #include <dali/devel-api/adaptor-framework/file-loader.h>
24 #include <dali/devel-api/adaptor-framework/image-loading.h>
25 #include <dali/public-api/animation/constraint-source.h>
26 #include <dali/public-api/animation/constraint.h>
27 #include <dali/public-api/animation/constraints.h>
28 #include <dali/public-api/object/type-registry-helper.h>
29 #include <dali/public-api/object/type-registry.h>
30
31 // INTERNAL INCLUDES
32 #include <dali-toolkit/devel-api/controls/control-devel.h>
33 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
34 #include <dali-toolkit/internal/controls/model3d-view/obj-loader.h>
35 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
36
37 namespace Dali
38 {
39 namespace Toolkit
40 {
41 namespace Internal
42 {
43 namespace
44 {
45 // Texture indices are constants.
46 enum TextureIndex
47 {
48   DIFFUSE_TEXTURE_INDEX,
49   NORMAL_TEXTURE_INDEX,
50   GLOSS_TEXTURE_INDEX
51 };
52
53 /**
54  * @brief Loads a texture from a file.
55  * @param[in] imageUrl The URL of the file
56  * @return A texture if loading succeeds, an empty handle otherwise
57  */
58 Texture LoadTexture(const char* imageUrl)
59 {
60   Texture            texture;
61   Devel::PixelBuffer pixelBuffer = LoadImageFromFile(imageUrl);
62   if(pixelBuffer)
63   {
64     texture             = Texture::New(TextureType::TEXTURE_2D, pixelBuffer.GetPixelFormat(), pixelBuffer.GetWidth(), pixelBuffer.GetHeight());
65     PixelData pixelData = Devel::PixelBuffer::Convert(pixelBuffer);
66     texture.Upload(pixelData);
67     texture.GenerateMipmaps();
68   }
69
70   return texture;
71 }
72
73 // Type registration
74 BaseHandle Create()
75 {
76   return Toolkit::Model3dView::New();
77 }
78
79 // Setup properties, signals and actions using the type-registry.
80 DALI_TYPE_REGISTRATION_BEGIN(Toolkit::Model3dView, Toolkit::Control, Create);
81
82 DALI_PROPERTY_REGISTRATION(Toolkit, Model3dView, "geometryUrl", STRING, GEOMETRY_URL)
83 DALI_PROPERTY_REGISTRATION(Toolkit, Model3dView, "materialUrl", STRING, MATERIAL_URL)
84 DALI_PROPERTY_REGISTRATION(Toolkit, Model3dView, "imagesUrl", STRING, IMAGES_URL)
85 DALI_PROPERTY_REGISTRATION(Toolkit, Model3dView, "illuminationType", INTEGER, ILLUMINATION_TYPE)
86 DALI_PROPERTY_REGISTRATION(Toolkit, Model3dView, "texture0Url", STRING, TEXTURE0_URL)
87 DALI_PROPERTY_REGISTRATION(Toolkit, Model3dView, "texture1Url", STRING, TEXTURE1_URL)
88 DALI_PROPERTY_REGISTRATION(Toolkit, Model3dView, "texture2Url", STRING, TEXTURE2_URL)
89
90 DALI_ANIMATABLE_PROPERTY_REGISTRATION(Toolkit, Model3dView, "lightPosition", VECTOR3, LIGHT_POSITION)
91
92 DALI_TYPE_REGISTRATION_END()
93
94 } // anonymous namespace
95
96 using namespace Dali;
97
98 Model3dView::Model3dView()
99 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT))
100 {
101   mIlluminationType = Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP;
102
103   mCameraFOV = Math::PI_OVER_180 * 45.f;
104
105   mControlSize = Vector2(100., 100.);
106 }
107
108 Model3dView::~Model3dView()
109 {
110 }
111
112 Toolkit::Model3dView Model3dView::New()
113 {
114   Model3dView* impl = new Model3dView();
115
116   Dali::Toolkit::Model3dView handle = Dali::Toolkit::Model3dView(*impl);
117
118   // Second-phase init of the implementation
119   // This can only be done after the CustomActor connection has been made...
120   impl->Initialize();
121
122   return handle;
123 }
124
125 void Model3dView::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
126 {
127   Toolkit::Model3dView model3dView = Toolkit::Model3dView::DownCast(Dali::BaseHandle(object));
128
129   if(model3dView)
130   {
131     Model3dView& impl(GetImpl(model3dView));
132     switch(index)
133     {
134       case Toolkit::Model3dView::Property::GEOMETRY_URL:
135       {
136         if(value.Get(impl.mObjUrl))
137         {
138           impl.LoadGeometry();
139           impl.CreateGeometry();
140         }
141         break;
142       }
143       case Toolkit::Model3dView::Property::MATERIAL_URL:
144       {
145         if(value.Get(impl.mTextureSetUrl))
146         {
147           impl.LoadMaterial();
148           impl.CreateMaterial();
149           impl.LoadTextures();
150         }
151         break;
152       }
153       case Toolkit::Model3dView::Property::IMAGES_URL:
154       {
155         if(value.Get(impl.mImagesUrl))
156         {
157           impl.LoadTextures();
158         }
159         break;
160       }
161       case Toolkit::Model3dView::Property::ILLUMINATION_TYPE:
162       {
163         int illuminationType;
164         if(value.Get(illuminationType))
165         {
166           impl.mIlluminationType = Toolkit::Model3dView::IlluminationType(illuminationType);
167           impl.CreateGeometry();
168           impl.CreateMaterial();
169           impl.LoadTextures();
170         }
171         break;
172       }
173       case Toolkit::Model3dView::Property::TEXTURE0_URL:
174       {
175         value.Get(impl.mTexture0Url);
176         break;
177       }
178       case Toolkit::Model3dView::Property::TEXTURE1_URL:
179       {
180         value.Get(impl.mTexture1Url);
181         break;
182       }
183       case Toolkit::Model3dView::Property::TEXTURE2_URL:
184       {
185         value.Get(impl.mTexture2Url);
186         break;
187       }
188     }
189   }
190 }
191
192 Property::Value Model3dView::GetProperty(BaseObject* object, Property::Index index)
193 {
194   Property::Value value;
195
196   Toolkit::Model3dView model3dView = Toolkit::Model3dView::DownCast(Dali::BaseHandle(object));
197
198   if(model3dView)
199   {
200     Model3dView& impl(GetImpl(model3dView));
201     switch(index)
202     {
203       case Toolkit::Model3dView::Property::GEOMETRY_URL:
204       {
205         value = impl.mObjUrl;
206         break;
207       }
208       case Toolkit::Model3dView::Property::MATERIAL_URL:
209       {
210         value = impl.mTextureSetUrl;
211         break;
212       }
213       case Toolkit::Model3dView::Property::IMAGES_URL:
214       {
215         value = impl.mImagesUrl;
216         break;
217       }
218       case Toolkit::Model3dView::Property::ILLUMINATION_TYPE:
219       {
220         value = int(impl.mIlluminationType);
221         break;
222       }
223       case Toolkit::Model3dView::Property::TEXTURE0_URL:
224       {
225         value = impl.mTexture0Url;
226         break;
227       }
228       case Toolkit::Model3dView::Property::TEXTURE1_URL:
229       {
230         value = impl.mTexture1Url;
231         break;
232       }
233       case Toolkit::Model3dView::Property::TEXTURE2_URL:
234       {
235         value = impl.mTexture2Url;
236         break;
237       }
238     }
239   }
240
241   return value;
242 }
243
244 /////////////////////////////////////////////////////////////
245
246 void Model3dView::OnSceneConnection(int depth)
247 {
248   CustomActor self = Self();
249   self.AddRenderer(mRenderer);
250
251   if(mObjLoader.IsSceneLoaded())
252   {
253     mMesh = mObjLoader.CreateGeometry(GetShaderProperties(mIlluminationType), true);
254
255     CreateMaterial();
256     LoadTextures();
257
258     mRenderer.SetGeometry(mMesh);
259
260     //create constraint for lightPosition Property with uLightPosition in the shader
261     Vector3               lightPosition(0, 0, 0);
262     Dali::Property::Index lightProperty = mShader.RegisterProperty("uLightPosition", lightPosition);
263     Constraint            constraint    = Constraint::New<Vector3>(mShader, lightProperty, EqualToConstraint());
264     constraint.AddSource(Source(self, Toolkit::Model3dView::Property::LIGHT_POSITION));
265     constraint.Apply();
266   }
267
268   Control::OnSceneConnection(depth);
269 }
270
271 ///////////////////////////////////////////////////////////
272 //
273 // Private methods
274 //
275
276 void Model3dView::OnInitialize()
277 {
278   //Create empty versions of the geometry and material so we always have a Renderer
279   Geometry mesh   = Geometry::New();
280   Shader   shader = Shader::New(SHADER_MODEL3D_VIEW_SIMPLE_SHADER_VERT, SHADER_MODEL3D_VIEW_SIMPLE_SHADER_FRAG);
281   mRenderer       = Renderer::New(mesh, shader);
282
283   Self().SetProperty(DevelControl::Property::ACCESSIBILITY_ROLE, Dali::Accessibility::Role::IMAGE);
284 }
285
286 void Model3dView::LoadGeometry()
287 {
288   //Load file in adaptor
289   std::streampos     fileSize;
290   Dali::Vector<char> fileContent;
291
292   if(FileLoader::ReadFile(mObjUrl, fileSize, fileContent, FileLoader::TEXT))
293   {
294     mObjLoader.ClearArrays();
295     mObjLoader.LoadObject(fileContent.Begin(), fileSize);
296
297     //Get size information from the obj loaded
298     mSceneCenter = mObjLoader.GetCenter();
299     mSceneSize   = mObjLoader.GetSize();
300   }
301   else
302   {
303     //Error
304   }
305 }
306
307 void Model3dView::LoadMaterial()
308 {
309   //Load file in adaptor
310   std::streampos     fileSize;
311   Dali::Vector<char> fileContent;
312
313   if(FileLoader::ReadFile(mTextureSetUrl, fileSize, fileContent, FileLoader::TEXT))
314   {
315     mObjLoader.LoadMaterial(fileContent.Begin(), fileSize, mTexture0Url, mTexture1Url, mTexture2Url);
316   }
317   else
318   {
319     //Error
320   }
321 }
322
323 void Model3dView::Load()
324 {
325   LoadGeometry();
326   LoadMaterial();
327 }
328
329 void Model3dView::OnRelayout(const Vector2& size, RelayoutContainer& container)
330 {
331   UpdateView();
332 }
333
334 void Model3dView::UpdateView()
335 {
336   if(mObjLoader.IsSceneLoaded())
337   {
338     //The object will always be centred
339
340     Matrix scaleMatrix;
341     scaleMatrix.SetIdentityAndScale(Vector3(1.0, -1.0, 1.0));
342
343     mShader.RegisterProperty("uObjectMatrix", scaleMatrix);
344   }
345 }
346
347 void Model3dView::CreateGeometry()
348 {
349   if(mObjLoader.IsSceneLoaded())
350   {
351     mMesh = mObjLoader.CreateGeometry(GetShaderProperties(mIlluminationType), true);
352
353     if(mRenderer)
354     {
355       mRenderer.SetGeometry(mMesh);
356       mRenderer.SetProperty(Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::ON);
357       mRenderer.SetProperty(Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON);
358     }
359   }
360 }
361
362 void Model3dView::UpdateShaderUniforms()
363 {
364   if(mShader)
365   {
366     //Update shader related info, uniforms, etc. for the new shader
367     UpdateView();
368
369     Vector3               lightPosition(0, 0, 0);
370     Dali::Property::Index lightProperty = mShader.RegisterProperty("uLightPosition", lightPosition);
371
372     CustomActor self = Self();
373
374     //create constraint for lightPosition Property with uLightPosition in the shader
375     if(lightProperty)
376     {
377       Constraint constraint = Constraint::New<Vector3>(mShader, lightProperty, EqualToConstraint());
378       constraint.AddSource(Source(self, Toolkit::Model3dView::Property::LIGHT_POSITION));
379       constraint.Apply();
380     }
381   }
382 }
383
384 void Model3dView::CreateMaterial()
385 {
386   if(mObjLoader.IsMaterialLoaded() && (mTexture0Url != "") && mObjLoader.IsTexturePresent())
387   {
388     if((mTexture2Url != "") && (mTexture1Url != "") && (mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP))
389     {
390       mShader = Shader::New(SHADER_MODEL3D_VIEW_NRMMAP_SHADER_VERT, SHADER_MODEL3D_VIEW_NRMMAP_SHADER_FRAG);
391     }
392     else if(mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_TEXTURE ||
393             mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP)
394     {
395       mShader = Shader::New(SHADER_MODEL3D_VIEW_SHADER_VERT, SHADER_MODEL3D_VIEW_SHADER_FRAG);
396     }
397     else
398     {
399       mShader = Shader::New(SHADER_MODEL3D_VIEW_SIMPLE_SHADER_VERT, SHADER_MODEL3D_VIEW_SIMPLE_SHADER_FRAG);
400     }
401   }
402   else
403   {
404     mShader = Shader::New(SHADER_MODEL3D_VIEW_SIMPLE_SHADER_VERT, SHADER_MODEL3D_VIEW_SIMPLE_SHADER_FRAG);
405   }
406
407   mTextureSet = TextureSet::New();
408
409   if(mRenderer)
410   {
411     mRenderer.SetTextures(mTextureSet);
412     mRenderer.SetShader(mShader);
413     mRenderer.SetProperty(Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK);
414   }
415
416   UpdateShaderUniforms();
417 }
418
419 void Model3dView::LoadTextures()
420 {
421   if(!mTextureSet)
422   {
423     return;
424   }
425
426   Sampler sampler = Sampler::New();
427   sampler.SetFilterMode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR_MIPMAP_LINEAR);
428
429   // Setup diffuse texture.
430   if(!mTexture0Url.empty() && (mIlluminationType != Toolkit::Model3dView::DIFFUSE))
431   {
432     std::string imageUrl = mImagesUrl + mTexture0Url;
433
434     //Load textures
435     Texture diffuseTexture = LoadTexture(imageUrl.c_str());
436     if(diffuseTexture)
437     {
438       mTextureSet.SetTexture(DIFFUSE_TEXTURE_INDEX, diffuseTexture);
439       mTextureSet.SetSampler(DIFFUSE_TEXTURE_INDEX, sampler);
440     }
441   }
442
443   if(mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP)
444   {
445     // Setup normal map texture.
446     if(!mTexture1Url.empty())
447     {
448       std::string imageUrl = mImagesUrl + mTexture1Url;
449
450       //Load textures
451       Texture normalTexture = LoadTexture(imageUrl.c_str());
452       if(normalTexture)
453       {
454         mTextureSet.SetTexture(NORMAL_TEXTURE_INDEX, normalTexture);
455         mTextureSet.SetSampler(NORMAL_TEXTURE_INDEX, sampler);
456       }
457     }
458     if(!mTexture2Url.empty())
459     {
460       // Setup gloss map texture.
461       std::string imageUrl = mImagesUrl + mTexture2Url;
462
463       //Load textures
464       Texture glossTexture = LoadTexture(imageUrl.c_str());
465       if(glossTexture)
466       {
467         mTextureSet.SetTexture(GLOSS_TEXTURE_INDEX, glossTexture);
468         mTextureSet.SetSampler(GLOSS_TEXTURE_INDEX, sampler);
469       }
470     }
471   }
472 }
473
474 int Model3dView::GetShaderProperties(Toolkit::Model3dView::IlluminationType illuminationType)
475 {
476   int objectProperties = 0;
477
478   if(illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_TEXTURE ||
479      illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP)
480   {
481     objectProperties |= ObjLoader::TEXTURE_COORDINATES;
482   }
483
484   if(illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP)
485   {
486     objectProperties |= ObjLoader::TANGENTS | ObjLoader::BINORMALS;
487   }
488
489   return objectProperties;
490 }
491
492 } // namespace Internal
493 } // namespace Toolkit
494 } // namespace Dali