/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <dali/public-api/animation/constraint.h>
#include <dali/public-api/animation/constraint-source.h>
#include <dali/public-api/animation/constraints.h>
-#include <dali/devel-api/object/type-registry-helper.h>
+#include <dali/public-api/object/type-registry-helper.h>
#include <dali-toolkit/public-api/controls/model3d-view/model3d-view.h>
#include <dali/public-api/images/resource-image.h>
#include <dali/devel-api/adaptor-framework/file-loader.h>
+#include <dali/devel-api/adaptor-framework/image-loading.h>
// INTERNAL INCLUDES
#include <dali-toolkit/internal/controls/model3d-view/obj-loader.h>
namespace
{
+// Texture indices are constants.
+enum TextureIndex
+{
+ DIFFUSE_TEXTURE_INDEX,
+ NORMAL_TEXTURE_INDEX,
+ GLOSS_TEXTURE_INDEX
+};
+
+/**
+ * @brief Loads a texture from a file.
+ * @param[in] imageUrl The URL of the file
+ * @return A texture if loading succeeds, an empty handle otherwise
+ */
+Texture LoadTexture( const char* imageUrl )
+{
+ Texture texture;
+ Devel::PixelBuffer pixelBuffer = LoadImageFromFile( imageUrl );
+ if( pixelBuffer )
+ {
+ texture = Texture::New( TextureType::TEXTURE_2D, pixelBuffer.GetPixelFormat(), pixelBuffer.GetWidth(), pixelBuffer.GetHeight() );
+ PixelData pixelData = Devel::PixelBuffer::Convert( pixelBuffer );
+ texture.Upload( pixelData );
+ texture.GenerateMipmaps();
+ }
+
+ return texture;
+}
+
// Type registration
BaseHandle Create()
{
// Setup properties, signals and actions using the type-registry.
DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Model3dView, Toolkit::Control, Create );
-DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "geometry-url", STRING, GEOMETRY_URL)
-DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "material-url", STRING, MATERIAL_URL)
-DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "images-url", STRING, IMAGES_URL)
-DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "illumination-type", INTEGER, ILLUMINATION_TYPE)
-DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "texture0-url", STRING, TEXTURE0_URL)
-DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "texture1-url", STRING, TEXTURE1_URL)
-DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "texture2-url", STRING, TEXTURE2_URL)
+DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "geometryUrl", STRING, GEOMETRY_URL)
+DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "materialUrl", STRING, MATERIAL_URL)
+DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "imagesUrl", STRING, IMAGES_URL)
+DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "illuminationType", INTEGER, ILLUMINATION_TYPE)
+DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "texture0Url", STRING, TEXTURE0_URL)
+DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "texture1Url", STRING, TEXTURE1_URL)
+DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "texture2Url", STRING, TEXTURE2_URL)
-DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, Model3dView, "light-position", VECTOR3, LIGHT_POSITION)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, Model3dView, "lightPosition", VECTOR3, LIGHT_POSITION)
DALI_TYPE_REGISTRATION_END()
uniform mediump mat3 uNormalMatrix;
uniform mediump mat4 uObjectMatrix;\n
uniform mediump vec3 uLightPosition;\n
- \n
+
void main()\n
{\n
vec4 vertexPosition = vec4(aPosition*min(uSize.x, uSize.y), 1.0);\n
vertexPosition = uObjectMatrix * vertexPosition;\n
vertexPosition = uMvpMatrix * vertexPosition;\n
- \n
+
//Illumination in Model-View space - Transform attributes and uniforms\n
- vec4 vertPos4 = uModelView * vec4(aPosition.xyz, 1.0);\n
- vec3 vertPos = vec3(vertPos4) / vertPos4.w;\n
- \n
- vec3 normalInterp = uNormalMatrix * aNormal;\n
- \n
- vec4 lightPos4 = uModelView * vec4(uLightPosition, 1.0);\n
- vec3 lightPos = vec3(lightPos4) / lightPos4.w;\n
- \n
+ vec4 vertPos = uModelView * vec4(aPosition.xyz, 1.0);\n
+ vec3 normal = uNormalMatrix * aNormal;\n
+ vec4 lightPos = uModelView * vec4(uLightPosition, 1.0);\n
vec3 vecToLight = normalize( lightPos.xyz - vertPos.xyz );\n
- \n
- float lightDiffuse = dot( vecToLight, normalInterp );\n
- lightDiffuse = max(0.0,lightDiffuse);\n
+
+ float lightDiffuse = max( dot( vecToLight, normal ), 0.0 );\n
vIllumination = vec3(lightDiffuse * 0.5 + 0.5);\n
- \n
+
gl_Position = vertexPosition;\n
}\n
);
precision mediump float;\n
varying mediump vec3 vIllumination;\n
uniform lowp vec4 uColor;\n
- \n
+
void main()\n
{\n
- gl_FragColor.rgb = vIllumination.rgb * uColor.rgb;\n
- gl_FragColor.a = uColor.a;\n
+ gl_FragColor = vec4( vIllumination.rgb * uColor.rgb, uColor.a);\n
}\n
);
uniform mediump mat3 uNormalMatrix;
uniform mediump mat4 uObjectMatrix;\n
uniform mediump vec3 uLightPosition;\n
- \n
+
void main()
{\n
vec4 vertexPosition = vec4(aPosition*min(uSize.x, uSize.y), 1.0);\n
vertexPosition = uObjectMatrix * vertexPosition;\n
vertexPosition = uMvpMatrix * vertexPosition;\n
- \n
+
//Illumination in Model-View space - Transform attributes and uniforms\n
- vec4 vertPos4 = uModelView * vec4(aPosition.xyz, 1.0);\n
- vec3 vertPos = vec3(vertPos4) / vertPos4.w;\n
- \n
- vec4 lightPos4 = uModelView * vec4(uLightPosition, 1.0);\n
- vec3 lightPos = vec3(lightPos4) / lightPos4.w;\n
- \n
- vec3 normalInterp = normalize(uNormalMatrix * aNormal);\n
- \n
+ vec4 vertPos = uModelView * vec4(aPosition.xyz, 1.0);\n
+ vec4 lightPos = uModelView * vec4(uLightPosition, 1.0);\n
+ vec3 normal = normalize(uNormalMatrix * aNormal);\n
+
vec3 vecToLight = normalize( lightPos.xyz - vertPos.xyz );\n
- vec3 viewDir = normalize(-vertPos);
- \n
+ vec3 viewDir = normalize(-vertPos.xyz);
+
vec3 halfVector = normalize(viewDir + vecToLight);
- \n
- float lightDiffuse = dot( vecToLight, normalInterp );\n
+
+ float lightDiffuse = dot( vecToLight, normal );\n
lightDiffuse = max(0.0,lightDiffuse);\n
vIllumination = vec3(lightDiffuse * 0.5 + 0.5);\n
- \n
- // this is blinn phong
- //float specAngle = max(dot(halfVector, normalInterp), 0.0);\n
- //vSpecular = pow(specAngle, 16.0);\n
- \n
- // this is phong (for comparison)
- vec3 reflectDir = reflect(-vecToLight, normalInterp);
- float specAngle = max(dot(reflectDir, viewDir), 0.0);
- // note that the exponent is different here
- vSpecular = pow(specAngle, 16.0/4.0);
- \n
+
+ vec3 reflectDir = reflect(-vecToLight, normal);
+ vSpecular = pow( max(dot(reflectDir, viewDir), 0.0), 4.0 );
+
vTexCoord = aTexCoord;\n
gl_Position = vertexPosition;\n
}\n
varying mediump float vSpecular;\n
uniform sampler2D sDiffuse;\n
uniform lowp vec4 uColor;\n
- \n
+
void main()\n
{\n
vec4 texture = texture2D( sDiffuse, vTexCoord );\n
- gl_FragColor.rgb = vIllumination.rgb * texture.rgb * uColor.rgb + vSpecular * 0.3;\n
- gl_FragColor.a = texture.a * uColor.a;\n
+ gl_FragColor = vec4( vIllumination.rgb * texture.rgb * uColor.rgb + vSpecular * 0.3, texture.a * uColor.a);\n
}\n
);
uniform mediump mat3 uNormalMatrix;
uniform mediump mat4 uObjectMatrix;\n
uniform mediump vec3 uLightPosition;\n
- \n
+
void main()
{\n
vec4 vertexPosition = vec4(aPosition*min(uSize.x, uSize.y), 1.0);\n
vertexPosition = uObjectMatrix * vertexPosition;\n
vertexPosition = uMvpMatrix * vertexPosition;\n
- \n
- vTexCoord = aTexCoord;\n
- \n
- vec3 vNormal = normalize(uNormalMatrix * aNormal);\n
- vec3 vTangent = normalize(uNormalMatrix * aTangent);\n
- vec3 vBiNormal = normalize(uNormalMatrix * aBiNormal);\n
- \n
- vec4 vertPos4 = uModelView * vec4(aPosition.xyz, 1.0);\n
- vec3 vertPos = vec3(vertPos4) / vertPos4.w;\n
- \n
- vec4 lightPos4 = uModelView * vec4(uLightPosition, 1.0);\n
- vec3 lightPos = vec3(lightPos4) / lightPos4.w;\n
- \n
- vec3 vecToLight = lightPos - vertPos;
- vLightDirection.x = dot(vecToLight, vTangent);
- vLightDirection.y = dot(vecToLight, vBiNormal);
- vLightDirection.z = dot(vecToLight, vNormal);
- vLightDirection = normalize(vLightDirection);
- \n
- vec3 viewDir = normalize(vertPos);
- \n
+
+ vec4 vertPos = uModelView * vec4(aPosition.xyz, 1.0);\n
+ vec4 lightPos = uModelView * vec4(uLightPosition, 1.0);\n
+
+ vec3 tangent = normalize(uNormalMatrix * aTangent);
+ vec3 binormal = normalize(uNormalMatrix * aBiNormal);
+ vec3 normal = normalize(uNormalMatrix * aNormal);
+
+ vec3 vecToLight = normalize( lightPos.xyz - vertPos.xyz );\n
+ vLightDirection.x = dot(vecToLight, tangent);
+ vLightDirection.y = dot(vecToLight, binormal);
+ vLightDirection.z = dot(vecToLight, normal);
+
+ vec3 viewDir = normalize(-vertPos.xyz);
vec3 halfVector = normalize(viewDir + vecToLight);
- vHalfVector.x = dot (halfVector, vTangent);
- vHalfVector.y = dot (halfVector, vBiNormal);
- vHalfVector.z = dot (halfVector, vNormal);
- \n
- gl_Position = vertexPosition;\n
+ vHalfVector.x = dot(halfVector, tangent);
+ vHalfVector.y = dot(halfVector, binormal);
+ vHalfVector.z = dot(halfVector, normal);
- //vHalfVector = aTangent;
+ vTexCoord = aTexCoord;\n
+ gl_Position = vertexPosition;\n
}\n
);
uniform sampler2D sNormal;\n
uniform sampler2D sGloss;\n
uniform lowp vec4 uColor;\n
- \n
+
void main()\n
{\n
vec4 texture = texture2D( sDiffuse, vTexCoord );\n
- vec4 nrmMap = texture2D( sNormal, vTexCoord ) * 2.0 - 1.0;\n
+ vec3 normal = normalize( texture2D( sNormal, vTexCoord ).xyz * 2.0 - 1.0 );\n
vec4 glossMap = texture2D( sGloss, vTexCoord );\n
- \n
- vec3 normalizedLightDirection = normalize(vLightDirection);\n
- float lightDiffuse = max( 0.0, dot( nrmMap.xyz, normalizedLightDirection ) );\n
+
+ float lightDiffuse = max( 0.0, dot( normal, normalize(vLightDirection) ) );\n
lightDiffuse = lightDiffuse * 0.5 + 0.5;\n
- \n
- float shininess = pow (max (dot (vHalfVector, nrmMap.xyz), 0.0), 16.0) ;
- \n
- gl_FragColor.rgb = texture.rgb * uColor.rgb * lightDiffuse + shininess * glossMap.rgb;\n
- gl_FragColor.a = texture.a * uColor.a;\n
- //gl_FragColor.rgb = vHalfVector.rgb;
+ float shininess = pow (max (dot (normalize( vHalfVector ), normal), 0.0), 16.0) ;
+
+ gl_FragColor = vec4( texture.rgb * uColor.rgb * lightDiffuse + shininess * glossMap.rgb, texture.a * uColor.a);\n
}\n
);
using namespace Dali;
-void LookAt(Matrix& result, const Vector3& eye, const Vector3& target, const Vector3& up)
-{
- Vector3 vZ = target - eye;
- vZ.Normalize();
-
- Vector3 vX = up.Cross(vZ);
- vX.Normalize();
-
- Vector3 vY = vZ.Cross(vX);
- vY.Normalize();
-
- result.SetInverseTransformComponents(vX, vY, vZ, eye);
-}
-
-
Model3dView::Model3dView()
- : Control( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) )
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) )
{
- mTexture0Url = "";
- mTexture1Url = "";
- mTexture2Url = "";
-
mIlluminationType = Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP;
mCameraFOV = Math::PI_OVER_180 * 45.f;
}
case Toolkit::Model3dView::Property::MATERIAL_URL:
{
- if( value.Get(impl.mMaterialUrl) )
+ if( value.Get(impl.mTextureSetUrl) )
{
impl.LoadMaterial();
impl.CreateMaterial();
+ impl.LoadTextures();
}
break;
}
}
case Toolkit::Model3dView::Property::MATERIAL_URL:
{
- value = impl.mMaterialUrl;
+ value = impl.mTextureSetUrl;
break;
}
case Toolkit::Model3dView::Property::IMAGES_URL:
void Model3dView::OnStageConnection( int depth )
{
- Control::OnStageConnection( depth );
-
CustomActor self = Self();
self.AddRenderer( mRenderer );
if( mObjLoader.IsSceneLoaded() )
{
- mMesh = mObjLoader.CreateGeometry(mIlluminationType);
+ mMesh = mObjLoader.CreateGeometry( GetShaderProperties( mIlluminationType ), true );
CreateMaterial();
LoadTextures();
constraint.AddSource( Source( self, Toolkit::Model3dView::Property::LIGHT_POSITION ) );
constraint.Apply();
}
+
+ Control::OnStageConnection( depth );
}
///////////////////////////////////////////////////////////
{
//Create empty versions of the geometry and material so we always have a Renderer
Geometry mesh = Geometry::New();
- Shader shader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER, (Shader::ShaderHints)(Shader::HINT_REQUIRES_SELF_DEPTH_TEST | Shader::HINT_MODIFIES_GEOMETRY) );
- Material material = Material::New( shader );
- mRenderer = Renderer::New( mesh, material );
+ Shader shader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER );
+ mRenderer = Renderer::New( mesh, shader );
+
}
void Model3dView::LoadGeometry()
if (FileLoader::ReadFile(mObjUrl,fileSize,fileContent,FileLoader::TEXT))
{
mObjLoader.ClearArrays();
-
- std::string materialUrl;
- mObjLoader.Load(fileContent.Begin(), fileSize, materialUrl);
+ mObjLoader.LoadObject(fileContent.Begin(), fileSize);
//Get size information from the obj loaded
mSceneCenter = mObjLoader.GetCenter();
std::streampos fileSize;
Dali::Vector<char> fileContent;
- if( FileLoader::ReadFile(mMaterialUrl, fileSize, fileContent, FileLoader::TEXT) )
+ if( FileLoader::ReadFile(mTextureSetUrl, fileSize, fileContent, FileLoader::TEXT) )
{
mObjLoader.LoadMaterial(fileContent.Begin(), fileSize, mTexture0Url, mTexture1Url, mTexture2Url);
}
{
if( mObjLoader.IsSceneLoaded() )
{
- mMesh = mObjLoader.CreateGeometry(mIlluminationType);
+ mMesh = mObjLoader.CreateGeometry( GetShaderProperties( mIlluminationType ), true );
if( mRenderer )
{
mRenderer.SetGeometry( mMesh );
+ mRenderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::ON );
+ mRenderer.SetProperty( Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON );
}
}
}
void Model3dView::CreateMaterial()
{
- if( mObjLoader.IsMaterialLoaded() && (mTexture0Url != ""))
+ if( mObjLoader.IsMaterialLoaded() && (mTexture0Url != "") && mObjLoader.IsTexturePresent() )
{
- if( (mTexture2Url != "") && (mTexture1Url != "") && (mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP))
+ if( (mTexture2Url != "") && (mTexture1Url != "") && (mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP) )
{
- mShader = Shader::New( NRMMAP_VERTEX_SHADER, NRMMAP_FRAGMENT_SHADER, (Shader::ShaderHints)(Shader::HINT_REQUIRES_SELF_DEPTH_TEST | Shader::HINT_MODIFIES_GEOMETRY) );
+ mShader = Shader::New( NRMMAP_VERTEX_SHADER, NRMMAP_FRAGMENT_SHADER );
}
- else if(mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_TEXTURE)
+ else if( mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_TEXTURE ||
+ mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP )
{
- mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER, (Shader::ShaderHints)(Shader::HINT_REQUIRES_SELF_DEPTH_TEST | Shader::HINT_MODIFIES_GEOMETRY) );
+ mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
}
else
{
- mShader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER, (Shader::ShaderHints)(Shader::HINT_REQUIRES_SELF_DEPTH_TEST | Shader::HINT_MODIFIES_GEOMETRY) );
+ mShader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER );
}
}
else
{
- mShader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER, (Shader::ShaderHints)(Shader::HINT_REQUIRES_SELF_DEPTH_TEST | Shader::HINT_MODIFIES_GEOMETRY) );
+ mShader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER );
}
- mMaterial = Material::New( mShader );
-
- mMaterial.SetFaceCullingMode(Material::NONE);
+ mTextureSet = TextureSet::New();
if( mRenderer )
{
- mRenderer.SetMaterial( mMaterial );
+ mRenderer.SetTextures( mTextureSet );
+ mRenderer.SetShader( mShader );
+ mRenderer.SetProperty( Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK );
}
UpdateShaderUniforms();
void Model3dView::LoadTextures()
{
- if( !mMaterial )
- return ;
+ if( !mTextureSet )
+ {
+ return;
+ }
+
+ Sampler sampler = Sampler::New();
+ sampler.SetFilterMode( FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR_MIPMAP_LINEAR );
- if( mTexture0Url != "" )
+ // Setup diffuse texture.
+ if( !mTexture0Url.empty() && ( mIlluminationType != Toolkit::Model3dView::DIFFUSE ) )
{
- std::string imgUrl = mImagesUrl + mTexture0Url;
+ std::string imageUrl = mImagesUrl + mTexture0Url;
//Load textures
- Image tex0 = ResourceImage::New( imgUrl );
- if( tex0 )
+ Texture diffuseTexture = LoadTexture( imageUrl.c_str() );
+ if( diffuseTexture )
{
- size_t index = mMaterial.AddTexture( tex0, "sDiffuse" );
- mMaterial.SetTextureAffectsTransparency(index, false );
+ mTextureSet.SetTexture( DIFFUSE_TEXTURE_INDEX, diffuseTexture );
+ mTextureSet.SetSampler( DIFFUSE_TEXTURE_INDEX, sampler );
}
}
- if( (mTexture1Url != "") && (mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP) )
+ if( mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP )
{
- std::string imgUrl = mImagesUrl + mTexture1Url;
+ // Setup normal map texture.
+ if( !mTexture1Url.empty() )
+ {
+ std::string imageUrl = mImagesUrl + mTexture1Url;
- //Load textures
- Image tex1 = ResourceImage::New( imgUrl );
- if (tex1)
+ //Load textures
+ Texture normalTexture = LoadTexture( imageUrl.c_str() );
+ if( normalTexture )
+ {
+ mTextureSet.SetTexture( NORMAL_TEXTURE_INDEX, normalTexture );
+ mTextureSet.SetSampler( NORMAL_TEXTURE_INDEX, sampler );
+ }
+ }
+ if( !mTexture2Url.empty() )
{
- size_t index = mMaterial.AddTexture( tex1, "sNormal" );
- mMaterial.SetTextureAffectsTransparency(index, false );
+ // Setup gloss map texture.
+ std::string imageUrl = mImagesUrl + mTexture2Url;
+
+ //Load textures
+ Texture glossTexture = LoadTexture( imageUrl.c_str() );
+ if( glossTexture )
+ {
+ mTextureSet.SetTexture( GLOSS_TEXTURE_INDEX, glossTexture );
+ mTextureSet.SetSampler( GLOSS_TEXTURE_INDEX, sampler );
+ }
}
}
+}
- if( (mTexture2Url != "") && (mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP) )
+int Model3dView::GetShaderProperties( Toolkit::Model3dView::IlluminationType illuminationType )
+{
+ int objectProperties = 0;
+
+ if( illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_TEXTURE ||
+ illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP )
{
- std::string imgUrl = mImagesUrl + mTexture2Url;
+ objectProperties |= ObjLoader::TEXTURE_COORDINATES;
+ }
- //Load textures
- Image tex2 = ResourceImage::New( imgUrl );
- if( tex2 )
- {
- size_t index = mMaterial.AddTexture( tex2, "sGloss" );
- mMaterial.SetTextureAffectsTransparency(index, false );
- }
+ if( illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP )
+ {
+ objectProperties |= ObjLoader::TANGENTS | ObjLoader::BINORMALS;
}
+
+ return objectProperties;
}
} // namespace Internal