2 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "mesh-renderer.h"
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>
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>
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.
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
61 //If a shader requires certain textures, they must be listed in order,
62 //as detailed in the TextureIndex enum documentation.
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
78 vec4 vertexPosition = vec4( aPosition * min( uSize.x, uSize.y ), 1.0 );\n
79 vertexPosition = uObjectMatrix * vertexPosition;\n
80 vertexPosition = uMvpMatrix * vertexPosition;\n
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
89 float lightDiffuse = max( dot( vecToLight, normal ), 0.0 );\n
90 vIllumination = vec3( lightDiffuse * 0.5 + 0.5 );\n
92 gl_Position = vertexPosition;\n
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
104 gl_FragColor = vec4( vIllumination.rgb * uColor.rgb, uColor.a );\n
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
125 vec4 vertexPosition = vec4( aPosition * min( uSize.x, uSize.y ), 1.0 );\n
126 vertexPosition = uObjectMatrix * vertexPosition;\n
127 vertexPosition = uMvpMatrix * vertexPosition;\n
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
135 vec3 vecToLight = normalize( lightPos.xyz - vertPos.xyz );\n
136 vec3 viewDir = normalize( -vertPos.xyz );
138 vec3 halfVector = normalize( viewDir + vecToLight );
140 float lightDiffuse = dot( vecToLight, normal );\n
141 lightDiffuse = max( 0.0,lightDiffuse );\n
142 vIllumination = vec3( lightDiffuse * 0.5 + 0.5 );\n
144 vec3 reflectDir = reflect( -vecToLight, normal );
145 vSpecular = pow( max( dot( reflectDir, viewDir ), 0.0 ), 4.0 );
147 vTexCoord = aTexCoord;\n
148 gl_Position = vertexPosition;\n
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
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
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
188 vec4 vertexPosition = vec4( aPosition * min( uSize.x, uSize.y ), 1.0 );\n
189 vertexPosition = uObjectMatrix * vertexPosition;\n
190 vertexPosition = uMvpMatrix * vertexPosition;\n
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
196 vec3 tangent = normalize( uNormalMatrix * aTangent );
197 vec3 binormal = normalize( uNormalMatrix * aBiNormal );
198 vec3 normal = normalize( uNormalMatrix * mat3( uObjectMatrix ) * aNormal );
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 );
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 );
211 vTexCoord = aTexCoord;\n
212 gl_Position = vertexPosition;\n
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
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
233 float lightDiffuse = max( 0.0, dot( normal, normalize( vLightDirection ) ) );\n
234 lightDiffuse = lightDiffuse * 0.5 + 0.5;\n
236 float shininess = pow ( max ( dot ( normalize( vHalfVector ), normal ), 0.0 ), 16.0 ) ;
238 gl_FragColor = vec4( texture.rgb * uColor.rgb * lightDiffuse + shininess * glossMap.rgb, texture.a * uColor.a );\n
244 MeshRenderer::MeshRenderer( RendererFactoryCache& factoryCache )
245 : ControlRenderer( factoryCache ),
246 mShaderType( ALL_TEXTURES ),
251 MeshRenderer::~MeshRenderer()
255 void MeshRenderer::DoInitialize( Actor& actor, const Property::Map& propertyMap )
257 Property::Value* objectUrl = propertyMap.Find( OBJECT_URL );
258 if( !objectUrl || !objectUrl->Get( mObjectUrl ) )
260 DALI_LOG_ERROR( "Fail to provide object URL to the MeshRenderer object.\n" );
263 Property::Value* materialUrl = propertyMap.Find( MATERIAL_URL );
265 if( !materialUrl || !materialUrl->Get( mMaterialUrl ) || mMaterialUrl.empty() )
270 Property::Value* imagesUrl = propertyMap.Find( TEXTURES_PATH );
271 if( !imagesUrl || !imagesUrl->Get( mTexturesPath ) )
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();
278 Property::Value* shaderType = propertyMap.Find( SHADER_TYPE );
279 if( shaderType && shaderType->Get( mShaderTypeString ) )
281 if( mShaderTypeString == "textureless" )
283 mShaderType = TEXTURELESS;
285 else if( mShaderTypeString == "diffuseTexture" )
287 mShaderType = DIFFUSE_TEXTURE;
289 else if( mShaderTypeString == "allTextures" )
291 mShaderType = ALL_TEXTURES;
295 DALI_LOG_ERROR( "Unknown shader type provided to the MeshRenderer object.\n");
300 void MeshRenderer::SetSize( const Vector2& size )
302 ControlRenderer::SetSize( size );
304 // ToDo: renderer responds to the size change
307 void MeshRenderer::SetClipRect( const Rect<int>& clipRect )
309 ControlRenderer::SetClipRect( clipRect );
311 //ToDo: renderer responds to the clipRect change
314 void MeshRenderer::SetOffset( const Vector2& offset )
316 //ToDo: renderer applies the offset
319 void MeshRenderer::DoSetOnStage( Actor& actor )
321 InitializeRenderer();
324 void MeshRenderer::DoCreatePropertyMap( Property::Map& map ) const
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 );
334 void MeshRenderer::InitializeRenderer()
336 //Try to load the geometry from the file.
337 if( !LoadGeometry() )
339 SupplyEmptyGeometry();
343 //If a texture is used by the obj file, load the supplied material file.
344 if( mObjLoader.IsTexturePresent() && !mMaterialUrl.empty() )
346 if( !LoadMaterial() )
348 SupplyEmptyGeometry();
353 //Now that the required parts are loaded, create the geometry for the object.
354 if( !CreateGeometry() )
356 SupplyEmptyGeometry();
362 //Load the various texture files supplied by the material file.
363 if( !LoadTextures() )
365 SupplyEmptyGeometry();
369 mImpl->mRenderer = Renderer::New( mGeometry, mShader );
370 mImpl->mRenderer.SetTextures( mTextureSet );
371 mImpl->mRenderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::ON );
374 void MeshRenderer::SupplyEmptyGeometry()
376 mGeometry = Geometry::New();
377 mShader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER );
378 mImpl->mRenderer = Renderer::New( mGeometry, mShader );
380 DALI_LOG_ERROR( "Initialisation error in mesh renderer.\n" );
383 void MeshRenderer::UpdateShaderUniforms()
385 Stage stage = Stage::GetCurrent();
387 Vector3 lightPosition( 0, 0, stage.GetSize().width );
388 mShader.RegisterProperty( LIGHT_POSITION, lightPosition );
391 scaleMatrix.SetIdentityAndScale( Vector3( 1.0, -1.0, 1.0 ) );
392 mShader.RegisterProperty( OBJECT_MATRIX, scaleMatrix );
395 void MeshRenderer::CreateShader()
397 if( mShaderType == ALL_TEXTURES )
399 mShader = Shader::New( NORMAL_MAP_VERTEX_SHADER, NORMAL_MAP_FRAGMENT_SHADER );
401 else if( mShaderType == DIFFUSE_TEXTURE )
403 mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
407 mShader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER );
410 UpdateShaderUniforms();
413 bool MeshRenderer::CreateGeometry()
415 //Determine if we need to use a simpler shader to handle the provided data
416 if( mShaderType == ALL_TEXTURES )
418 if( !mObjLoader.IsNormalMapPresent() || !mObjLoader.IsSpecularMapPresent() )
420 mShaderType = DIFFUSE_TEXTURE;
423 if( !mObjLoader.IsTexturePresent() || !mObjLoader.IsDiffuseMapPresent() || !mUseTexture )
425 mShaderType = TEXTURELESS;
428 int objectProperties = 0;
430 if( mShaderType == DIFFUSE_TEXTURE ||
431 mShaderType == ALL_TEXTURES )
433 objectProperties |= ObjLoader::TEXTURE_COORDINATES;
436 if( mShaderType == ALL_TEXTURES )
438 objectProperties |= ObjLoader::TANGENTS | ObjLoader::BINOMIALS;
441 //Create geometry with attributes required by shader.
442 mGeometry = mObjLoader.CreateGeometry( objectProperties );
449 DALI_LOG_ERROR( "Failed to load geometry in mesh renderer.\n" );
453 bool MeshRenderer::LoadGeometry()
455 std::streampos fileSize;
456 Dali::Vector<char> fileContent;
458 if( FileLoader::ReadFile( mObjectUrl, fileSize, fileContent, FileLoader::TEXT ) )
460 mObjLoader.ClearArrays();
461 mObjLoader.LoadObject( fileContent.Begin(), fileSize );
463 //Get size information from the obj loaded
464 mSceneCenter = mObjLoader.GetCenter();
465 mSceneSize = mObjLoader.GetSize();
470 DALI_LOG_ERROR( "Failed to find object to load in mesh renderer.\n" );
474 bool MeshRenderer::LoadMaterial()
476 std::streampos fileSize;
477 Dali::Vector<char> fileContent;
479 if( FileLoader::ReadFile( mMaterialUrl, fileSize, fileContent, FileLoader::TEXT ) )
481 //Load data into obj (usable) form
482 mObjLoader.LoadMaterial( fileContent.Begin(), fileSize, mDiffuseTextureUrl, mNormalTextureUrl, mGlossTextureUrl );
486 DALI_LOG_ERROR( "Failed to find texture set to load in mesh renderer.\n" );
491 bool MeshRenderer::LoadTextures()
493 mTextureSet = TextureSet::New();
495 if( !mDiffuseTextureUrl.empty() )
497 std::string imageUrl = mTexturesPath + mDiffuseTextureUrl;
500 Image diffuseTexture = ResourceImage::New( imageUrl );
503 mTextureSet.SetImage( DIFFUSE_INDEX, diffuseTexture );
507 DALI_LOG_ERROR( "Failed to load diffuse map texture in mesh renderer.\n");
512 if( !mNormalTextureUrl.empty() && ( mShaderType == ALL_TEXTURES ) )
514 std::string imageUrl = mTexturesPath + mNormalTextureUrl;
517 Image normalTexture = ResourceImage::New( imageUrl );
520 mTextureSet.SetImage( NORMAL_INDEX, normalTexture );
524 DALI_LOG_ERROR( "Failed to load normal map texture in mesh renderer.\n");
529 if( !mGlossTextureUrl.empty() && ( mShaderType == ALL_TEXTURES ) )
531 std::string imageUrl = mTexturesPath + mGlossTextureUrl;
534 Image glossTexture = ResourceImage::New( imageUrl );
537 mTextureSet.SetImage( GLOSS_INDEX, glossTexture );
541 DALI_LOG_ERROR( "Failed to load gloss map texture in mesh renderer.\n");
549 } // namespace Internal
551 } // namespace Toolkit