[AT-SPI] Require ControlAccessible for Control
[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   DevelControl::SetAccessibilityConstructor(Self(), [](Dali::Actor actor) {
284     return std::make_unique<DevelControl::ControlAccessible>(actor, Dali::Accessibility::Role::IMAGE);
285   });
286 }
287
288 void Model3dView::LoadGeometry()
289 {
290   //Load file in adaptor
291   std::streampos     fileSize;
292   Dali::Vector<char> fileContent;
293
294   if(FileLoader::ReadFile(mObjUrl, fileSize, fileContent, FileLoader::TEXT))
295   {
296     mObjLoader.ClearArrays();
297     mObjLoader.LoadObject(fileContent.Begin(), fileSize);
298
299     //Get size information from the obj loaded
300     mSceneCenter = mObjLoader.GetCenter();
301     mSceneSize   = mObjLoader.GetSize();
302   }
303   else
304   {
305     //Error
306   }
307 }
308
309 void Model3dView::LoadMaterial()
310 {
311   //Load file in adaptor
312   std::streampos     fileSize;
313   Dali::Vector<char> fileContent;
314
315   if(FileLoader::ReadFile(mTextureSetUrl, fileSize, fileContent, FileLoader::TEXT))
316   {
317     mObjLoader.LoadMaterial(fileContent.Begin(), fileSize, mTexture0Url, mTexture1Url, mTexture2Url);
318   }
319   else
320   {
321     //Error
322   }
323 }
324
325 void Model3dView::Load()
326 {
327   LoadGeometry();
328   LoadMaterial();
329 }
330
331 void Model3dView::OnRelayout(const Vector2& size, RelayoutContainer& container)
332 {
333   UpdateView();
334 }
335
336 void Model3dView::UpdateView()
337 {
338   if(mObjLoader.IsSceneLoaded())
339   {
340     //The object will always be centred
341
342     Matrix scaleMatrix;
343     scaleMatrix.SetIdentityAndScale(Vector3(1.0, -1.0, 1.0));
344
345     mShader.RegisterProperty("uObjectMatrix", scaleMatrix);
346   }
347 }
348
349 void Model3dView::CreateGeometry()
350 {
351   if(mObjLoader.IsSceneLoaded())
352   {
353     mMesh = mObjLoader.CreateGeometry(GetShaderProperties(mIlluminationType), true);
354
355     if(mRenderer)
356     {
357       mRenderer.SetGeometry(mMesh);
358       mRenderer.SetProperty(Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::ON);
359       mRenderer.SetProperty(Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON);
360     }
361   }
362 }
363
364 void Model3dView::UpdateShaderUniforms()
365 {
366   if(mShader)
367   {
368     //Update shader related info, uniforms, etc. for the new shader
369     UpdateView();
370
371     Vector3               lightPosition(0, 0, 0);
372     Dali::Property::Index lightProperty = mShader.RegisterProperty("uLightPosition", lightPosition);
373
374     CustomActor self = Self();
375
376     //create constraint for lightPosition Property with uLightPosition in the shader
377     if(lightProperty)
378     {
379       Constraint constraint = Constraint::New<Vector3>(mShader, lightProperty, EqualToConstraint());
380       constraint.AddSource(Source(self, Toolkit::Model3dView::Property::LIGHT_POSITION));
381       constraint.Apply();
382     }
383   }
384 }
385
386 void Model3dView::CreateMaterial()
387 {
388   if(mObjLoader.IsMaterialLoaded() && (mTexture0Url != "") && mObjLoader.IsTexturePresent())
389   {
390     if((mTexture2Url != "") && (mTexture1Url != "") && (mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP))
391     {
392       mShader = Shader::New(SHADER_MODEL3D_VIEW_NRMMAP_SHADER_VERT, SHADER_MODEL3D_VIEW_NRMMAP_SHADER_FRAG);
393     }
394     else if(mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_TEXTURE ||
395             mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP)
396     {
397       mShader = Shader::New(SHADER_MODEL3D_VIEW_SHADER_VERT, SHADER_MODEL3D_VIEW_SHADER_FRAG);
398     }
399     else
400     {
401       mShader = Shader::New(SHADER_MODEL3D_VIEW_SIMPLE_SHADER_VERT, SHADER_MODEL3D_VIEW_SIMPLE_SHADER_FRAG);
402     }
403   }
404   else
405   {
406     mShader = Shader::New(SHADER_MODEL3D_VIEW_SIMPLE_SHADER_VERT, SHADER_MODEL3D_VIEW_SIMPLE_SHADER_FRAG);
407   }
408
409   mTextureSet = TextureSet::New();
410
411   if(mRenderer)
412   {
413     mRenderer.SetTextures(mTextureSet);
414     mRenderer.SetShader(mShader);
415     mRenderer.SetProperty(Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK);
416   }
417
418   UpdateShaderUniforms();
419 }
420
421 void Model3dView::LoadTextures()
422 {
423   if(!mTextureSet)
424   {
425     return;
426   }
427
428   Sampler sampler = Sampler::New();
429   sampler.SetFilterMode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR_MIPMAP_LINEAR);
430
431   // Setup diffuse texture.
432   if(!mTexture0Url.empty() && (mIlluminationType != Toolkit::Model3dView::DIFFUSE))
433   {
434     std::string imageUrl = mImagesUrl + mTexture0Url;
435
436     //Load textures
437     Texture diffuseTexture = LoadTexture(imageUrl.c_str());
438     if(diffuseTexture)
439     {
440       mTextureSet.SetTexture(DIFFUSE_TEXTURE_INDEX, diffuseTexture);
441       mTextureSet.SetSampler(DIFFUSE_TEXTURE_INDEX, sampler);
442     }
443   }
444
445   if(mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP)
446   {
447     // Setup normal map texture.
448     if(!mTexture1Url.empty())
449     {
450       std::string imageUrl = mImagesUrl + mTexture1Url;
451
452       //Load textures
453       Texture normalTexture = LoadTexture(imageUrl.c_str());
454       if(normalTexture)
455       {
456         mTextureSet.SetTexture(NORMAL_TEXTURE_INDEX, normalTexture);
457         mTextureSet.SetSampler(NORMAL_TEXTURE_INDEX, sampler);
458       }
459     }
460     if(!mTexture2Url.empty())
461     {
462       // Setup gloss map texture.
463       std::string imageUrl = mImagesUrl + mTexture2Url;
464
465       //Load textures
466       Texture glossTexture = LoadTexture(imageUrl.c_str());
467       if(glossTexture)
468       {
469         mTextureSet.SetTexture(GLOSS_TEXTURE_INDEX, glossTexture);
470         mTextureSet.SetSampler(GLOSS_TEXTURE_INDEX, sampler);
471       }
472     }
473   }
474 }
475
476 int Model3dView::GetShaderProperties(Toolkit::Model3dView::IlluminationType illuminationType)
477 {
478   int objectProperties = 0;
479
480   if(illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_TEXTURE ||
481      illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP)
482   {
483     objectProperties |= ObjLoader::TEXTURE_COORDINATES;
484   }
485
486   if(illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP)
487   {
488     objectProperties |= ObjLoader::TANGENTS | ObjLoader::BINORMALS;
489   }
490
491   return objectProperties;
492 }
493
494 } // namespace Internal
495 } // namespace Toolkit
496 } // namespace Dali