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-visual.h"
22 #include <dali/integration-api/debug.h>
23 #include <dali/public-api/common/stage.h>
24 #include <dali/devel-api/adaptor-framework/bitmap-loader.h>
25 #include <dali/devel-api/adaptor-framework/file-loader.h>
29 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
30 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
38 * @brief Loads a texture from a file
39 * @param[in] imageUrl The url of the file
40 * @param[in] generateMipmaps Indicates whether to generate mipmaps for the texture
41 * @return A texture if loading succeeds, an empty handle otherwise
43 Texture LoadTexture( const char* imageUrl, bool generateMipmaps )
46 Dali::BitmapLoader loader = Dali::BitmapLoader::New( imageUrl );
48 PixelData pixelData = loader.GetPixelData();
51 texture = Texture::New( TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight() );
52 texture.Upload( pixelData );
56 texture.GenerateMipmaps();
73 //Defines ordering of textures for shaders.
74 //All shaders, if including certain texture types, must include them in the same order.
75 //Within the texture set for the renderer, textures are ordered in the same manner.
84 const char * const OBJECT_MATRIX_UNIFORM_NAME( "uObjectMatrix" );
85 const char * const STAGE_OFFSET_UNIFORM_NAME( "uStageOffset" );
87 const char * const SHADER_TYPE_TEXTURELESS( "TEXTURELESS" );
88 const char * const SHADER_TYPE_DIFFUSE_TEXTURE( "DIFFUSE_TEXTURE" );
89 const char * const SHADER_TYPE_ALL_TEXTURES( "ALL_TEXTURES" );
92 //If a shader requires certain textures, they must be listed in order,
93 //as detailed in the TextureIndex enum documentation.
95 //A basic shader that doesn't use textures at all.
96 const char* SIMPLE_VERTEX_SHADER = DALI_COMPOSE_SHADER(
97 attribute highp vec3 aPosition;\n
98 attribute highp vec3 aNormal;\n
99 varying mediump vec3 vIllumination;\n
100 uniform mediump vec3 uSize;\n
101 uniform mediump mat4 uMvpMatrix;\n
102 uniform mediump mat4 uModelView;\n
103 uniform mediump mat4 uViewMatrix;\n
104 uniform mediump mat3 uNormalMatrix;
105 uniform mediump mat4 uObjectMatrix;\n
106 uniform mediump vec3 lightPosition;\n
107 uniform mediump vec2 uStageOffset;\n
111 vec4 normalisedVertexPosition = vec4( aPosition * min( uSize.x, uSize.y ), 1.0 );\n
112 vec4 vertexPosition = uObjectMatrix * normalisedVertexPosition;\n
113 vertexPosition = uMvpMatrix * vertexPosition;\n
115 //Illumination in Model-View space - Transform attributes and uniforms\n
116 vec4 mvVertexPosition = uModelView * normalisedVertexPosition;\n
117 vec3 normal = uNormalMatrix * mat3( uObjectMatrix ) * aNormal;\n
119 vec4 mvLightPosition = vec4( ( lightPosition.xy - uStageOffset ), lightPosition.z, 1.0 );\n
120 mvLightPosition = uViewMatrix * mvLightPosition;\n
121 vec3 vectorToLight = normalize( mvLightPosition.xyz - mvVertexPosition.xyz );\n
123 float lightDiffuse = max( dot( vectorToLight, normal ), 0.0 );\n
124 vIllumination = vec3( lightDiffuse * 0.5 + 0.5 );\n
126 gl_Position = vertexPosition;\n
130 //Fragment shader corresponding to the texture-less shader.
131 const char* SIMPLE_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
132 precision mediump float;\n
133 varying mediump vec3 vIllumination;\n
134 uniform lowp vec4 uColor;\n
138 gl_FragColor = vec4( vIllumination.rgb * uColor.rgb, uColor.a );\n
142 //Diffuse and specular illumination shader with albedo texture. Texture is index 0.
143 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
144 attribute highp vec3 aPosition;\n
145 attribute highp vec2 aTexCoord;\n
146 attribute highp vec3 aNormal;\n
147 varying mediump vec2 vTexCoord;\n
148 varying mediump vec3 vIllumination;\n
149 varying mediump float vSpecular;\n
150 uniform mediump vec3 uSize;\n
151 uniform mediump mat4 uMvpMatrix;\n
152 uniform mediump mat4 uModelView;
153 uniform mediump mat4 uViewMatrix;\n
154 uniform mediump mat3 uNormalMatrix;
155 uniform mediump mat4 uObjectMatrix;\n
156 uniform mediump vec3 lightPosition;\n
157 uniform mediump vec2 uStageOffset;\n
161 vec4 normalisedVertexPosition = vec4( aPosition * min( uSize.x, uSize.y ), 1.0 );\n
162 vec4 vertexPosition = uObjectMatrix * normalisedVertexPosition;\n
163 vertexPosition = uMvpMatrix * vertexPosition;\n
165 //Illumination in Model-View space - Transform attributes and uniforms\n
166 vec4 mvVertexPosition = uModelView * normalisedVertexPosition;\n
167 vec3 normal = normalize( uNormalMatrix * mat3( uObjectMatrix ) * aNormal );\n
169 vec4 mvLightPosition = vec4( ( lightPosition.xy - uStageOffset ), lightPosition.z, 1.0 );\n
170 mvLightPosition = uViewMatrix * mvLightPosition;\n
171 vec3 vectorToLight = normalize( mvLightPosition.xyz - mvVertexPosition.xyz );\n
173 vec3 viewDirection = normalize( -mvVertexPosition.xyz );
175 float lightDiffuse = dot( vectorToLight, normal );\n
176 lightDiffuse = max( 0.0,lightDiffuse );\n
177 vIllumination = vec3( lightDiffuse * 0.5 + 0.5 );\n
179 vec3 reflectDirection = reflect( -vectorToLight, normal );
180 vSpecular = pow( max( dot( reflectDirection, viewDirection ), 0.0 ), 4.0 );
182 vTexCoord = aTexCoord;\n
183 gl_Position = vertexPosition;\n
187 //Fragment shader corresponding to the diffuse and specular illumination shader with albedo texture
188 const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
189 precision mediump float;\n
190 varying mediump vec2 vTexCoord;\n
191 varying mediump vec3 vIllumination;\n
192 varying mediump float vSpecular;\n
193 uniform sampler2D sDiffuse;\n
194 uniform lowp vec4 uColor;\n
198 vec4 texture = texture2D( sDiffuse, vTexCoord );\n
199 gl_FragColor = vec4( vIllumination.rgb * texture.rgb * uColor.rgb + vSpecular * 0.3, texture.a * uColor.a );\n
203 //Diffuse and specular illumination shader with albedo texture, normal map and gloss map shader.
204 //Diffuse (albedo) texture is index 0, normal is 1, gloss is 2. They must be declared in this order.
205 const char* NORMAL_MAP_VERTEX_SHADER = DALI_COMPOSE_SHADER(
206 attribute highp vec3 aPosition;\n
207 attribute highp vec2 aTexCoord;\n
208 attribute highp vec3 aNormal;\n
209 attribute highp vec3 aTangent;\n
210 attribute highp vec3 aBiNormal;\n
211 varying mediump vec2 vTexCoord;\n
212 varying mediump vec3 vLightDirection;\n
213 varying mediump vec3 vHalfVector;\n
214 uniform mediump vec3 uSize;\n
215 uniform mediump mat4 uMvpMatrix;\n
216 uniform mediump mat4 uModelView;
217 uniform mediump mat4 uViewMatrix;\n
218 uniform mediump mat3 uNormalMatrix;
219 uniform mediump mat4 uObjectMatrix;\n
220 uniform mediump vec3 lightPosition;\n
221 uniform mediump vec2 uStageOffset;\n
224 vec4 normalisedVertexPosition = vec4( aPosition * min( uSize.x, uSize.y ), 1.0 );\n
225 vec4 vertexPosition = uObjectMatrix * normalisedVertexPosition;\n
226 vertexPosition = uMvpMatrix * vertexPosition;\n
228 vec4 mvVertexPosition = uModelView * normalisedVertexPosition;\n
230 vec3 tangent = normalize( uNormalMatrix * mat3( uObjectMatrix ) * aTangent );
231 vec3 binormal = normalize( uNormalMatrix * mat3( uObjectMatrix ) * aBiNormal );
232 vec3 normal = normalize( uNormalMatrix * mat3( uObjectMatrix ) * aNormal );
234 vec4 mvLightPosition = vec4( ( lightPosition.xy - uStageOffset ), lightPosition.z, 1.0 );\n
235 mvLightPosition = uViewMatrix * mvLightPosition;\n
236 vec3 vectorToLight = normalize( mvLightPosition.xyz - mvVertexPosition.xyz );\n
237 vLightDirection.x = dot( vectorToLight, tangent );
238 vLightDirection.y = dot( vectorToLight, binormal );
239 vLightDirection.z = dot( vectorToLight, normal );
241 vec3 viewDirection = normalize( -mvVertexPosition.xyz );
242 vec3 halfVector = normalize( viewDirection + vectorToLight );
243 vHalfVector.x = dot( halfVector, tangent );
244 vHalfVector.y = dot( halfVector, binormal );
245 vHalfVector.z = dot( halfVector, normal );
247 vTexCoord = aTexCoord;\n
248 gl_Position = vertexPosition;\n
252 //Fragment shader corresponding to the shader that uses all textures (diffuse, normal and gloss maps)
253 const char* NORMAL_MAP_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
254 precision mediump float;\n
255 varying mediump vec2 vTexCoord;\n
256 varying mediump vec3 vLightDirection;\n
257 varying mediump vec3 vHalfVector;\n
258 uniform sampler2D sDiffuse;\n
259 uniform sampler2D sNormal;\n
260 uniform sampler2D sGloss;\n
261 uniform lowp vec4 uColor;\n
265 vec4 texture = texture2D( sDiffuse, vTexCoord );\n
266 vec3 normal = normalize( texture2D( sNormal, vTexCoord ).xyz * 2.0 - 1.0 );\n
267 vec4 glossMap = texture2D( sGloss, vTexCoord );\n
269 float lightDiffuse = max( 0.0, dot( normal, normalize( vLightDirection ) ) );\n
270 lightDiffuse = lightDiffuse * 0.5 + 0.5;\n
272 float shininess = pow ( max ( dot ( normalize( vHalfVector ), normal ), 0.0 ), 16.0 ) ;
274 gl_FragColor = vec4( texture.rgb * uColor.rgb * lightDiffuse + shininess * glossMap.rgb, texture.a * uColor.a );\n
280 MeshVisual::MeshVisual( VisualFactoryCache& factoryCache )
281 : Visual::Base( factoryCache ),
282 mShaderType( ALL_TEXTURES ),
284 mUseMipmapping( true ),
285 mUseSoftNormals( true )
289 MeshVisual::~MeshVisual()
293 void MeshVisual::DoInitialize( Actor& actor, const Property::Map& propertyMap )
295 Property::Value* objectUrl = propertyMap.Find( OBJECT_URL );
296 if( !objectUrl || !objectUrl->Get( mObjectUrl ) )
298 DALI_LOG_ERROR( "Fail to provide object URL to the MeshVisual object.\n" );
301 Property::Value* materialUrl = propertyMap.Find( MATERIAL_URL );
302 if( !materialUrl || !materialUrl->Get( mMaterialUrl ) || mMaterialUrl.empty() )
307 Property::Value* imagesUrl = propertyMap.Find( TEXTURES_PATH );
308 if( !imagesUrl || !imagesUrl->Get( mTexturesPath ) )
310 //Default behaviour is to assume files are in the same directory,
311 // or have their locations detailed in full when supplied.
312 mTexturesPath.clear();
315 Property::Value* shaderType = propertyMap.Find( SHADER_TYPE );
318 std::string shaderTypeString;
319 if( shaderType->Get( shaderTypeString ) )
321 if( shaderTypeString == SHADER_TYPE_TEXTURELESS )
323 mShaderType = TEXTURELESS;
325 else if( shaderTypeString == SHADER_TYPE_DIFFUSE_TEXTURE )
327 mShaderType = DIFFUSE_TEXTURE;
329 else if( shaderTypeString == SHADER_TYPE_ALL_TEXTURES )
331 mShaderType = ALL_TEXTURES;
335 DALI_LOG_ERROR( "Unknown shader type provided to the MeshVisual object.\n");
340 Property::Value* useMipmapping = propertyMap.Find( USE_MIPMAPPING );
343 useMipmapping->Get( mUseMipmapping );
346 Property::Value* useSoftNormals = propertyMap.Find( USE_SOFT_NORMALS );
349 useSoftNormals->Get( mUseSoftNormals );
352 Property::Value* lightPosition = propertyMap.Find( LIGHT_POSITION_UNIFORM_NAME );
355 if( !lightPosition->Get( mLightPosition ) )
357 DALI_LOG_ERROR( "Invalid value passed for light position in MeshRenderer object.\n" );
358 mLightPosition = Vector3::ZERO;
363 //Default behaviour is to place the light directly in front of the object,
364 // at a reasonable distance to light everything on screen.
365 Stage stage = Stage::GetCurrent();
367 mLightPosition = Vector3( stage.GetSize().width / 2, stage.GetSize().height / 2, stage.GetSize().width * 5 );
371 void MeshVisual::SetSize( const Vector2& size )
373 Visual::Base::SetSize( size );
375 // ToDo: renderer responds to the size change
378 void MeshVisual::SetClipRect( const Rect<int>& clipRect )
380 Visual::Base::SetClipRect( clipRect );
382 //ToDo: renderer responds to the clipRect change
385 void MeshVisual::SetOffset( const Vector2& offset )
387 //ToDo: renderer applies the offset
390 void MeshVisual::DoSetOnStage( Actor& actor )
392 InitializeRenderer();
395 void MeshVisual::DoCreatePropertyMap( Property::Map& map ) const
398 map.Insert( RENDERER_TYPE, MESH_RENDERER );
399 map.Insert( OBJECT_URL, mObjectUrl );
400 map.Insert( MATERIAL_URL, mMaterialUrl );
401 map.Insert( TEXTURES_PATH, mTexturesPath );
403 std::string shaderTypeString;
404 switch( mShaderType )
408 shaderTypeString = SHADER_TYPE_ALL_TEXTURES;
412 case DIFFUSE_TEXTURE:
414 shaderTypeString = SHADER_TYPE_DIFFUSE_TEXTURE;
420 shaderTypeString = SHADER_TYPE_TEXTURELESS;
424 map.Insert( SHADER_TYPE, shaderTypeString );
426 map.Insert( USE_MIPMAPPING, mUseMipmapping );
427 map.Insert( USE_SOFT_NORMALS, mUseSoftNormals );
428 map.Insert( LIGHT_POSITION_UNIFORM_NAME, mLightPosition );
431 void MeshVisual::InitializeRenderer()
433 //Try to load the geometry from the file.
434 if( !LoadGeometry() )
436 SupplyEmptyGeometry();
440 //If a texture is used by the obj file, load the supplied material file.
441 if( mObjLoader.IsTexturePresent() && !mMaterialUrl.empty() )
443 if( !LoadMaterial() )
445 SupplyEmptyGeometry();
450 //Now that the required parts are loaded, create the geometry for the object.
451 if( !CreateGeometry() )
453 SupplyEmptyGeometry();
459 //Load the various texture files supplied by the material file.
460 if( !LoadTextures() )
462 SupplyEmptyGeometry();
466 mImpl->mRenderer = Renderer::New( mGeometry, mShader );
467 mImpl->mRenderer.SetTextures( mTextureSet );
468 mImpl->mRenderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::ON );
471 void MeshVisual::SupplyEmptyGeometry()
473 mGeometry = Geometry::New();
474 mShader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER );
475 mImpl->mRenderer = Renderer::New( mGeometry, mShader );
477 DALI_LOG_ERROR( "Initialisation error in mesh visual.\n" );
480 void MeshVisual::UpdateShaderUniforms()
482 Stage stage = Stage::GetCurrent();
483 float width = stage.GetSize().width;
484 float height = stage.GetSize().height;
487 scaleMatrix.SetIdentityAndScale( Vector3( 1.0, -1.0, 1.0 ) );
489 mShader.RegisterProperty( STAGE_OFFSET_UNIFORM_NAME, Vector2( width, height ) / 2.0f );
490 mShader.RegisterProperty( LIGHT_POSITION_UNIFORM_NAME, mLightPosition );
491 mShader.RegisterProperty( OBJECT_MATRIX_UNIFORM_NAME, scaleMatrix );
494 void MeshVisual::CreateShader()
496 if( mShaderType == ALL_TEXTURES )
498 mShader = Shader::New( NORMAL_MAP_VERTEX_SHADER, NORMAL_MAP_FRAGMENT_SHADER );
500 else if( mShaderType == DIFFUSE_TEXTURE )
502 mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
506 mShader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER );
509 UpdateShaderUniforms();
512 bool MeshVisual::CreateGeometry()
514 //Determine if we need to use a simpler shader to handle the provided data
515 if( !mUseTexture || !mObjLoader.IsDiffuseMapPresent() )
517 mShaderType = TEXTURELESS;
519 else if( mShaderType == ALL_TEXTURES && (!mObjLoader.IsNormalMapPresent() || !mObjLoader.IsSpecularMapPresent()) )
521 mShaderType = DIFFUSE_TEXTURE;
524 int objectProperties = 0;
526 if( mShaderType == DIFFUSE_TEXTURE ||
527 mShaderType == ALL_TEXTURES )
529 objectProperties |= ObjLoader::TEXTURE_COORDINATES;
532 if( mShaderType == ALL_TEXTURES )
534 objectProperties |= ObjLoader::TANGENTS | ObjLoader::BINORMALS;
537 //Create geometry with attributes required by shader.
538 mGeometry = mObjLoader.CreateGeometry( objectProperties, mUseSoftNormals );
545 DALI_LOG_ERROR( "Failed to load geometry in mesh visual.\n" );
549 bool MeshVisual::LoadGeometry()
551 std::streampos fileSize;
552 Dali::Vector<char> fileContent;
554 if( FileLoader::ReadFile( mObjectUrl, fileSize, fileContent, FileLoader::TEXT ) )
556 mObjLoader.ClearArrays();
557 mObjLoader.LoadObject( fileContent.Begin(), fileSize );
559 //Get size information from the obj loaded
560 mSceneCenter = mObjLoader.GetCenter();
561 mSceneSize = mObjLoader.GetSize();
566 DALI_LOG_ERROR( "Failed to find object to load in mesh visual.\n" );
570 bool MeshVisual::LoadMaterial()
572 std::streampos fileSize;
573 Dali::Vector<char> fileContent;
575 if( FileLoader::ReadFile( mMaterialUrl, fileSize, fileContent, FileLoader::TEXT ) )
577 //Load data into obj (usable) form
578 mObjLoader.LoadMaterial( fileContent.Begin(), fileSize, mDiffuseTextureUrl, mNormalTextureUrl, mGlossTextureUrl );
582 DALI_LOG_ERROR( "Failed to find texture set to load in mesh visual.\n" );
587 bool MeshVisual::LoadTextures()
589 mTextureSet = TextureSet::New();
591 if( mShaderType != TEXTURELESS )
593 Sampler sampler = Sampler::New();
596 sampler.SetFilterMode( FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR_MIPMAP_LINEAR );
599 if( !mDiffuseTextureUrl.empty() )
601 std::string imageUrl = mTexturesPath + mDiffuseTextureUrl;
604 Texture diffuseTexture = LoadTexture( imageUrl.c_str(), mUseMipmapping );
607 mTextureSet.SetTexture( DIFFUSE_INDEX, diffuseTexture );
608 mTextureSet.SetSampler( DIFFUSE_INDEX, sampler );
612 DALI_LOG_ERROR( "Failed to load diffuse map texture in mesh visual.\n");
617 if( !mNormalTextureUrl.empty() && ( mShaderType == ALL_TEXTURES ) )
619 std::string imageUrl = mTexturesPath + mNormalTextureUrl;
622 Texture normalTexture = LoadTexture( imageUrl.c_str(), mUseMipmapping );
625 mTextureSet.SetTexture( NORMAL_INDEX, normalTexture );
626 mTextureSet.SetSampler( NORMAL_INDEX, sampler );
630 DALI_LOG_ERROR( "Failed to load normal map texture in mesh visual.\n");
635 if( !mGlossTextureUrl.empty() && ( mShaderType == ALL_TEXTURES ) )
637 std::string imageUrl = mTexturesPath + mGlossTextureUrl;
640 Texture glossTexture = LoadTexture( imageUrl.c_str(), mUseMipmapping );
643 mTextureSet.SetTexture( GLOSS_INDEX, glossTexture );
644 mTextureSet.SetSampler( GLOSS_INDEX, sampler );
648 DALI_LOG_ERROR( "Failed to load gloss map texture in mesh visual.\n");
656 } // namespace Internal
658 } // namespace Toolkit