be409da1e5f1381a6c1e981350d51553fff7052b
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / model3d-view / model3d-view-impl.cpp
1 /*
2  * Copyright (c) 2015 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/public-api/images/resource-image.h>
29 #include <dali/devel-api/adaptor-framework/file-loader.h>
30
31 // INTERNAL INCLUDES
32 #include <dali-toolkit/internal/controls/model3d-view/obj-loader.h>
33
34 namespace Dali
35 {
36
37 namespace Toolkit
38 {
39
40 namespace Internal
41 {
42
43 namespace
44 {
45
46 // Type registration
47 BaseHandle Create()
48 {
49   return Toolkit::Model3dView::New();
50 }
51
52 // Setup properties, signals and actions using the type-registry.
53 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Model3dView, Toolkit::Control, Create );
54
55 DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "geometryUrl",  STRING, GEOMETRY_URL)
56 DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "materialUrl",  STRING, MATERIAL_URL)
57 DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "imagesUrl",  STRING, IMAGES_URL)
58 DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "illuminationType",  INTEGER, ILLUMINATION_TYPE)
59 DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "texture0Url",  STRING, TEXTURE0_URL)
60 DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "texture1Url",  STRING, TEXTURE1_URL)
61 DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "texture2Url",  STRING, TEXTURE2_URL)
62
63 DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, Model3dView, "lightPosition",  VECTOR3, LIGHT_POSITION)
64
65 DALI_TYPE_REGISTRATION_END()
66
67
68 #define MAKE_SHADER(A)#A
69
70 //  Diffuse illumination shader
71
72 const char* SIMPLE_VERTEX_SHADER = MAKE_SHADER(
73   attribute highp vec3 aPosition;\n
74   attribute highp vec2 aTexCoord;\n
75   attribute highp vec3 aNormal;\n
76   varying mediump vec3 vIllumination;\n
77   uniform mediump vec3 uSize;\n
78   uniform mediump mat4 uMvpMatrix;\n
79   uniform mediump mat4 uModelView;\n
80   uniform mediump mat3 uNormalMatrix;
81   uniform mediump mat4 uObjectMatrix;\n
82   uniform mediump vec3 uLightPosition;\n
83
84   void main()\n
85   {\n
86     vec4 vertexPosition = vec4(aPosition*min(uSize.x, uSize.y), 1.0);\n
87     vertexPosition = uObjectMatrix * vertexPosition;\n
88     vertexPosition = uMvpMatrix * vertexPosition;\n
89
90     //Illumination in Model-View space - Transform attributes and uniforms\n
91     vec4 vertPos = uModelView * vec4(aPosition.xyz, 1.0);\n
92     vec3 normal = uNormalMatrix * aNormal;\n
93     vec4 lightPos = uModelView * vec4(uLightPosition, 1.0);\n
94     vec3 vecToLight = normalize( lightPos.xyz - vertPos.xyz );\n
95
96     float lightDiffuse = max( dot( vecToLight, normal ), 0.0 );\n
97     vIllumination = vec3(lightDiffuse * 0.5 + 0.5);\n
98
99     gl_Position = vertexPosition;\n
100   }\n
101 );
102
103 const char* SIMPLE_FRAGMENT_SHADER = MAKE_SHADER(
104   precision mediump float;\n
105   varying mediump vec3 vIllumination;\n
106   uniform lowp vec4 uColor;\n
107
108   void main()\n
109   {\n
110     gl_FragColor = vec4( vIllumination.rgb * uColor.rgb, uColor.a);\n
111   }\n
112 );
113
114 //  Diffuse and specular illumination shader with albedo texture
115
116 const char* VERTEX_SHADER = MAKE_SHADER(
117   attribute highp vec3 aPosition;\n
118   attribute highp vec2 aTexCoord;\n
119   attribute highp vec3 aNormal;\n
120   varying mediump vec2 vTexCoord;\n
121   varying mediump vec3 vIllumination;\n
122   varying mediump float vSpecular;\n
123   uniform mediump vec3 uSize;\n
124   uniform mediump mat4 uMvpMatrix;\n
125   uniform mediump mat4 uModelView;
126   uniform mediump mat3 uNormalMatrix;
127   uniform mediump mat4 uObjectMatrix;\n
128   uniform mediump vec3 uLightPosition;\n
129
130   void main()
131   {\n
132     vec4 vertexPosition = vec4(aPosition*min(uSize.x, uSize.y), 1.0);\n
133     vertexPosition = uObjectMatrix * vertexPosition;\n
134     vertexPosition = uMvpMatrix * vertexPosition;\n
135
136     //Illumination in Model-View space - Transform attributes and uniforms\n
137     vec4 vertPos = uModelView * vec4(aPosition.xyz, 1.0);\n
138     vec4 lightPos = uModelView * vec4(uLightPosition, 1.0);\n
139     vec3 normal = normalize(uNormalMatrix * aNormal);\n
140
141     vec3 vecToLight = normalize( lightPos.xyz - vertPos.xyz );\n
142     vec3 viewDir = normalize(-vertPos.xyz);
143
144     vec3 halfVector = normalize(viewDir + vecToLight);
145
146     float lightDiffuse = dot( vecToLight, normal );\n
147     lightDiffuse = max(0.0,lightDiffuse);\n
148     vIllumination = vec3(lightDiffuse * 0.5 + 0.5);\n
149
150     vec3 reflectDir = reflect(-vecToLight, normal);
151     vSpecular = pow( max(dot(reflectDir, viewDir), 0.0), 4.0 );
152
153     vTexCoord = aTexCoord;\n
154     gl_Position = vertexPosition;\n
155   }\n
156 );
157
158 const char* FRAGMENT_SHADER = MAKE_SHADER(
159   precision mediump float;\n
160   varying mediump vec2 vTexCoord;\n
161   varying mediump vec3 vIllumination;\n
162   varying mediump float vSpecular;\n
163   uniform sampler2D sDiffuse;\n
164   uniform lowp vec4 uColor;\n
165
166   void main()\n
167   {\n
168     vec4 texture = texture2D( sDiffuse, vTexCoord );\n
169     gl_FragColor = vec4( vIllumination.rgb * texture.rgb * uColor.rgb + vSpecular * 0.3, texture.a * uColor.a);\n
170   }\n
171 );
172
173 //  Diffuse and specular illumination shader with albedo texture, normal map and gloss map shader
174
175 const char* NRMMAP_VERTEX_SHADER = MAKE_SHADER(
176   attribute highp vec3 aPosition;\n
177   attribute highp vec2 aTexCoord;\n
178   attribute highp vec3 aNormal;\n
179   attribute highp vec3 aTangent;\n
180   attribute highp vec3 aBiNormal;\n
181   varying mediump vec2 vTexCoord;\n
182   varying mediump vec3 vLightDirection;\n
183   varying mediump vec3 vHalfVector;\n
184   uniform mediump vec3 uSize;\n
185   uniform mediump mat4 uMvpMatrix;\n
186   uniform mediump mat4 uModelView;
187   uniform mediump mat3 uNormalMatrix;
188   uniform mediump mat4 uObjectMatrix;\n
189   uniform mediump vec3 uLightPosition;\n
190
191   void main()
192   {\n
193     vec4 vertexPosition = vec4(aPosition*min(uSize.x, uSize.y), 1.0);\n
194     vertexPosition = uObjectMatrix * vertexPosition;\n
195     vertexPosition = uMvpMatrix * vertexPosition;\n
196
197     vec4 vertPos = uModelView * vec4(aPosition.xyz, 1.0);\n
198     vec4 lightPos = uModelView * vec4(uLightPosition, 1.0);\n
199
200     vec3 tangent = normalize(uNormalMatrix * aTangent);
201     vec3 binormal = normalize(uNormalMatrix * aBiNormal);
202     vec3 normal = normalize(uNormalMatrix * aNormal);
203
204     vec3 vecToLight = normalize( lightPos.xyz - vertPos.xyz );\n
205     vLightDirection.x = dot(vecToLight, tangent);
206     vLightDirection.y = dot(vecToLight, binormal);
207     vLightDirection.z = dot(vecToLight, normal);
208
209     vec3 viewDir = normalize(-vertPos.xyz);
210     vec3 halfVector = normalize(viewDir + vecToLight);
211     vHalfVector.x = dot(halfVector, tangent);
212     vHalfVector.y = dot(halfVector, binormal);
213     vHalfVector.z = dot(halfVector, normal);
214
215     vTexCoord = aTexCoord;\n
216     gl_Position = vertexPosition;\n
217   }\n
218 );
219
220 const char* NRMMAP_FRAGMENT_SHADER = MAKE_SHADER(
221   precision mediump float;\n
222   varying mediump vec2 vTexCoord;\n
223   varying mediump vec3 vLightDirection;\n
224   varying mediump vec3 vHalfVector;\n
225   uniform sampler2D sDiffuse;\n
226   uniform sampler2D sNormal;\n
227   uniform sampler2D sGloss;\n
228   uniform lowp vec4 uColor;\n
229
230   void main()\n
231   {\n
232     vec4 texture = texture2D( sDiffuse, vTexCoord );\n
233     vec3 normal = normalize( texture2D( sNormal, vTexCoord ).xyz * 2.0 - 1.0 );\n
234     vec4 glossMap = texture2D( sGloss, vTexCoord );\n
235
236     float lightDiffuse = max( 0.0, dot( normal, normalize(vLightDirection) ) );\n
237     lightDiffuse = lightDiffuse * 0.5 + 0.5;\n
238
239     float shininess = pow (max (dot (normalize( vHalfVector ), normal), 0.0), 16.0)  ;
240
241     gl_FragColor = vec4( texture.rgb * uColor.rgb * lightDiffuse + shininess * glossMap.rgb, texture.a * uColor.a);\n
242   }\n
243 );
244
245
246 } // anonymous namespace
247
248 using namespace Dali;
249
250 Model3dView::Model3dView()
251   : Control( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) )
252 {
253   mTexture0Url = "";
254   mTexture1Url = "";
255   mTexture2Url = "";
256
257   mIlluminationType = Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP;
258
259   mCameraFOV = Math::PI_OVER_180 * 45.f;
260
261   mControlSize = Vector2(100.,100.);
262 }
263
264 Model3dView::~Model3dView()
265 {
266 }
267
268 Toolkit::Model3dView Model3dView::New()
269 {
270   Model3dView* impl = new Model3dView();
271
272   Dali::Toolkit::Model3dView handle = Dali::Toolkit::Model3dView( *impl );
273
274   // Second-phase init of the implementation
275   // This can only be done after the CustomActor connection has been made...
276   impl->Initialize();
277
278   return handle;
279 }
280
281 void Model3dView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
282 {
283   Toolkit::Model3dView model3dView = Toolkit::Model3dView::DownCast( Dali::BaseHandle( object ) );
284
285   if( model3dView )
286   {
287     Model3dView& impl( GetImpl( model3dView ) );
288     switch( index )
289     {
290       case Toolkit::Model3dView::Property::GEOMETRY_URL:
291       {
292         if( value.Get(impl.mObjUrl) )
293         {
294           impl.LoadGeometry();
295           impl.CreateGeometry();
296         }
297         break;
298       }
299       case Toolkit::Model3dView::Property::MATERIAL_URL:
300       {
301         if( value.Get(impl.mTextureSetUrl) )
302         {
303           impl.LoadMaterial();
304           impl.CreateMaterial();
305         }
306         break;
307       }
308       case Toolkit::Model3dView::Property::IMAGES_URL:
309       {
310         if( value.Get(impl.mImagesUrl) )
311         {
312           impl.LoadTextures();
313         }
314         break;
315       }
316       case Toolkit::Model3dView::Property::ILLUMINATION_TYPE:
317       {
318         int illuminationType;
319         if( value.Get(illuminationType) )
320         {
321           impl.mIlluminationType = Toolkit::Model3dView::IlluminationType(illuminationType);
322           impl.CreateGeometry();
323           impl.CreateMaterial();
324           impl.LoadTextures();
325         }
326         break;
327       }
328       case Toolkit::Model3dView::Property::TEXTURE0_URL:
329       {
330         value.Get(impl.mTexture0Url);
331         break;
332       }
333       case Toolkit::Model3dView::Property::TEXTURE1_URL:
334       {
335         value.Get(impl.mTexture1Url);
336         break;
337       }
338       case Toolkit::Model3dView::Property::TEXTURE2_URL:
339       {
340         value.Get(impl.mTexture2Url);
341         break;
342       }
343     }
344   }
345 }
346
347 Property::Value Model3dView::GetProperty( BaseObject* object, Property::Index index )
348 {
349   Property::Value value;
350
351   Toolkit::Model3dView model3dView = Toolkit::Model3dView::DownCast( Dali::BaseHandle( object ) );
352
353   if( model3dView )
354   {
355     Model3dView& impl( GetImpl( model3dView ) );
356     switch( index )
357     {
358       case Toolkit::Model3dView::Property::GEOMETRY_URL:
359       {
360         value = impl.mObjUrl;
361         break;
362       }
363       case Toolkit::Model3dView::Property::MATERIAL_URL:
364       {
365         value = impl.mTextureSetUrl;
366         break;
367       }
368       case Toolkit::Model3dView::Property::IMAGES_URL:
369       {
370         value = impl.mImagesUrl;
371         break;
372       }
373       case Toolkit::Model3dView::Property::ILLUMINATION_TYPE:
374       {
375         value = int(impl.mIlluminationType);
376         break;
377       }
378       case Toolkit::Model3dView::Property::TEXTURE0_URL:
379       {
380         value = impl.mTexture0Url;
381         break;
382       }
383       case Toolkit::Model3dView::Property::TEXTURE1_URL:
384       {
385         value = impl.mTexture1Url;
386         break;
387       }
388       case Toolkit::Model3dView::Property::TEXTURE2_URL:
389       {
390         value = impl.mTexture2Url;
391         break;
392       }
393     }
394   }
395
396   return value;
397 }
398
399 /////////////////////////////////////////////////////////////
400
401
402 void Model3dView::OnStageConnection( int depth )
403 {
404   Control::OnStageConnection( depth );
405
406   CustomActor self = Self();
407   self.AddRenderer( mRenderer );
408
409   if( mObjLoader.IsSceneLoaded() )
410   {
411     mMesh = mObjLoader.CreateGeometry( mIlluminationType );
412
413     CreateMaterial();
414     LoadTextures();
415
416     mRenderer.SetGeometry( mMesh );
417
418     //create constraint for lightPosition Property with uLightPosition in the shader
419     Vector3 lightPosition( 0, 0, 0 );
420     Dali::Property::Index lightProperty = mShader.RegisterProperty( "uLightPosition", lightPosition );
421     Constraint constraint = Constraint::New<Vector3>( mShader, lightProperty, EqualToConstraint() );
422     constraint.AddSource( Source( self, Toolkit::Model3dView::Property::LIGHT_POSITION ) );
423     constraint.Apply();
424   }
425 }
426
427 ///////////////////////////////////////////////////////////
428 //
429 // Private methods
430 //
431
432 void Model3dView::OnInitialize()
433 {
434   //Create empty versions of the geometry and material so we always have a Renderer
435   Geometry mesh = Geometry::New();
436   Shader shader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER );
437   mRenderer = Renderer::New( mesh, shader );
438
439 }
440
441 void Model3dView::LoadGeometry()
442 {
443   //Load file in adaptor
444   std::streampos fileSize;
445   Dali::Vector<char> fileContent;
446
447   if (FileLoader::ReadFile(mObjUrl,fileSize,fileContent,FileLoader::TEXT))
448   {
449     mObjLoader.ClearArrays();
450
451     std::string materialUrl;
452     mObjLoader.Load(fileContent.Begin(), fileSize, materialUrl);
453
454     //Get size information from the obj loaded
455     mSceneCenter = mObjLoader.GetCenter();
456     mSceneSize = mObjLoader.GetSize();
457   }
458   else
459   {
460     //Error
461   }
462 }
463
464 void Model3dView::LoadMaterial()
465 {
466   //Load file in adaptor
467   std::streampos fileSize;
468   Dali::Vector<char> fileContent;
469
470   if( FileLoader::ReadFile(mTextureSetUrl, fileSize, fileContent, FileLoader::TEXT) )
471   {
472     mObjLoader.LoadMaterial(fileContent.Begin(), fileSize, mTexture0Url, mTexture1Url, mTexture2Url);
473   }
474   else
475   {
476     //Error
477   }
478 }
479
480 void Model3dView::Load()
481 {
482   LoadGeometry();
483   LoadMaterial();
484 }
485
486 void Model3dView::OnRelayout( const Vector2& size, RelayoutContainer& container )
487 {
488   UpdateView();
489 }
490
491 void Model3dView::UpdateView()
492 {
493   if( mObjLoader.IsSceneLoaded() )
494   {
495     //The object will always be centred
496
497     Matrix scaleMatrix;
498     scaleMatrix.SetIdentityAndScale(Vector3(1.0, -1.0, 1.0));
499
500     mShader.RegisterProperty( "uObjectMatrix", scaleMatrix );
501   }
502 }
503
504 void Model3dView::CreateGeometry()
505 {
506   if( mObjLoader.IsSceneLoaded() )
507   {
508     mMesh = mObjLoader.CreateGeometry( mIlluminationType );
509
510     if( mRenderer )
511     {
512       mRenderer.SetGeometry( mMesh );
513       mRenderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::ON );
514     }
515   }
516 }
517
518 void Model3dView::UpdateShaderUniforms()
519 {
520   if( mShader )
521   {
522     //Update shader related info, uniforms, etc. for the new shader
523     UpdateView();
524
525     Vector3 lightPosition( 0, 0, 0 );
526     Dali::Property::Index lightProperty = mShader.RegisterProperty( "uLightPosition", lightPosition );
527
528     CustomActor self = Self();
529
530     //create constraint for lightPosition Property with uLightPosition in the shader
531     if( lightProperty )
532     {
533       Constraint constraint = Constraint::New<Vector3>( mShader, lightProperty, EqualToConstraint() );
534       constraint.AddSource( Source( self, Toolkit::Model3dView::Property::LIGHT_POSITION ) );
535       constraint.Apply();
536     }
537   }
538 }
539
540 void Model3dView::CreateMaterial()
541 {
542   if( mObjLoader.IsMaterialLoaded() && (mTexture0Url != "") && mObjLoader.IsTexturePresent() )
543   {
544     if( (mTexture2Url != "") && (mTexture1Url != "") && (mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP) )
545     {
546       mShader = Shader::New( NRMMAP_VERTEX_SHADER, NRMMAP_FRAGMENT_SHADER );
547     }
548     else if( mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_TEXTURE ||
549              mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP )
550     {
551       mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
552     }
553     else
554     {
555       mShader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER );
556     }
557   }
558   else
559   {
560     mShader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER );
561   }
562
563   mTextureSet = TextureSet::New();
564
565   if( mRenderer )
566   {
567     mRenderer.SetTextures( mTextureSet );
568     mRenderer.SetShader( mShader );
569     mRenderer.SetProperty( Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK );
570   }
571
572   UpdateShaderUniforms();
573 }
574
575 void Model3dView::LoadTextures()
576 {
577   if( !mTextureSet )
578     return ;
579
580   if( (mTexture0Url != "") && (mIlluminationType != Toolkit::Model3dView::DIFFUSE) )
581   {
582     std::string imgUrl = mImagesUrl + mTexture0Url;
583
584     //Load textures
585     Image tex0 = ResourceImage::New( imgUrl );
586     if( tex0 )
587     {
588       mTextureSet.SetImage( 0u, tex0 );
589     }
590   }
591
592   if( (mTexture1Url != "") && (mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP) )
593   {
594     std::string imgUrl = mImagesUrl + mTexture1Url;
595
596     //Load textures
597     Image tex1 = ResourceImage::New( imgUrl );
598     if (tex1)
599     {
600       mTextureSet.SetImage( 1u, tex1 );
601     }
602   }
603
604   if( (mTexture2Url != "") && (mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP) )
605   {
606     std::string imgUrl = mImagesUrl + mTexture2Url;
607
608     //Load textures
609     Image tex2 = ResourceImage::New( imgUrl );
610     if( tex2 )
611     {
612       mTextureSet.SetImage( 2u, tex2 );
613     }
614   }
615 }
616
617 } // namespace Internal
618 } // namespace Toolkit
619 } // namespace Dali