Merge "Fixed bug in SetIndexBuffer for v8 plugin" into devel/master
[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/devel-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 void LookAt(Matrix& result, const Vector3& eye, const Vector3& target, const Vector3& up)
251 {
252   Vector3 vZ = target - eye;
253   vZ.Normalize();
254
255   Vector3 vX = up.Cross(vZ);
256   vX.Normalize();
257
258   Vector3 vY = vZ.Cross(vX);
259   vY.Normalize();
260
261   result.SetInverseTransformComponents(vX, vY, vZ, eye);
262 }
263
264
265 Model3dView::Model3dView()
266   : Control( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) )
267 {
268   mTexture0Url = "";
269   mTexture1Url = "";
270   mTexture2Url = "";
271
272   mIlluminationType = Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP;
273
274   mCameraFOV = Math::PI_OVER_180 * 45.f;
275
276   mControlSize = Vector2(100.,100.);
277 }
278
279 Model3dView::~Model3dView()
280 {
281 }
282
283 Toolkit::Model3dView Model3dView::New()
284 {
285   Model3dView* impl = new Model3dView();
286
287   Dali::Toolkit::Model3dView handle = Dali::Toolkit::Model3dView( *impl );
288
289   // Second-phase init of the implementation
290   // This can only be done after the CustomActor connection has been made...
291   impl->Initialize();
292
293   return handle;
294 }
295
296 void Model3dView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
297 {
298   Toolkit::Model3dView model3dView = Toolkit::Model3dView::DownCast( Dali::BaseHandle( object ) );
299
300   if( model3dView )
301   {
302     Model3dView& impl( GetImpl( model3dView ) );
303     switch( index )
304     {
305       case Toolkit::Model3dView::Property::GEOMETRY_URL:
306       {
307         if( value.Get(impl.mObjUrl) )
308         {
309           impl.LoadGeometry();
310           impl.CreateGeometry();
311         }
312         break;
313       }
314       case Toolkit::Model3dView::Property::MATERIAL_URL:
315       {
316         if( value.Get(impl.mTextureSetUrl) )
317         {
318           impl.LoadMaterial();
319           impl.CreateMaterial();
320         }
321         break;
322       }
323       case Toolkit::Model3dView::Property::IMAGES_URL:
324       {
325         if( value.Get(impl.mImagesUrl) )
326         {
327           impl.LoadTextures();
328         }
329         break;
330       }
331       case Toolkit::Model3dView::Property::ILLUMINATION_TYPE:
332       {
333         int illuminationType;
334         if( value.Get(illuminationType) )
335         {
336           impl.mIlluminationType = Toolkit::Model3dView::IlluminationType(illuminationType);
337           impl.CreateGeometry();
338           impl.CreateMaterial();
339           impl.LoadTextures();
340         }
341         break;
342       }
343       case Toolkit::Model3dView::Property::TEXTURE0_URL:
344       {
345         value.Get(impl.mTexture0Url);
346         break;
347       }
348       case Toolkit::Model3dView::Property::TEXTURE1_URL:
349       {
350         value.Get(impl.mTexture1Url);
351         break;
352       }
353       case Toolkit::Model3dView::Property::TEXTURE2_URL:
354       {
355         value.Get(impl.mTexture2Url);
356         break;
357       }
358     }
359   }
360 }
361
362 Property::Value Model3dView::GetProperty( BaseObject* object, Property::Index index )
363 {
364   Property::Value value;
365
366   Toolkit::Model3dView model3dView = Toolkit::Model3dView::DownCast( Dali::BaseHandle( object ) );
367
368   if( model3dView )
369   {
370     Model3dView& impl( GetImpl( model3dView ) );
371     switch( index )
372     {
373       case Toolkit::Model3dView::Property::GEOMETRY_URL:
374       {
375         value = impl.mObjUrl;
376         break;
377       }
378       case Toolkit::Model3dView::Property::MATERIAL_URL:
379       {
380         value = impl.mTextureSetUrl;
381         break;
382       }
383       case Toolkit::Model3dView::Property::IMAGES_URL:
384       {
385         value = impl.mImagesUrl;
386         break;
387       }
388       case Toolkit::Model3dView::Property::ILLUMINATION_TYPE:
389       {
390         value = int(impl.mIlluminationType);
391         break;
392       }
393       case Toolkit::Model3dView::Property::TEXTURE0_URL:
394       {
395         value = impl.mTexture0Url;
396         break;
397       }
398       case Toolkit::Model3dView::Property::TEXTURE1_URL:
399       {
400         value = impl.mTexture1Url;
401         break;
402       }
403       case Toolkit::Model3dView::Property::TEXTURE2_URL:
404       {
405         value = impl.mTexture2Url;
406         break;
407       }
408     }
409   }
410
411   return value;
412 }
413
414 /////////////////////////////////////////////////////////////
415
416
417 void Model3dView::OnStageConnection( int depth )
418 {
419   Control::OnStageConnection( depth );
420
421   CustomActor self = Self();
422   self.AddRenderer( mRenderer );
423
424   if( mObjLoader.IsSceneLoaded() )
425   {
426     mMesh = mObjLoader.CreateGeometry(mIlluminationType);
427
428     CreateMaterial();
429     LoadTextures();
430
431     mRenderer.SetGeometry( mMesh );
432
433     //create constraint for lightPosition Property with uLightPosition in the shader
434     Vector3 lightPosition( 0, 0, 0 );
435     Dali::Property::Index lightProperty = mShader.RegisterProperty( "uLightPosition", lightPosition );
436     Constraint constraint = Constraint::New<Vector3>( mShader, lightProperty, EqualToConstraint() );
437     constraint.AddSource( Source( self, Toolkit::Model3dView::Property::LIGHT_POSITION ) );
438     constraint.Apply();
439   }
440 }
441
442 ///////////////////////////////////////////////////////////
443 //
444 // Private methods
445 //
446
447 void Model3dView::OnInitialize()
448 {
449   //Create empty versions of the geometry and material so we always have a Renderer
450   Geometry mesh = Geometry::New();
451   Shader shader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER );
452   mRenderer = Renderer::New( mesh, shader );
453
454 }
455
456 void Model3dView::LoadGeometry()
457 {
458   //Load file in adaptor
459   std::streampos fileSize;
460   Dali::Vector<char> fileContent;
461
462   if (FileLoader::ReadFile(mObjUrl,fileSize,fileContent,FileLoader::TEXT))
463   {
464     mObjLoader.ClearArrays();
465
466     std::string materialUrl;
467     mObjLoader.Load(fileContent.Begin(), fileSize, materialUrl);
468
469     //Get size information from the obj loaded
470     mSceneCenter = mObjLoader.GetCenter();
471     mSceneSize = mObjLoader.GetSize();
472   }
473   else
474   {
475     //Error
476   }
477 }
478
479 void Model3dView::LoadMaterial()
480 {
481   //Load file in adaptor
482   std::streampos fileSize;
483   Dali::Vector<char> fileContent;
484
485   if( FileLoader::ReadFile(mTextureSetUrl, fileSize, fileContent, FileLoader::TEXT) )
486   {
487     mObjLoader.LoadMaterial(fileContent.Begin(), fileSize, mTexture0Url, mTexture1Url, mTexture2Url);
488   }
489   else
490   {
491     //Error
492   }
493 }
494
495 void Model3dView::Load()
496 {
497   LoadGeometry();
498   LoadMaterial();
499 }
500
501 void Model3dView::OnRelayout( const Vector2& size, RelayoutContainer& container )
502 {
503   UpdateView();
504 }
505
506 void Model3dView::UpdateView()
507 {
508   if( mObjLoader.IsSceneLoaded() )
509   {
510     //The object will always be centred
511
512     Matrix scaleMatrix;
513     scaleMatrix.SetIdentityAndScale(Vector3(1.0, -1.0, 1.0));
514
515     mShader.RegisterProperty( "uObjectMatrix", scaleMatrix );
516   }
517 }
518
519 void Model3dView::CreateGeometry()
520 {
521   if( mObjLoader.IsSceneLoaded() )
522   {
523     mMesh = mObjLoader.CreateGeometry(mIlluminationType);
524
525     if( mRenderer )
526     {
527       mRenderer.SetGeometry( mMesh );
528       mRenderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, Renderer::DEPTH_WRITE_ON );
529     }
530   }
531 }
532
533 void Model3dView::UpdateShaderUniforms()
534 {
535   if( mShader )
536   {
537     //Update shader related info, uniforms, etc. for the new shader
538     UpdateView();
539
540     Vector3 lightPosition( 0, 0, 0 );
541     Dali::Property::Index lightProperty = mShader.RegisterProperty( "uLightPosition", lightPosition );
542
543     CustomActor self = Self();
544
545     //create constraint for lightPosition Property with uLightPosition in the shader
546     if( lightProperty )
547     {
548       Constraint constraint = Constraint::New<Vector3>( mShader, lightProperty, EqualToConstraint() );
549       constraint.AddSource( Source( self, Toolkit::Model3dView::Property::LIGHT_POSITION ) );
550       constraint.Apply();
551     }
552   }
553 }
554
555 void Model3dView::CreateMaterial()
556 {
557   if( mObjLoader.IsMaterialLoaded() && (mTexture0Url != "") && mObjLoader.IsTexturePresent() )
558   {
559     if( (mTexture2Url != "") && (mTexture1Url != "") && (mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP) && mObjLoader.IsNormalMapPresent() )
560     {
561       mShader = Shader::New( NRMMAP_VERTEX_SHADER, NRMMAP_FRAGMENT_SHADER );
562     }
563     else if( mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_TEXTURE )
564     {
565       mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
566     }
567     else
568     {
569       mShader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER );
570     }
571   }
572   else
573   {
574     mShader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER );
575   }
576
577   mTextureSet = TextureSet::New();
578
579   if( mRenderer )
580   {
581     mRenderer.SetTextures( mTextureSet );
582     mRenderer.SetShader( mShader );
583     mRenderer.SetProperty( Renderer::Property::FACE_CULLING_MODE, Renderer::CULL_NONE);
584   }
585
586   UpdateShaderUniforms();
587 }
588
589 void Model3dView::LoadTextures()
590 {
591   if( !mTextureSet )
592     return ;
593
594   if( mTexture0Url != "" )
595   {
596     std::string imgUrl = mImagesUrl + mTexture0Url;
597
598     //Load textures
599     Image tex0 = ResourceImage::New( imgUrl );
600     if( tex0 )
601     {
602       mTextureSet.SetImage( 0u, tex0 );
603     }
604   }
605
606   if( (mTexture1Url != "") && (mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP) )
607   {
608     std::string imgUrl = mImagesUrl + mTexture1Url;
609
610     //Load textures
611     Image tex1 = ResourceImage::New( imgUrl );
612     if (tex1)
613     {
614       mTextureSet.SetImage( 1u, tex1 );
615     }
616   }
617
618   if( (mTexture2Url != "") && (mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP) )
619   {
620     std::string imgUrl = mImagesUrl + mTexture2Url;
621
622     //Load textures
623     Image tex2 = ResourceImage::New( imgUrl );
624     if( tex2 )
625     {
626       mTextureSet.SetImage( 2u, tex2 );
627     }
628   }
629 }
630
631 } // namespace Internal
632 } // namespace Toolkit
633 } // namespace Dali