8b3256de33cc71525023ca8e8f6f3bd91dedd4b4
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / renderers / mesh / mesh-renderer.cpp
1 /*
2  * Copyright (c) 2016 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 "mesh-renderer.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <dali/public-api/images/resource-image.h>
24 #include <dali/public-api/common/stage.h>
25 #include <dali/devel-api/adaptor-framework/file-loader.h>
26 #include <fstream>
27
28 //INTERNAL INCLUDES
29 #include <dali-toolkit/internal/controls/renderers/renderer-string-constants.h>
30 #include <dali-toolkit/internal/controls/renderers/renderer-factory-impl.h>
31 #include <dali-toolkit/internal/controls/renderers/renderer-factory-cache.h>
32 #include <dali-toolkit/internal/controls/renderers/control-renderer-data-impl.h>
33
34 namespace Dali
35 {
36
37 namespace Toolkit
38 {
39
40 namespace Internal
41 {
42
43 namespace
44 {
45
46 //Defines ordering of textures for shaders.
47 //All shaders, if including certain texture types, must include them in the same order.
48 //Within the texture set for the renderer, textures are ordered in the same manner.
49 enum TextureIndex
50 {
51   DIFFUSE_INDEX = 0u,
52   NORMAL_INDEX = 1u,
53   GLOSS_INDEX = 2u
54 };
55
56 const char * const RENDERER_TYPE_VALUE( "mesh" ); //String label for which type of control renderer this is.
57 const char * const LIGHT_POSITION( "uLightPosition" ); //Shader property
58 const char * const OBJECT_MATRIX( "uObjectMatrix" ); //Shader property
59
60 //Shaders
61 //If a shader requires certain textures, they must be listed in order,
62 //as detailed in the TextureIndex enum documentation.
63
64 //A basic shader that doesn't use textures at all.
65 const char* SIMPLE_VERTEX_SHADER = DALI_COMPOSE_SHADER(
66   attribute highp vec3 aPosition;\n
67   attribute highp vec3 aNormal;\n
68   varying mediump vec3 vIllumination;\n
69   uniform mediump vec3 uSize;\n
70   uniform mediump mat4 uMvpMatrix;\n
71   uniform mediump mat4 uModelView;\n
72   uniform mediump mat3 uNormalMatrix;
73   uniform mediump mat4 uObjectMatrix;\n
74   uniform mediump vec3 uLightPosition;\n
75
76   void main()\n
77   {\n
78     vec4 vertexPosition = vec4( aPosition * min( uSize.x, uSize.y ), 1.0 );\n
79     vertexPosition = uObjectMatrix * vertexPosition;\n
80     vertexPosition = uMvpMatrix * vertexPosition;\n
81
82     //Illumination in Model-View space - Transform attributes and uniforms\n
83     vec4 vertPos = uModelView * vec4( aPosition.xyz, 1.0 );\n
84     vec3 normal = uNormalMatrix * mat3( uObjectMatrix ) * aNormal;\n
85     vec4 centre = uModelView * vec4( 0.0, 0.0, 0.0, 1.0 );\n
86     vec4 lightPos = vec4( centre.x, centre.y, uLightPosition.z, 1.0 );\n
87     vec3 vecToLight = normalize( lightPos.xyz - vertPos.xyz );\n
88
89     float lightDiffuse = max( dot( vecToLight, normal ), 0.0 );\n
90     vIllumination = vec3( lightDiffuse * 0.5 + 0.5 );\n
91
92     gl_Position = vertexPosition;\n
93   }\n
94 );
95
96 //Fragment shader corresponding to the texture-less shader.
97 const char* SIMPLE_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
98   precision mediump float;\n
99   varying mediump vec3 vIllumination;\n
100   uniform lowp vec4 uColor;\n
101
102   void main()\n
103   {\n
104     gl_FragColor = vec4( vIllumination.rgb * uColor.rgb, uColor.a );\n
105   }\n
106 );
107
108 //Diffuse and specular illumination shader with albedo texture. Texture is index 0.
109 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
110   attribute highp vec3 aPosition;\n
111   attribute highp vec2 aTexCoord;\n
112   attribute highp vec3 aNormal;\n
113   varying mediump vec2 vTexCoord;\n
114   varying mediump vec3 vIllumination;\n
115   varying mediump float vSpecular;\n
116   uniform mediump vec3 uSize;\n
117   uniform mediump mat4 uMvpMatrix;\n
118   uniform mediump mat4 uModelView;
119   uniform mediump mat3 uNormalMatrix;
120   uniform mediump mat4 uObjectMatrix;\n
121   uniform mediump vec3 uLightPosition;\n
122
123   void main()
124   {\n
125     vec4 vertexPosition = vec4( aPosition * min( uSize.x, uSize.y ), 1.0 );\n
126     vertexPosition = uObjectMatrix * vertexPosition;\n
127     vertexPosition = uMvpMatrix * vertexPosition;\n
128
129     //Illumination in Model-View space - Transform attributes and uniforms\n
130     vec4 vertPos = uModelView * vec4( aPosition.xyz, 1.0 );\n
131     vec4 centre = uModelView * vec4( 0.0, 0.0, 0.0, 1.0 );\n
132     vec4 lightPos = vec4( centre.x, centre.y, uLightPosition.z, 1.0 );\n
133     vec3 normal = normalize( uNormalMatrix * mat3( uObjectMatrix ) * aNormal );\n
134
135     vec3 vecToLight = normalize( lightPos.xyz - vertPos.xyz );\n
136     vec3 viewDir = normalize( -vertPos.xyz );
137
138     vec3 halfVector = normalize( viewDir + vecToLight );
139
140     float lightDiffuse = dot( vecToLight, normal );\n
141     lightDiffuse = max( 0.0,lightDiffuse );\n
142     vIllumination = vec3( lightDiffuse * 0.5 + 0.5 );\n
143
144     vec3 reflectDir = reflect( -vecToLight, normal );
145     vSpecular = pow( max( dot( reflectDir, viewDir ), 0.0 ), 4.0 );
146
147     vTexCoord = aTexCoord;\n
148     gl_Position = vertexPosition;\n
149   }\n
150 );
151
152 //Fragment shader corresponding to the diffuse and specular illumination shader with albedo texture
153 const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
154   precision mediump float;\n
155   varying mediump vec2 vTexCoord;\n
156   varying mediump vec3 vIllumination;\n
157   varying mediump float vSpecular;\n
158   uniform sampler2D sDiffuse;\n
159   uniform lowp vec4 uColor;\n
160
161   void main()\n
162   {\n
163     vec4 texture = texture2D( sDiffuse, vTexCoord );\n
164     gl_FragColor = vec4( vIllumination.rgb * texture.rgb * uColor.rgb + vSpecular * 0.3, texture.a * uColor.a );\n
165   }\n
166 );
167
168 //Diffuse and specular illumination shader with albedo texture, normal map and gloss map shader.
169 //Diffuse (albedo) texture is index 0, normal is 1, gloss is 2. They must be declared in this order.
170 const char* NORMAL_MAP_VERTEX_SHADER = DALI_COMPOSE_SHADER(
171   attribute highp vec3 aPosition;\n
172   attribute highp vec2 aTexCoord;\n
173   attribute highp vec3 aNormal;\n
174   attribute highp vec3 aTangent;\n
175   attribute highp vec3 aBiNormal;\n
176   varying mediump vec2 vTexCoord;\n
177   varying mediump vec3 vLightDirection;\n
178   varying mediump vec3 vHalfVector;\n
179   uniform mediump vec3 uSize;\n
180   uniform mediump mat4 uMvpMatrix;\n
181   uniform mediump mat4 uModelView;
182   uniform mediump mat3 uNormalMatrix;
183   uniform mediump mat4 uObjectMatrix;\n
184   uniform mediump vec3 uLightPosition;\n
185
186   void main()
187   {\n
188     vec4 vertexPosition = vec4( aPosition * min( uSize.x, uSize.y ), 1.0 );\n
189     vertexPosition = uObjectMatrix * vertexPosition;\n
190     vertexPosition = uMvpMatrix * vertexPosition;\n
191
192     vec4 vertPos = uModelView * vec4( aPosition.xyz, 1.0 );\n
193     vec4 centre = uModelView * vec4( 0.0, 0.0, 0.0, 1.0 );\n
194     vec4 lightPos = vec4( centre.x, centre.y, uLightPosition.z, 1.0 );\n
195
196     vec3 tangent = normalize( uNormalMatrix * aTangent );
197     vec3 binormal = normalize( uNormalMatrix * aBiNormal );
198     vec3 normal = normalize( uNormalMatrix * mat3( uObjectMatrix ) * aNormal );
199
200     vec3 vecToLight = normalize( lightPos.xyz - vertPos.xyz );\n
201     vLightDirection.x = dot( vecToLight, tangent );
202     vLightDirection.y = dot( vecToLight, binormal );
203     vLightDirection.z = dot( vecToLight, normal );
204
205     vec3 viewDir = normalize( -vertPos.xyz );
206     vec3 halfVector = normalize( viewDir + vecToLight );
207     vHalfVector.x = dot( halfVector, tangent );
208     vHalfVector.y = dot( halfVector, binormal );
209     vHalfVector.z = dot( halfVector, normal );
210
211     vTexCoord = aTexCoord;\n
212     gl_Position = vertexPosition;\n
213   }\n
214 );
215
216 //Fragment shader corresponding to the shader that uses all textures (diffuse, normal and gloss maps)
217 const char* NORMAL_MAP_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
218   precision mediump float;\n
219   varying mediump vec2 vTexCoord;\n
220   varying mediump vec3 vLightDirection;\n
221   varying mediump vec3 vHalfVector;\n
222   uniform sampler2D sDiffuse;\n
223   uniform sampler2D sNormal;\n
224   uniform sampler2D sGloss;\n
225   uniform lowp vec4 uColor;\n
226
227   void main()\n
228   {\n
229     vec4 texture = texture2D( sDiffuse, vTexCoord );\n
230     vec3 normal = normalize( texture2D( sNormal, vTexCoord ).xyz * 2.0 - 1.0 );\n
231     vec4 glossMap = texture2D( sGloss, vTexCoord );\n
232
233     float lightDiffuse = max( 0.0, dot( normal, normalize( vLightDirection ) ) );\n
234     lightDiffuse = lightDiffuse * 0.5 + 0.5;\n
235
236     float shininess = pow ( max ( dot ( normalize( vHalfVector ), normal ), 0.0 ), 16.0 )  ;
237
238     gl_FragColor = vec4( texture.rgb * uColor.rgb * lightDiffuse + shininess * glossMap.rgb, texture.a * uColor.a );\n
239   }\n
240 );
241
242 } // namespace
243
244 MeshRenderer::MeshRenderer( RendererFactoryCache& factoryCache )
245 : ControlRenderer( factoryCache ),
246   mShaderType( ALL_TEXTURES ),
247   mUseTexture( true )
248 {
249 }
250
251 MeshRenderer::~MeshRenderer()
252 {
253 }
254
255 void MeshRenderer::DoInitialize( Actor& actor, const Property::Map& propertyMap )
256 {
257   Property::Value* objectUrl = propertyMap.Find( OBJECT_URL );
258   if( !objectUrl || !objectUrl->Get( mObjectUrl ) )
259   {
260     DALI_LOG_ERROR( "Fail to provide object URL to the MeshRenderer object.\n" );
261   }
262
263   Property::Value* materialUrl = propertyMap.Find( MATERIAL_URL );
264
265   if( !materialUrl || !materialUrl->Get( mMaterialUrl ) || mMaterialUrl.empty() )
266   {
267     mUseTexture = false;
268   }
269
270   Property::Value* imagesUrl = propertyMap.Find( TEXTURES_PATH );
271   if( !imagesUrl || !imagesUrl->Get( mTexturesPath ) )
272   {
273     //Default behaviour is to assume files are in the same directory,
274     // or have their locations detailed in full when supplied.
275     mTexturesPath.clear();
276   }
277
278   Property::Value* shaderType = propertyMap.Find( SHADER_TYPE );
279   if( shaderType && shaderType->Get( mShaderTypeString ) )
280   {
281     if( mShaderTypeString == "textureless" )
282     {
283       mShaderType = TEXTURELESS;
284     }
285     else if( mShaderTypeString == "diffuseTexture" )
286     {
287       mShaderType = DIFFUSE_TEXTURE;
288     }
289     else if( mShaderTypeString == "allTextures" )
290     {
291       mShaderType = ALL_TEXTURES;
292     }
293     else
294     {
295       DALI_LOG_ERROR( "Unknown shader type provided to the MeshRenderer object.\n");
296     }
297   }
298 }
299
300 void MeshRenderer::SetSize( const Vector2& size )
301 {
302   ControlRenderer::SetSize( size );
303
304   // ToDo: renderer responds to the size change
305 }
306
307 void MeshRenderer::SetClipRect( const Rect<int>& clipRect )
308 {
309   ControlRenderer::SetClipRect( clipRect );
310
311   //ToDo: renderer responds to the clipRect change
312 }
313
314 void MeshRenderer::SetOffset( const Vector2& offset )
315 {
316   //ToDo: renderer applies the offset
317 }
318
319 void MeshRenderer::DoSetOnStage( Actor& actor )
320 {
321   InitializeRenderer();
322 }
323
324 void MeshRenderer::DoCreatePropertyMap( Property::Map& map ) const
325 {
326   map.Clear();
327   map.Insert( RENDERER_TYPE, RENDERER_TYPE_VALUE );
328   map.Insert( OBJECT_URL, mObjectUrl );
329   map.Insert( MATERIAL_URL, mMaterialUrl );
330   map.Insert( TEXTURES_PATH, mTexturesPath );
331   map.Insert( SHADER_TYPE, mShaderTypeString );
332 }
333
334 void MeshRenderer::InitializeRenderer()
335 {
336   //Try to load the geometry from the file.
337   if( !LoadGeometry() )
338   {
339     SupplyEmptyGeometry();
340     return;
341   }
342
343   //If a texture is used by the obj file, load the supplied material file.
344   if( mObjLoader.IsTexturePresent() && !mMaterialUrl.empty() )
345   {
346     if( !LoadMaterial() )
347     {
348       SupplyEmptyGeometry();
349       return;
350     }
351   }
352
353   //Now that the required parts are loaded, create the geometry for the object.
354   if( !CreateGeometry() )
355   {
356     SupplyEmptyGeometry();
357     return;
358   }
359
360   CreateShader();
361
362   //Load the various texture files supplied by the material file.
363   if( !LoadTextures() )
364   {
365     SupplyEmptyGeometry();
366     return;
367   }
368
369   mImpl->mRenderer = Renderer::New( mGeometry, mShader );
370   mImpl->mRenderer.SetTextures( mTextureSet );
371   mImpl->mRenderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::ON );
372 }
373
374 void MeshRenderer::SupplyEmptyGeometry()
375 {
376   mGeometry = Geometry::New();
377   mShader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER );
378   mImpl->mRenderer = Renderer::New( mGeometry, mShader );
379
380   DALI_LOG_ERROR( "Initialisation error in mesh renderer.\n" );
381 }
382
383 void MeshRenderer::UpdateShaderUniforms()
384 {
385   Stage stage = Stage::GetCurrent();
386
387   Vector3 lightPosition( 0, 0, stage.GetSize().width );
388   mShader.RegisterProperty( LIGHT_POSITION, lightPosition );
389
390   Matrix scaleMatrix;
391   scaleMatrix.SetIdentityAndScale( Vector3( 1.0, -1.0, 1.0 ) );
392   mShader.RegisterProperty( OBJECT_MATRIX, scaleMatrix );
393 }
394
395 void MeshRenderer::CreateShader()
396 {
397   if( mShaderType == ALL_TEXTURES )
398   {
399     mShader = Shader::New( NORMAL_MAP_VERTEX_SHADER, NORMAL_MAP_FRAGMENT_SHADER );
400   }
401   else if( mShaderType == DIFFUSE_TEXTURE )
402   {
403     mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
404   }
405   else //Textureless
406   {
407     mShader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER );
408   }
409
410   UpdateShaderUniforms();
411 }
412
413 bool MeshRenderer::CreateGeometry()
414 {
415   //Determine if we need to use a simpler shader to handle the provided data
416   if( mShaderType == ALL_TEXTURES )
417   {
418     if( !mObjLoader.IsNormalMapPresent() || !mObjLoader.IsSpecularMapPresent() )
419     {
420       mShaderType = DIFFUSE_TEXTURE;
421     }
422   }
423   if( !mObjLoader.IsTexturePresent() || !mObjLoader.IsDiffuseMapPresent() || !mUseTexture )
424   {
425     mShaderType = TEXTURELESS;
426   }
427
428   int objectProperties = 0;
429
430   if( mShaderType == DIFFUSE_TEXTURE ||
431       mShaderType == ALL_TEXTURES )
432   {
433     objectProperties |= ObjLoader::TEXTURE_COORDINATES;
434   }
435
436   if( mShaderType == ALL_TEXTURES )
437   {
438     objectProperties |= ObjLoader::TANGENTS | ObjLoader::BINOMIALS;
439   }
440
441   //Create geometry with attributes required by shader.
442   mGeometry = mObjLoader.CreateGeometry( objectProperties );
443
444   if( mGeometry )
445   {
446     return true;
447   }
448
449   DALI_LOG_ERROR( "Failed to load geometry in mesh renderer.\n" );
450   return false;
451 }
452
453 bool MeshRenderer::LoadGeometry()
454 {
455   std::streampos fileSize;
456   Dali::Vector<char> fileContent;
457
458   if( FileLoader::ReadFile( mObjectUrl, fileSize, fileContent, FileLoader::TEXT ) )
459   {
460     mObjLoader.ClearArrays();
461     mObjLoader.LoadObject( fileContent.Begin(), fileSize );
462
463     //Get size information from the obj loaded
464     mSceneCenter = mObjLoader.GetCenter();
465     mSceneSize = mObjLoader.GetSize();
466
467     return true;
468   }
469
470   DALI_LOG_ERROR( "Failed to find object to load in mesh renderer.\n" );
471   return false;
472 }
473
474 bool MeshRenderer::LoadMaterial()
475 {
476   std::streampos fileSize;
477   Dali::Vector<char> fileContent;
478
479   if( FileLoader::ReadFile( mMaterialUrl, fileSize, fileContent, FileLoader::TEXT ) )
480   {
481     //Load data into obj (usable) form
482     mObjLoader.LoadMaterial( fileContent.Begin(), fileSize, mDiffuseTextureUrl, mNormalTextureUrl, mGlossTextureUrl );
483     return true;
484   }
485
486   DALI_LOG_ERROR( "Failed to find texture set to load in mesh renderer.\n" );
487   mUseTexture = false;
488   return false;
489 }
490
491 bool MeshRenderer::LoadTextures()
492 {
493   mTextureSet = TextureSet::New();
494
495   if( !mDiffuseTextureUrl.empty() )
496   {
497     std::string imageUrl = mTexturesPath + mDiffuseTextureUrl;
498
499     //Load textures
500     Image diffuseTexture = ResourceImage::New( imageUrl );
501     if( diffuseTexture )
502     {
503       mTextureSet.SetImage( DIFFUSE_INDEX, diffuseTexture );
504     }
505     else
506     {
507       DALI_LOG_ERROR( "Failed to load diffuse map texture in mesh renderer.\n");
508       return false;
509     }
510   }
511
512   if( !mNormalTextureUrl.empty() && ( mShaderType == ALL_TEXTURES ) )
513   {
514     std::string imageUrl = mTexturesPath + mNormalTextureUrl;
515
516     //Load textures
517     Image normalTexture = ResourceImage::New( imageUrl );
518     if( normalTexture )
519     {
520       mTextureSet.SetImage( NORMAL_INDEX, normalTexture );
521     }
522     else
523     {
524       DALI_LOG_ERROR( "Failed to load normal map texture in mesh renderer.\n");
525       return false;
526     }
527   }
528
529   if( !mGlossTextureUrl.empty() && ( mShaderType == ALL_TEXTURES ) )
530   {
531     std::string imageUrl = mTexturesPath + mGlossTextureUrl;
532
533     //Load textures
534     Image glossTexture = ResourceImage::New( imageUrl );
535     if( glossTexture )
536     {
537       mTextureSet.SetImage( GLOSS_INDEX, glossTexture );
538     }
539     else
540     {
541       DALI_LOG_ERROR( "Failed to load gloss map texture in mesh renderer.\n");
542       return false;
543     }
544   }
545
546   return true;
547 }
548
549 } // namespace Internal
550
551 } // namespace Toolkit
552
553 } // namespace Dali