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