[dali_2.3.19] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / model3d-view / obj-loader.cpp
index 857032a..fe03a54 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 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 "obj-loader.h"
 
 // EXTERNAL INCLUDES
-#include <string>
-#include <sstream>
+#include <dali/integration-api/debug.h>
 #include <string.h>
+#include <sstream>
+#include <string>
 
 namespace Dali
 {
-
 namespace Toolkit
 {
-
 namespace Internal
 {
-
+namespace
+{
+const int MAX_POINT_INDICES = 4;
+}
 using namespace Dali;
 
 ObjLoader::ObjLoader()
 {
-  mSceneLoaded = false;
-  mMaterialLoaded = false;
+  mSceneLoaded      = false;
+  mMaterialLoaded   = false;
+  mHasTexturePoints = false;
+  mHasDiffuseMap    = false;
+  mHasNormalMap     = false;
+  mHasSpecularMap   = false;
   mSceneAABB.Init();
 }
 
@@ -56,102 +62,150 @@ bool ObjLoader::IsMaterialLoaded()
   return mMaterialLoaded;
 }
 
-//TODO: Use a function that can generate more than one normal/tangent per vertex (using angle)
-void ObjLoader::CalculateTangentArray(const Dali::Vector<Vector3>& vertex,
-                                      const Dali::Vector<Vector2>& texcoord,
-                                      Dali::Vector<TriIndex>& triangle,
-                                      Dali::Vector<Vector3>& normal,
-                                      Dali::Vector<Vector3>& tangent)
+void ObjLoader::CalculateHardFaceNormals(const Dali::Vector<Vector3>& vertices, Dali::Vector<TriIndex>& triangles, Dali::Vector<Vector3>& normals)
 {
-  normal.Clear();
-  normal.Resize(vertex.Size());
+  int numFaceVertices = 3 * triangles.Size(); //Vertex per face, as each point has different normals for each face.
+  int normalIndex     = 0;                    //Tracks progress through the array of normals.
 
-  Vector3 *tan1 = new Vector3[vertex.Size() * 2];
+  normals.Clear();
+  normals.Resize(numFaceVertices);
 
-  memset( tan1, 0, normal.Size() * sizeof(Vector3) * 2 );
-  memset( &normal[0], 0, normal.Size() * sizeof(Vector3) * 2 );
-
-  for ( unsigned long a = 0; a < triangle.Size(); a++ )
+  //For each triangle, calculate the normal by crossing two vectors on the triangle's plane.
+  for(unsigned long i = 0; i < triangles.Size(); i++)
   {
-    Vector3 Tangent, Bitangent, Normal;
+    //Triangle vertices.
+    const Vector3& v0 = vertices[triangles[i].pointIndex[0]];
+    const Vector3& v1 = vertices[triangles[i].pointIndex[1]];
+    const Vector3& v2 = vertices[triangles[i].pointIndex[2]];
 
-    const Vector3& v0 = vertex[triangle[a].pntIndex[0]];
-    const Vector3& v1 = vertex[triangle[a].pntIndex[1]];
-    const Vector3& v2 = vertex[triangle[a].pntIndex[2]];
+    //Triangle edges.
+    Vector3 edge1 = v1 - v0;
+    Vector3 edge2 = v2 - v0;
 
-    Vector3 Edge1 = v1 - v0;
-    Vector3 Edge2 = v2 - v0;
+    //Using edges as vectors on the plane, cross to get the normal.
+    Vector3 normalVector = edge1.Cross(edge2);
+    normalVector.Normalize();
 
-    Normal = Edge1.Cross(Edge2);
+    //Assign normals to points.
+    for(unsigned long j = 0; j < 3; j++, normalIndex++)
+    {
+      triangles[i].normalIndex[j] = normalIndex;
+      normals[normalIndex]        = normalVector;
+    }
+  }
+}
 
-    const Vector2& w0 = texcoord[triangle[a].texIndex[0]];
-    const Vector2& w1 = texcoord[triangle[a].texIndex[1]];
-    const Vector2& w2 = texcoord[triangle[a].texIndex[2]];
+void ObjLoader::CalculateSoftFaceNormals(const Dali::Vector<Vector3>& vertices, Dali::Vector<TriIndex>& triangles, Dali::Vector<Vector3>& normals)
+{
+  int normalIndex = 0; //Tracks progress through the array of normals.
 
-    float DeltaU1 = w1.x - w0.x;
-    float DeltaV1 = w1.y - w0.y;
-    float DeltaU2 = w2.x - w0.x;
-    float DeltaV2 = w2.y - w0.y;
+  normals.Clear();
+  normals.Resize(vertices.Size()); //One (averaged) normal per point.
 
-    float f = 1.0f / (DeltaU1 * DeltaV2 - DeltaU2 * DeltaV1);
+  //For each triangle, calculate the normal by crossing two vectors on the triangle's plane
+  //We then add the triangle's normal to the cumulative normals at each point of it
+  for(unsigned long i = 0; i < triangles.Size(); i++)
+  {
+    //Triangle vertices.
+    const Vector3& v0 = vertices[triangles[i].pointIndex[0]];
+    const Vector3& v1 = vertices[triangles[i].pointIndex[1]];
+    const Vector3& v2 = vertices[triangles[i].pointIndex[2]];
 
-    Tangent.x = f * ( DeltaV2 * Edge1.x - DeltaV1 * Edge2.x );
-    Tangent.y = f * ( DeltaV2 * Edge1.y - DeltaV1 * Edge2.y );
-    Tangent.z = f * ( DeltaV2 * Edge1.z - DeltaV1 * Edge2.z );
+    //Triangle edges.
+    Vector3 edge1 = v1 - v0;
+    Vector3 edge2 = v2 - v0;
 
-    tan1[triangle[a].pntIndex[0]] += Tangent;
-    tan1[triangle[a].pntIndex[1]] += Tangent;
-    tan1[triangle[a].pntIndex[2]] += Tangent;
+    //Using edges as vectors on the plane, cross to get the normal.
+    Vector3 normalVector = edge1.Cross(edge2);
 
-    normal[triangle[a].pntIndex[0]] += Normal;
-    normal[triangle[a].pntIndex[1]] += Normal;
-    normal[triangle[a].pntIndex[2]] += Normal;
+    //Add this triangle's normal to the cumulative normal of each constituent point and set the index of the normal accordingly.
+    for(unsigned long j = 0; j < 3; j++, normalIndex++)
+    {
+      triangles[i].normalIndex[j] = triangles[i].pointIndex[j]; //Normal index matches up to vertex index, as one normal per vertex.
+      normals[triangles[i].normalIndex[j]] += normalVector;
+    }
   }
 
-  for ( unsigned long a = 0; a < triangle.Size(); a++ )
+  //Normalise the normals.
+  for(unsigned long i = 0; i < normals.Size(); i++)
   {
-    for ( unsigned long j = 0; j < 3; j++ )
-    {
-      triangle[a].nrmIndex[j] = triangle[a].pntIndex[j];
-    }
+    normals[i].Normalize();
   }
+}
+
+//TODO: Use a function that can generate more than one normal/tangent per vertex (using angle)
+void ObjLoader::CalculateTangentFrame()
+{
+  //Reset tangent and bitangent vectors to hold new values.
+  mTangents.Clear();
+  mBiTangents.Clear();
+  mTangents.Resize(mPoints.Size());
+  mBiTangents.Resize(mPoints.Size());
 
-  for ( unsigned long a = 0; a < normal.Size(); a++ )
+  //For each triangle, calculate the tangent vector and then add it to the total tangent vector of each point.
+  for(unsigned long a = 0; a < mTriangles.Size(); a++)
   {
-    normal[a].Normalize();
+    Vector3 tangentVector;
 
-    const Vector3& n = normal[a];
-    const Vector3& t = tan1[a];
+    const Vector3& v0 = mPoints[mTriangles[a].pointIndex[0]];
+    const Vector3& v1 = mPoints[mTriangles[a].pointIndex[1]];
+    const Vector3& v2 = mPoints[mTriangles[a].pointIndex[2]];
 
-    // Gram-Schmidt orthogonalize
-    Vector3 calc = t - n * n.Dot(t);
-    calc.Normalize();
-    tangent[a] = Vector3( calc.x,calc.y,calc.z );
+    Vector3 edge1 = v1 - v0;
+    Vector3 edge2 = v2 - v0;
+
+    const Vector2& w0 = mTextures[mTriangles[a].textureIndex[0]];
+    const Vector2& w1 = mTextures[mTriangles[a].textureIndex[1]];
+    const Vector2& w2 = mTextures[mTriangles[a].textureIndex[2]];
+
+    float deltaU1 = w1.x - w0.x;
+    float deltaV1 = w1.y - w0.y;
+    float deltaU2 = w2.x - w0.x;
+    float deltaV2 = w2.y - w0.y;
+
+    float f = 1.0f / (deltaU1 * deltaV2 - deltaU2 * deltaV1);
+
+    tangentVector.x = f * (deltaV2 * edge1.x - deltaV1 * edge2.x);
+    tangentVector.y = f * (deltaV2 * edge1.y - deltaV1 * edge2.y);
+    tangentVector.z = f * (deltaV2 * edge1.z - deltaV1 * edge2.z);
+
+    mTangents[mTriangles[a].pointIndex[0]] += tangentVector;
+    mTangents[mTriangles[a].pointIndex[1]] += tangentVector;
+    mTangents[mTriangles[a].pointIndex[2]] += tangentVector;
   }
 
-  delete[] tan1;
-}
+  //Orthogonalize tangents and set binormals.
+  for(unsigned long a = 0; a < mTangents.Size(); a++)
+  {
+    const Vector3& n = mNormals[a];
+    const Vector3& t = mTangents[a];
+
+    // Gram-Schmidt orthogonalize
+    mTangents[a] = t - n * n.Dot(t);
+    mTangents[a].Normalize();
 
+    mBiTangents[a] = mNormals[a].Cross(mTangents[a]);
+  }
+}
 
-void ObjLoader::CenterAndScale( bool center, Dali::Vector<Vector3>& points )
+void ObjLoader::CenterAndScale(bool center, Dali::Vector<Vector3>& points)
 {
   BoundingVolume newAABB;
 
   Vector3 sceneSize = GetSize();
 
   float biggestDimension = sceneSize.x;
-  if( sceneSize.y > biggestDimension )
+  if(sceneSize.y > biggestDimension)
   {
     biggestDimension = sceneSize.y;
   }
-  if( sceneSize.z > biggestDimension )
+  if(sceneSize.z > biggestDimension)
   {
     biggestDimension = sceneSize.z;
   }
 
-
   newAABB.Init();
-  for( unsigned int ui = 0; ui < points.Size(); ++ui )
+  for(unsigned int ui = 0; ui < points.Size(); ++ui)
   {
     points[ui] = points[ui] - GetCenter();
     points[ui] = points[ui] / biggestDimension;
@@ -161,57 +215,72 @@ void ObjLoader::CenterAndScale( bool center, Dali::Vector<Vector3>& points )
   mSceneAABB = newAABB;
 }
 
-void ObjLoader::CreateGeometryArray(Dali::Vector<Vertex> & vertices,
-                                    Dali::Vector<Vector2> & textures,
-                                    Dali::Vector<VertexExt> & verticesExt,
-                                    Dali::Vector<unsigned short> & indices)
+void ObjLoader::CreateGeometryArray(Dali::Vector<Vertex>&         vertices,
+                                    Dali::Vector<Vector2>&        textures,
+                                    Dali::Vector<VertexExt>&      verticesExt,
+                                    Dali::Vector<unsigned short>& indices,
+                                    bool                          useSoftNormals)
 {
-  //If we don't have tangents, calculate them
-  //we need to recalculate the normals too, because we need just one normal,tangent, bitangent per vertex
-  //In the case of a textureless object, we don't need tangents and so we skip this step
-  //TODO: Use a better function to calculate tangents
-  if( mTangents.Size() == 0 && mHasTexture && mHasNormalMap )
+  //We must calculate the tangents and bitangents if they weren't supplied, or if they don't match up.
+  bool mustCalculateTangents = mTangents.Size() == 0 || mBiTangents.Size() == 0 ||
+                               mTangents.Size() != mBiTangents.Size() || mTangents.Size() != mNormals.Size() ||
+                               mBiTangents.Size() != mNormals.Size();
+
+  //However, we don't need to do this if the object doesn't use textures to begin with.
+  mustCalculateTangents &= mHasTexturePoints;
+
+  //We also have to recalculate the normals if we need to calculate tangents,
+  // as we need just one normal, tangent and bitangent per vertex, rather than the supplied per-face vertices.
+  //Alternatively, we need to calculate the normals if there weren't any to begin with.
+  if(mNormals.Size() == 0 || mustCalculateTangents)
   {
-    mTangents.Resize( mNormals.Size() );
-    mBiTangents.Resize( mNormals.Size() );
-    CalculateTangentArray( mPoints, mTextures, mTriangles, mNormals, mTangents );
-    for ( unsigned int ui = 0 ; ui < mNormals.Size() ; ++ui )
+    if(useSoftNormals || mustCalculateTangents)
     {
-      mBiTangents[ui] = mNormals[ui].Cross(mTangents[ui]);
+      CalculateSoftFaceNormals(mPoints, mTriangles, mNormals);
     }
+    else
+    {
+      CalculateHardFaceNormals(mPoints, mTriangles, mNormals);
+    }
+  }
+
+  //TODO: Use a better function to calculate tangents
+  if(mHasTexturePoints && mustCalculateTangents)
+  {
+    CalculateTangentFrame();
   }
 
   bool mapsCorrespond; //True if the sizes of the arrays necessary for the object agree.
 
-  if ( mHasTexture )
+  if(mHasTexturePoints)
   {
-    mapsCorrespond = ( mPoints.Size() == mTextures.Size() ) && ( mTextures.Size() == mNormals.Size() );
+    mapsCorrespond = (mPoints.Size() == mTextures.Size()) && (mTextures.Size() == mNormals.Size());
   }
   else
   {
-    mapsCorrespond = ( mPoints.Size() == mNormals.Size() );
+    mapsCorrespond = (mPoints.Size() == mNormals.Size());
   }
 
   //Check the number of points textures and normals
-  if ( mapsCorrespond )
+  if(mapsCorrespond)
   {
-    int numPoints = mPoints.Size();
+    int numPoints  = mPoints.Size();
     int numIndices = 3 * mTriangles.Size();
-    vertices.Resize( numPoints );
-    textures.Resize( numPoints );
-    verticesExt.Resize( numPoints );
-    indices.Resize( numIndices );
+    vertices.Resize(numPoints);
+    textures.Resize(numPoints);
+    verticesExt.Resize(numPoints);
+    indices.Resize(numIndices);
 
     //We create the vertices array. For now we just copy points info
-    for (unsigned int ui = 0 ; ui < mPoints.Size() ; ++ui )
+    for(unsigned int ui = 0; ui < mPoints.Size(); ++ui)
     {
       Vertex vertex;
       vertex.position = mPoints[ui];
-      vertices[ui] = vertex;
+      vertices[ui]    = vertex;
 
-      if ( mHasTexture )
+      if(mHasTexturePoints)
       {
-        textures[ui] = Vector2();
+        textures[ui]    = Vector2();
         verticesExt[ui] = VertexExt();
       }
     }
@@ -219,24 +288,20 @@ void ObjLoader::CreateGeometryArray(Dali::Vector<Vertex> & vertices,
     int indiceIndex = 0;
 
     //We copy the indices
-    for ( unsigned int ui = 0 ; ui < mTriangles.Size() ; ++ui )
+    for(unsigned int ui = 0; ui < mTriangles.Size(); ++ui)
     {
-      for ( int j = 0 ; j < 3 ; ++j )
+      for(int j = 0; j < 3; ++j)
       {
-        indices[indiceIndex] = mTriangles[ui].pntIndex[j];
+        indices[indiceIndex] = mTriangles[ui].pointIndex[j];
         indiceIndex++;
 
-        vertices[mTriangles[ui].pntIndex[j]].normal = mNormals[mTriangles[ui].nrmIndex[j]];
+        vertices[mTriangles[ui].pointIndex[j]].normal = mNormals[mTriangles[ui].normalIndex[j]];
 
-        if ( mHasTexture )
+        if(mHasTexturePoints)
         {
-          textures[mTriangles[ui].pntIndex[j]] = mTextures[mTriangles[ui].texIndex[j]];
-        }
-
-        if ( mHasNormalMap && mHasTexture )
-        {
-          verticesExt[mTriangles[ui].pntIndex[j]].tangent = mTangents[mTriangles[ui].nrmIndex[j]];
-          verticesExt[mTriangles[ui].pntIndex[j]].bitangent = mBiTangents[mTriangles[ui].nrmIndex[j]];
+          textures[mTriangles[ui].pointIndex[j]]              = mTextures[mTriangles[ui].textureIndex[j]];
+          verticesExt[mTriangles[ui].pointIndex[j]].tangent   = mTangents[mTriangles[ui].normalIndex[j]];
+          verticesExt[mTriangles[ui].pointIndex[j]].bitangent = mBiTangents[mTriangles[ui].normalIndex[j]];
         }
       }
     }
@@ -244,33 +309,29 @@ void ObjLoader::CreateGeometryArray(Dali::Vector<Vertex> & vertices,
   else
   {
     int numVertices = 3 * mTriangles.Size();
-    vertices.Resize( numVertices );
-    textures.Resize( numVertices );
-    verticesExt.Resize( numVertices );
+    vertices.Resize(numVertices);
+    textures.Resize(numVertices);
+    verticesExt.Resize(numVertices);
 
     int index = 0;
 
     //We have to normalize the arrays so we can draw we just one index array
-    for ( unsigned int ui = 0 ; ui < mTriangles.Size() ; ++ui )
+    for(unsigned int ui = 0; ui < mTriangles.Size(); ++ui)
     {
-      for ( int j = 0 ; j < 3 ; ++j )
+      for(int j = 0; j < 3; ++j)
       {
         Vertex vertex;
-        vertex.position = mPoints[mTriangles[ui].pntIndex[j]];
-        vertex.normal = mNormals[mTriangles[ui].nrmIndex[j]];
+        vertex.position = mPoints[mTriangles[ui].pointIndex[j]];
+        vertex.normal   = mNormals[mTriangles[ui].normalIndex[j]];
         vertices[index] = vertex;
 
-        if ( mHasTexture )
-        {
-          textures[index] = mTextures[mTriangles[ui].texIndex[j]];
-        }
-
-        if ( mHasNormalMap && mHasTexture )
+        if(mHasTexturePoints)
         {
+          textures[index] = mTextures[mTriangles[ui].textureIndex[j]];
           VertexExt vertexExt;
-          vertexExt.tangent = mTangents[mTriangles[ui].nrmIndex[j]];
-          vertexExt.bitangent = mBiTangents[mTriangles[ui].nrmIndex[j]];
-          verticesExt[index] = vertexExt;
+          vertexExt.tangent   = mTangents[mTriangles[ui].normalIndex[j]];
+          vertexExt.bitangent = mBiTangents[mTriangles[ui].normalIndex[j]];
+          verticesExt[index]  = vertexExt;
         }
 
         index++;
@@ -279,99 +340,95 @@ void ObjLoader::CreateGeometryArray(Dali::Vector<Vertex> & vertices,
   }
 }
 
-bool ObjLoader::Load( char* objBuffer, std::streampos fileSize, std::string& materialFile )
+bool ObjLoader::LoadObject(char* objBuffer, std::streampos fileSize)
 {
-  Vector3 point;
-  Vector2 texture;
-  std::string vet[4], name;
-  int ptIdx[4];
-  int nrmIdx[4];
-  int texIdx[4];
-  TriIndex triangle,triangle2;
-  int pntAcum = 0, texAcum = 0, nrmAcum = 0;
-  bool iniObj = false;
-  bool hasTexture = false;
-  bool hasNormalMap = false;
-  int face = 0;
+  Vector3     point;
+  Vector2     texture;
+  std::string vet[MAX_POINT_INDICES], name;
+  int         ptIdx[MAX_POINT_INDICES];
+  int         nrmIdx[MAX_POINT_INDICES];
+  int         texIdx[MAX_POINT_INDICES];
+  TriIndex    triangle, triangle2;
+  int         pntAcum = 0, texAcum = 0, nrmAcum = 0;
+  bool        iniObj     = false;
+  bool        hasTexture = false;
+  int         face       = 0;
 
   //Init AABB for the file
   mSceneAABB.Init();
 
   std::string strMatActual;
 
-  std::string input = objBuffer;
+  std::string        input(objBuffer, fileSize);
   std::istringstream ss(input);
-  ss.imbue( std::locale( "C" ) );
-
+  ss.imbue(std::locale("C"));
 
   std::string line;
-  std::getline( ss, line );
+  std::getline(ss, line);
 
-  while ( std::getline( ss, line ) )
+  while(std::getline(ss, line))
   {
-    std::istringstream isline( line, std::istringstream::in );
-    std::string tag;
+    std::istringstream isline(line, std::istringstream::in);
+    std::string        tag;
 
     isline >> tag;
 
-    if ( tag == "v" )
+    if(tag == "v")
     {
       //Two different objects in the same file
       isline >> point.x;
       isline >> point.y;
       isline >> point.z;
-      mPoints.PushBack( point );
+      mPoints.PushBack(point);
 
-      mSceneAABB.ConsiderNewPointInVolume( point );
+      mSceneAABB.ConsiderNewPointInVolume(point);
     }
-    else if ( tag == "vn" )
+    else if(tag == "vn")
     {
       isline >> point.x;
       isline >> point.y;
       isline >> point.z;
 
-      mNormals.PushBack( point );
+      mNormals.PushBack(point);
     }
-    else if ( tag == "#_#tangent" )
+    else if(tag == "#_#tangent")
     {
       isline >> point.x;
       isline >> point.y;
       isline >> point.z;
 
-      mTangents.PushBack( point );
-      hasNormalMap = true;
+      mTangents.PushBack(point);
     }
-    else if ( tag == "#_#binormal" )
+    else if(tag == "#_#binormal")
     {
       isline >> point.x;
       isline >> point.y;
       isline >> point.z;
 
-      mBiTangents.PushBack( point );
-      hasNormalMap = true;
+      mBiTangents.PushBack(point);
     }
-    else if ( tag == "vt" )
+    else if(tag == "vt")
     {
       isline >> texture.x;
       isline >> texture.y;
 
-      texture.y = 1.0-texture.y;
-      mTextures.PushBack( texture );
+      texture.y = 1.0 - texture.y;
+      mTextures.PushBack(texture);
     }
-    else if ( tag == "#_#vt1" )
+    else if(tag == "#_#vt1")
     {
       isline >> texture.x;
       isline >> texture.y;
 
-      texture.y = 1.0-texture.y;
-      mTextures2.PushBack( texture );
+      texture.y = 1.0 - texture.y;
+      mTextures2.PushBack(texture);
     }
-    else if ( tag == "s" )
+    else if(tag == "s")
     {
     }
-    else if ( tag == "f" )
+    else if(tag == "f")
     {
-      if ( !iniObj )
+      if(!iniObj)
       {
         //name assign
 
@@ -379,37 +436,57 @@ bool ObjLoader::Load( char* objBuffer, std::streampos fileSize, std::string& mat
       }
 
       int numIndices = 0;
-      while( isline >> vet[numIndices] )
+      while((numIndices < MAX_POINT_INDICES) && (isline >> vet[numIndices]))
       {
         numIndices++;
       }
 
+      //Hold slashes that separate attributes of the same point.
       char separator;
       char separator2;
 
-      if ( strstr( vet[0].c_str(),"//" ) ) //No texture coordinates.
+      const char* subString; //A pointer to the position in the string as we move through it.
+
+      subString = strstr(vet[0].c_str(), "/"); //Search for the first '/'
+
+      if(subString)
       {
-        for( int i = 0 ; i < numIndices; i++)
+        if(subString[1] == '/') // Of the form A//C, so has points and normals but no texture coordinates.
         {
-          std::istringstream isindex( vet[i] );
-          isindex >> ptIdx[i] >> separator >> separator2 >> nrmIdx[i];
-          texIdx[i] = 0;
+          for(int i = 0; i < numIndices; i++)
+          {
+            std::istringstream isindex(vet[i]);
+            isindex >> ptIdx[i] >> separator >> separator2 >> nrmIdx[i];
+            texIdx[i] = 0;
+          }
         }
-      }
-      else if ( strstr( vet[0].c_str(),"/" ) ) //Has texture coordinates, and possibly also normals.
-      {
-        for( int i = 0 ; i < numIndices; i++ )
+        else if(strstr(subString, "/")) // Of the form A/B/C, so has points, textures and normals.
+        {
+          for(int i = 0; i < numIndices; i++)
+          {
+            std::istringstream isindex(vet[i]);
+            isindex >> ptIdx[i] >> separator >> texIdx[i] >> separator2 >> nrmIdx[i];
+          }
+
+          hasTexture = true;
+        }
+        else // Of the form A/B, so has points and textures but no normals.
         {
-          std::istringstream isindex( vet[i] );
-          isindex >> ptIdx[i] >> separator >> texIdx[i] >> separator2 >> nrmIdx[i];
+          for(int i = 0; i < numIndices; i++)
+          {
+            std::istringstream isindex(vet[i]);
+            isindex >> ptIdx[i] >> separator >> texIdx[i];
+            nrmIdx[i] = 0;
+          }
+
           hasTexture = true;
         }
       }
-      else //Has just points.
+      else // Simply of the form A, as in, point indices only.
       {
-        for( int i = 0 ; i < numIndices; i++ )
+        for(int i = 0; i < numIndices; i++)
         {
-          std::istringstream isindex( vet[i] );
+          std::istringstream isindex(vet[i]);
           isindex >> ptIdx[i];
           texIdx[i] = 0;
           nrmIdx[i] = 0;
@@ -417,182 +494,178 @@ bool ObjLoader::Load( char* objBuffer, std::streampos fileSize, std::string& mat
       }
 
       //If it is a triangle
-      if( numIndices == 3 )
+      if(numIndices == 3)
       {
-        for( int i = 0 ; i < 3; i++ )
+        for(int i = 0; i < 3; i++)
         {
-          triangle.pntIndex[i] = ptIdx[i] - 1 - pntAcum;
-          triangle.nrmIndex[i] = nrmIdx[i] - 1 - nrmAcum;
-          triangle.texIndex[i] = texIdx[i] - 1 - texAcum;
+          triangle.pointIndex[i]   = ptIdx[i] - 1 - pntAcum;
+          triangle.normalIndex[i]  = nrmIdx[i] - 1 - nrmAcum;
+          triangle.textureIndex[i] = texIdx[i] - 1 - texAcum;
         }
-        mTriangles.PushBack( triangle );
+        mTriangles.PushBack(triangle);
         face++;
       }
       //If on the other hand it is a quad, we will create two triangles
-      else if( numIndices == 4 )
+      else if(numIndices == 4)
       {
-        for( int i = 0 ; i < 3; i++ )
+        for(int i = 0; i < 3; i++)
         {
-          triangle.pntIndex[i] = ptIdx[i] - 1 - pntAcum;
-          triangle.nrmIndex[i] = nrmIdx[i] - 1 - nrmAcum;
-          triangle.texIndex[i] = texIdx[i] - 1 - texAcum;
+          triangle.pointIndex[i]   = ptIdx[i] - 1 - pntAcum;
+          triangle.normalIndex[i]  = nrmIdx[i] - 1 - nrmAcum;
+          triangle.textureIndex[i] = texIdx[i] - 1 - texAcum;
         }
-        mTriangles.PushBack( triangle );
+        mTriangles.PushBack(triangle);
         face++;
 
-        for( int i = 0 ; i < 3; i++ )
+        for(int i = 0; i < 3; i++)
         {
-          int idx = ( i + 2 ) % numIndices;
-          triangle2.pntIndex[i] = ptIdx[idx] - 1 - pntAcum;
-          triangle2.nrmIndex[i] = nrmIdx[idx] - 1 - nrmAcum;
-          triangle2.texIndex[i] = texIdx[idx] - 1 - texAcum;
+          int idx                   = (i + 2) % numIndices;
+          triangle2.pointIndex[i]   = ptIdx[idx] - 1 - pntAcum;
+          triangle2.normalIndex[i]  = nrmIdx[idx] - 1 - nrmAcum;
+          triangle2.textureIndex[i] = texIdx[idx] - 1 - texAcum;
         }
-        mTriangles.PushBack( triangle2 );
+        mTriangles.PushBack(triangle2);
         face++;
       }
     }
-    else if ( tag == "usemtl" )
+    else if(tag == "usemtl")
     {
       isline >> strMatActual;
     }
-    else if ( tag == "mtllib" )
+    else if(tag == "mtllib")
     {
       isline >> strMatActual;
     }
-    else if ( tag == "g" )
+    else if(tag == "g")
     {
       isline >> name;
     }
-    else
-    {
-    }
   }
 
-  if ( iniObj )
+  if(iniObj)
   {
-    CenterAndScale( true, mPoints );
-    mSceneLoaded = true;
-    mHasTexture = hasTexture;
-    mHasNormalMap = hasNormalMap;
+    CenterAndScale(true, mPoints);
+    mSceneLoaded      = true;
+    mHasTexturePoints = hasTexture;
     return true;
   }
 
   return false;
-
 }
 
-void ObjLoader::LoadMaterial( char* objBuffer, std::streampos fileSize, std::string& texture0Url,
-                              std::string& texture1Url, std::string& texture2Url )
+void ObjLoader::LoadMaterial(char* objBuffer, std::streampos fileSize, std::string& diffuseTextureUrl, std::string& normalTextureUrl, std::string& glossTextureUrl)
 {
-  float fR,fG,fB;
+  float fR, fG, fB;
 
   std::string info;
 
-  std::string input = objBuffer;
+  std::string        input(objBuffer, fileSize);
   std::istringstream ss(input);
   ss.imbue(std::locale("C"));
 
   std::string line;
-  std::getline( ss, line );
+  std::getline(ss, line);
 
-  while ( std::getline( ss, line ) )
+  while(std::getline(ss, line))
   {
-    std::istringstream isline( line, std::istringstream::in );
-    std::string tag;
+    std::istringstream isline(line, std::istringstream::in);
+    std::string        tag;
 
     isline >> tag;
 
-    if ( tag == "newmtl" )  //name of the material
+    if(tag == "newmtl") //name of the material
     {
       isline >> info;
     }
-    else if ( tag == "Kd" ) //diffuse color
+    else if(tag == "Ka") //ambient color
     {
       isline >> fR >> fG >> fB;
     }
-    else if ( tag == "Kd" ) //Ambient color
+    else if(tag == "Kd") //diffuse color
     {
       isline >> fR >> fG >> fB;
     }
-    else if ( tag == "Tf" ) //color
+    else if(tag == "Ks") //specular color
     {
+      isline >> fR >> fG >> fB;
     }
-    else if ( tag == "Ni" )
+    else if(tag == "Tf") //color
     {
     }
-    else if ( tag == "map_Kd" )
+    else if(tag == "Ni")
+    {
+    }
+    else if(tag == "map_Kd")
     {
       isline >> info;
-      texture0Url = info;
+      diffuseTextureUrl = info;
+      mHasDiffuseMap    = true;
     }
-    else if ( tag == "bump" )
+    else if(tag == "bump")
     {
       isline >> info;
-      texture1Url = info;
-      mHasNormalMap = true;
+      normalTextureUrl = info;
+      mHasNormalMap    = true;
     }
-    else if ( tag == "map_Ks" )
+    else if(tag == "map_Ks")
     {
       isline >> info;
-      texture2Url = info;
+      glossTextureUrl = info;
+      mHasSpecularMap = true;
     }
   }
 
   mMaterialLoaded = true;
 }
 
-Geometry ObjLoader::CreateGeometry( Toolkit::Model3dView::IlluminationType illuminationType )
+Geometry ObjLoader::CreateGeometry(int objectProperties, bool useSoftNormals)
 {
-  Dali::Vector<Vertex> vertices;
-  Dali::Vector<Vector2> textures;
-  Dali::Vector<VertexExt> verticesExt;
+  Geometry surface = Geometry::New();
+
+  Dali::Vector<Vertex>         vertices;
+  Dali::Vector<Vector2>        textures;
+  Dali::Vector<VertexExt>      verticesExt;
   Dali::Vector<unsigned short> indices;
 
-  CreateGeometryArray( vertices, textures, verticesExt, indices );
+  CreateGeometryArray(vertices, textures, verticesExt, indices, useSoftNormals);
 
   //All vertices need at least Position and Normal
   Property::Map vertexFormat;
-  vertexFormat["aPosition"] = Property::VECTOR3;
-  vertexFormat["aNormal"] = Property::VECTOR3;
-  PropertyBuffer surfaceVertices = PropertyBuffer::New( vertexFormat );
-  surfaceVertices.SetData( &vertices[0], vertices.Size() );
-
-  Geometry surface = Geometry::New();
-  surface.AddVertexBuffer( surfaceVertices );
+  vertexFormat["aPosition"]    = Property::VECTOR3;
+  vertexFormat["aNormal"]      = Property::VECTOR3;
+  VertexBuffer surfaceVertices = VertexBuffer::New(vertexFormat);
+  surfaceVertices.SetData(&vertices[0], vertices.Size());
+  surface.AddVertexBuffer(surfaceVertices);
 
   //Some need texture coordinates
-  if( ( (illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP ) ||
-        (illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_TEXTURE ) ) && mHasTexture )
+  if((objectProperties & TEXTURE_COORDINATES) && mHasTexturePoints && mHasDiffuseMap)
   {
     Property::Map textureFormat;
     textureFormat["aTexCoord"] = Property::VECTOR2;
-    PropertyBuffer extraVertices = PropertyBuffer::New( textureFormat );
-    extraVertices.SetData( &textures[0], textures.Size() );
+    VertexBuffer extraVertices = VertexBuffer::New(textureFormat);
+    extraVertices.SetData(&textures[0], textures.Size());
 
-    surface.AddVertexBuffer( extraVertices );
+    surface.AddVertexBuffer(extraVertices);
   }
 
   //Some need tangent and bitangent
-  if( illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP && mHasNormalMap && mHasTexture )
+  if((objectProperties & TANGENTS) && (objectProperties & BINORMALS) && mHasTexturePoints)
   {
     Property::Map vertexExtFormat;
-    vertexExtFormat["aTangent"] = Property::VECTOR3;
+    vertexExtFormat["aTangent"]  = Property::VECTOR3;
     vertexExtFormat["aBiNormal"] = Property::VECTOR3;
-    PropertyBuffer extraVertices = PropertyBuffer::New( vertexExtFormat );
-    extraVertices.SetData( &verticesExt[0], verticesExt.Size() );
+    VertexBuffer extraVertices   = VertexBuffer::New(vertexExtFormat);
+    extraVertices.SetData(&verticesExt[0], verticesExt.Size());
 
-    surface.AddVertexBuffer( extraVertices );
+    surface.AddVertexBuffer(extraVertices);
   }
 
-  if ( indices.Size() )
+  //If indices are required, we set them.
+  if(indices.Size())
   {
-    surface.SetIndexBuffer ( &indices[0], indices.Size() );
+    surface.SetIndexBuffer(&indices[0], indices.Size());
   }
 
-  vertices.Clear();
-  verticesExt.Clear();
-  indices.Clear();
-
   return surface;
 }
 
@@ -623,7 +696,12 @@ void ObjLoader::ClearArrays()
 
 bool ObjLoader::IsTexturePresent()
 {
-  return mHasTexture;
+  return mHasTexturePoints;
+}
+
+bool ObjLoader::IsDiffuseMapPresent()
+{
+  return mHasDiffuseMap;
 }
 
 bool ObjLoader::IsNormalMapPresent()
@@ -631,6 +709,11 @@ bool ObjLoader::IsNormalMapPresent()
   return mHasNormalMap;
 }
 
+bool ObjLoader::IsSpecularMapPresent()
+{
+  return mHasSpecularMap;
+}
+
 } // namespace Internal
 } // namespace Toolkit
 } // namespace Dali