Merge "Fix various Klocwork errors" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / model3d-view / obj-loader.cpp
1 /*
2  * Copyright (c) 2015 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 "obj-loader.h"
20
21 // EXTERNAL INCLUDES
22 #include <string>
23 #include <sstream>
24 #include <string.h>
25
26 namespace Dali
27 {
28
29 namespace Toolkit
30 {
31
32 namespace Internal
33 {
34
35 using namespace Dali;
36
37 ObjLoader::ObjLoader()
38 {
39   mSceneLoaded = false;
40   mMaterialLoaded = false;
41   mSceneAABB.Init();
42 }
43
44 ObjLoader::~ObjLoader()
45 {
46   ClearArrays();
47 }
48
49 bool ObjLoader::IsSceneLoaded()
50 {
51   return mSceneLoaded;
52 }
53
54 bool ObjLoader::IsMaterialLoaded()
55 {
56   return mMaterialLoaded;
57 }
58
59 //TODO: Use a function that can generate more than one normal/tangent per vertex (using angle)
60 void ObjLoader::CalculateTangentArray(const Dali::Vector<Vector3>& vertex,
61                                       const Dali::Vector<Vector2>& texcoord,
62                                       Dali::Vector<TriIndex>& triangle,
63                                       Dali::Vector<Vector3>& normal,
64                                       Dali::Vector<Vector3>& tangent)
65 {
66   normal.Clear();
67   normal.Resize(vertex.Size());
68
69   Vector3 *tan1 = new Vector3[vertex.Size() * 2];
70
71   memset(tan1, 0, normal.Size() * sizeof(Vector3) * 2);
72   memset(&normal[0], 0, normal.Size() * sizeof(Vector3) * 2);
73
74   for (unsigned long a = 0; a < triangle.Size(); a++)
75   {
76     Vector3 Tangent, Bitangent, Normal;
77
78     const Vector3& v0 = vertex[triangle[a].pntIndex[0]];
79     const Vector3& v1 = vertex[triangle[a].pntIndex[1]];
80     const Vector3& v2 = vertex[triangle[a].pntIndex[2]];
81
82     Vector3 Edge1 = v1 - v0;
83     Vector3 Edge2 = v2 - v0;
84
85     Normal = Edge1.Cross(Edge2);
86
87     const Vector2& w0 = texcoord[triangle[a].texIndex[0]];
88     const Vector2& w1 = texcoord[triangle[a].texIndex[1]];
89     const Vector2& w2 = texcoord[triangle[a].texIndex[2]];
90
91     float DeltaU1 = w1.x - w0.x;
92     float DeltaV1 = w1.y - w0.y;
93     float DeltaU2 = w2.x - w0.x;
94     float DeltaV2 = w2.y - w0.y;
95
96     float f = 1.0f / (DeltaU1 * DeltaV2 - DeltaU2 * DeltaV1);
97
98     Tangent.x = f * (DeltaV2 * Edge1.x - DeltaV1 * Edge2.x);
99     Tangent.y = f * (DeltaV2 * Edge1.y - DeltaV1 * Edge2.y);
100     Tangent.z = f * (DeltaV2 * Edge1.z - DeltaV1 * Edge2.z);
101
102     tan1[triangle[a].pntIndex[0]] += Tangent;
103     tan1[triangle[a].pntIndex[1]] += Tangent;
104     tan1[triangle[a].pntIndex[2]] += Tangent;
105
106     normal[triangle[a].pntIndex[0]] += Normal;
107     normal[triangle[a].pntIndex[1]] += Normal;
108     normal[triangle[a].pntIndex[2]] += Normal;
109   }
110
111   for (unsigned long a = 0; a < triangle.Size(); a++)
112   {
113     for (unsigned long j = 0; j < 3; j++)
114     {
115       triangle[a].nrmIndex[j] = triangle[a].pntIndex[j];
116     }
117   }
118
119   for (unsigned long a = 0; a < normal.Size(); a++)
120   {
121     normal[a].Normalize();
122
123     const Vector3& n = normal[a];
124     const Vector3& t = tan1[a];
125
126     // Gram-Schmidt orthogonalize
127     Vector3 calc = t - n * n.Dot(t);
128     calc.Normalize();
129     tangent[a] = Vector3(calc.x,calc.y,calc.z);
130   }
131
132   delete[] tan1;
133 }
134
135
136 void ObjLoader::CenterAndScale(bool center, Dali::Vector<Vector3>& points)
137 {
138   BoundingVolume newAABB;
139
140   Vector3 sceneSize = GetSize();
141
142   float biggestDimension = sceneSize.x;
143   if( sceneSize.y > biggestDimension )
144   {
145     biggestDimension = sceneSize.y;
146   }
147   if( sceneSize.z > biggestDimension )
148   {
149     biggestDimension = sceneSize.z;
150   }
151
152
153   newAABB.Init();
154   for( unsigned int ui = 0; ui < points.Size(); ++ui)
155   {
156     points[ui] = points[ui] - GetCenter();
157     points[ui] = points[ui] / biggestDimension;
158     newAABB.ConsiderNewPointInVolume(points[ui]);
159   }
160
161   mSceneAABB = newAABB;
162 }
163
164 void ObjLoader::CreateGeometryArray(Dali::Vector<Vertex> & vertices,
165                                     Dali::Vector<Vector2> & textures,
166                                     Dali::Vector<VertexExt> & verticesExt,
167                                     Dali::Vector<int> & indices)
168 {
169   //If we don't have tangents, calculate them
170   //we need to recalculate the normals too, because we need just one normal,tangent, bitangent per vertex
171   //TODO: Use a better function to calculate tangents
172   if( mTangents.Size() == 0 )
173   {
174     mTangents.Resize(mNormals.Size());
175     mBiTangents.Resize(mNormals.Size());
176     CalculateTangentArray(mPoints, mTextures, mTriangles, mNormals, mTangents);
177     for (unsigned int ui = 0 ; ui < mNormals.Size() ; ++ui )
178     {
179       mBiTangents[ui] = mNormals[ui].Cross(mTangents[ui]);
180     }
181   }
182
183   //Check the number of points textures and normals
184   if ((mPoints.Size() == mTextures.Size()) && (mTextures.Size() == mNormals.Size()))
185   {
186     //We create the vertices array. For now we just copy points info
187     for (unsigned int ui = 0 ; ui < mPoints.Size() ; ++ui )
188     {
189       Vertex vertex;
190       vertex.position = mPoints[ui];
191       vertices.PushBack(vertex);
192
193       textures.PushBack(Vector2());
194       verticesExt.PushBack(VertexExt());
195     }
196
197     //We copy the indices
198     for (unsigned int ui = 0 ; ui < mTriangles.Size() ; ++ui )
199     {
200       for (int j = 0 ; j < 3 ; ++j)
201       {
202         indices.PushBack(mTriangles[ui].pntIndex[j]);
203
204         vertices[mTriangles[ui].pntIndex[j]].normal = mNormals[mTriangles[ui].nrmIndex[j]];
205
206         textures[mTriangles[ui].pntIndex[j]] = mTextures[mTriangles[ui].texIndex[j]];
207
208         verticesExt[mTriangles[ui].pntIndex[j]].tangent = mTangents[mTriangles[ui].nrmIndex[j]];
209         verticesExt[mTriangles[ui].pntIndex[j]].bitangent = mBiTangents[mTriangles[ui].nrmIndex[j]];
210       }
211     }
212   }
213   else
214   {
215     //We have to normalize the arrays so we can draw we just one index array
216     for (unsigned int ui = 0 ; ui < mTriangles.Size() ; ++ui )
217     {
218       for (int j = 0 ; j < 3 ; ++j)
219       {
220         Vertex vertex;
221         vertex.position = mPoints[mTriangles[ui].pntIndex[j]];
222         vertex.normal = mNormals[mTriangles[ui].nrmIndex[j]];
223         vertices.PushBack(vertex);
224
225         textures.PushBack(mTextures[mTriangles[ui].texIndex[j]]);
226
227         VertexExt vertexExt;
228         vertexExt.tangent = mTangents[mTriangles[ui].nrmIndex[j]];
229         vertexExt.bitangent = mBiTangents[mTriangles[ui].nrmIndex[j]];
230         verticesExt.PushBack(vertexExt);
231       }
232     }
233   }
234 }
235
236 bool ObjLoader::Load(char* objBuffer, std::streampos fileSize, std::string& materialFile)
237 {
238   Vector3 point;
239   Vector2 texture;
240   std::string vet[4], name;
241   int ptIdx[4];
242   int nrmIdx[4];
243   int texIdx[4];
244   TriIndex triangle,triangle2;
245   int pntAcum = 0, texAcum = 0, nrmAcum = 0;
246   bool iniObj = false;
247   int face = 0;
248
249   //Init AABB for the file
250   mSceneAABB.Init();
251
252   std::string strMatActual;
253
254   std::string input = objBuffer;
255   std::istringstream ss(input);
256   ss.imbue(std::locale("C"));
257
258
259   std::string line;
260   std::getline(ss, line);
261
262   while (std::getline(ss, line))
263   {
264     std::istringstream isline(line, std::istringstream::in);
265     std::string tag;
266
267     isline >> tag;
268
269     if (tag == "v")
270     {
271       //Two different objects in the same file
272       isline >> point.x;
273       isline >> point.y;
274       isline >> point.z;
275       mPoints.PushBack(point);
276
277       mSceneAABB.ConsiderNewPointInVolume(point);
278     }
279     else if (tag == "vn")
280     {
281       isline >> point.x;
282       isline >> point.y;
283       isline >> point.z;
284
285       mNormals.PushBack(point);
286     }
287     else if (tag == "#_#tangent")
288     {
289       isline >> point.x;
290       isline >> point.y;
291       isline >> point.z;
292
293       mTangents.PushBack(point);
294     }
295     else if (tag == "#_#binormal")
296     {
297       isline >> point.x;
298       isline >> point.y;
299       isline >> point.z;
300
301       mBiTangents.PushBack(point);
302     }
303     else if (tag == "vt")
304     {
305       isline >> texture.x;
306       isline >> texture.y;
307
308       texture.y = 1.0-texture.y;
309       mTextures.PushBack(texture);
310     }
311     else if (tag == "#_#vt1")
312     {
313       isline >> texture.x;
314       isline >> texture.y;
315
316       texture.y = 1.0-texture.y;
317       mTextures2.PushBack(texture);
318     }
319     else if (tag == "s")
320     {
321     }
322     else if (tag == "f")
323     {
324       if (!iniObj)
325       {
326         //name assign
327
328         iniObj = true;
329       }
330
331       int numIndices = 0;
332       while( isline >> vet[numIndices] )
333       {
334         numIndices++;
335       }
336
337       char separator;
338       char separator2;
339       //File could not have texture Coordinates
340       if (strstr(vet[0].c_str(),"//"))
341       {
342         for( int i = 0 ; i < numIndices; i++)
343         {
344           std::istringstream isindex(vet[i]);
345           isindex >> ptIdx[i] >> separator >> nrmIdx[i];
346           texIdx[i] = 0;
347         }
348       }
349       else if (strstr(vet[0].c_str(),"/"))
350       {
351         for( int i = 0 ; i < numIndices; i++)
352         {
353           std::istringstream isindex(vet[i]);
354           isindex >> ptIdx[i] >> separator >> texIdx[i] >> separator2 >> nrmIdx[i];
355         }
356       }
357       else
358       {
359         for( int i = 0 ; i < numIndices; i++)
360         {
361           std::istringstream isindex(vet[i]);
362           isindex >> ptIdx[i];
363           texIdx[i] = 0;
364           nrmIdx[i] = 0;
365         }
366       }
367
368       //If it is a triangle
369       if( numIndices == 3 )
370       {
371         for( int i = 0 ; i < 3; i++)
372         {
373           triangle.pntIndex[i] = ptIdx[i] - 1 - pntAcum;
374           triangle.nrmIndex[i] = nrmIdx[i] - 1 - nrmAcum;
375           triangle.texIndex[i] = texIdx[i] - 1 - texAcum;
376         }
377         mTriangles.PushBack(triangle);
378         face++;
379       }
380       //If on the other hand it is a quad, we will create two triangles
381       else if( numIndices == 4 )
382       {
383         for( int i = 0 ; i < 3; i++)
384         {
385           triangle.pntIndex[i] = ptIdx[i] - 1 - pntAcum;
386           triangle.nrmIndex[i] = nrmIdx[i] - 1 - nrmAcum;
387           triangle.texIndex[i] = texIdx[i] - 1 - texAcum;
388         }
389         mTriangles.PushBack(triangle);
390         face++;
391
392         for( int i = 0 ; i < 3; i++)
393         {
394           int idx = (i+2) % numIndices;
395           triangle2.pntIndex[i] = ptIdx[idx] - 1 - pntAcum;
396           triangle2.nrmIndex[i] = nrmIdx[idx] - 1 - nrmAcum;
397           triangle2.texIndex[i] = texIdx[idx] - 1 - texAcum;
398         }
399         mTriangles.PushBack(triangle2);
400         face++;
401       }
402     }
403     else if (tag == "usemtl")
404     {
405       isline >> strMatActual;
406     }
407     else if (tag == "mtllib")
408     {
409       isline >> strMatActual;
410     }
411     else if (tag == "g")
412     {
413       isline >> name;
414     }
415     else
416     {
417     }
418   }
419
420   if (iniObj)
421   {
422     CenterAndScale(true, mPoints);
423     mSceneLoaded = true;
424     return true;
425   }
426
427   return false;
428
429 }
430
431 void ObjLoader::LoadMaterial(char* objBuffer, std::streampos fileSize, std::string& texture0Url, std::string& texture1Url, std::string& texture2Url)
432 {
433   float fR,fG,fB;
434
435   std::string info;
436
437   std::string input = objBuffer;
438   std::istringstream ss(input);
439   ss.imbue(std::locale("C"));
440
441   std::string line;
442   std::getline(ss, line);
443
444   while (std::getline(ss, line))
445   {
446     std::istringstream isline(line, std::istringstream::in);
447     std::string tag;
448
449     isline >> tag;
450
451     if (tag == "newmtl")  //name of the material
452     {
453       isline >> info;
454     }
455     else if (tag == "Kd") //diffuse color
456     {
457       isline >> fR >> fG >> fB;
458     }
459     else if (tag == "Kd") //Ambient color
460     {
461       isline >> fR >> fG >> fB;
462     }
463     else if (tag == "Tf") //color
464     {
465     }
466     else if (tag == "Ni")
467     {
468     }
469     else if (tag == "map_Kd")
470     {
471       isline >> info;
472       texture0Url = info;
473     }
474     else if (tag == "bump")
475     {
476       isline >> info;
477       texture1Url = info;
478     }
479     else if (tag == "map_Ks")
480     {
481       isline >> info;
482       texture2Url = info;
483     }
484   }
485
486   mMaterialLoaded = true;
487 }
488
489 Geometry ObjLoader::CreateGeometry(Toolkit::Model3dView::IlluminationType illuminationType)
490 {
491   Dali::Vector<Vertex> vertices;
492   Dali::Vector<Vector2> textures;
493   Dali::Vector<VertexExt> verticesExt;
494   Dali::Vector<int> indices;
495
496   CreateGeometryArray(vertices, textures, verticesExt, indices);
497
498   //All vertices need at least Position and Normal
499   Property::Map vertexFormat;
500   vertexFormat["aPosition"] = Property::VECTOR3;
501   vertexFormat["aNormal"] = Property::VECTOR3;
502   PropertyBuffer surfaceVertices = PropertyBuffer::New( vertexFormat, vertices.Size() );
503   surfaceVertices.SetData( &vertices[0] );
504
505   Geometry surface = Geometry::New();
506   surface.AddVertexBuffer( surfaceVertices );
507
508   //Some need texture coordinates
509   if( (illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP ) || (illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_TEXTURE ) )
510   {
511     Property::Map textureFormat;
512     textureFormat["aTexCoord"] = Property::VECTOR2;
513     PropertyBuffer extraVertices = PropertyBuffer::New( textureFormat, textures.Size() );
514     extraVertices.SetData( &textures[0] );
515
516     surface.AddVertexBuffer( extraVertices );
517   }
518
519   //Some need tangent and bitangent
520   if( illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP )
521   {
522     Property::Map vertexExtFormat;
523     vertexExtFormat["aTangent"] = Property::VECTOR3;
524     vertexExtFormat["aBiNormal"] = Property::VECTOR3;
525     PropertyBuffer extraVertices = PropertyBuffer::New( vertexExtFormat, verticesExt.Size() );
526     extraVertices.SetData( &verticesExt[0] );
527
528     surface.AddVertexBuffer( extraVertices );
529   }
530
531   if (indices.Size())
532   {
533     //Indices
534     Property::Map indicesVertexFormat;
535     indicesVertexFormat["aIndices"] = Property::INTEGER;
536     PropertyBuffer indicesToVertices = PropertyBuffer::New( indicesVertexFormat, indices.Size() );
537     indicesToVertices.SetData(&indices[0]);
538
539     surface.SetIndexBuffer ( indicesToVertices );
540   }
541
542   surface.SetRequiresDepthTesting(true);
543
544   vertices.Clear();
545   verticesExt.Clear();
546   indices.Clear();
547
548   return surface;
549 }
550
551 Vector3 ObjLoader::GetCenter()
552 {
553   Vector3 center = GetSize() * 0.5 + mSceneAABB.pointMin;
554   return center;
555 }
556
557 Vector3 ObjLoader::GetSize()
558 {
559   Vector3 size = mSceneAABB.pointMax - mSceneAABB.pointMin;
560   return size;
561 }
562
563 void ObjLoader::ClearArrays()
564 {
565   mPoints.Clear();
566   mTextures.Clear();
567   mNormals.Clear();
568   mTangents.Clear();
569   mBiTangents.Clear();
570
571   mTriangles.Clear();
572
573   mSceneLoaded = false;
574 }
575
576 } // namespace Internal
577 } // namespace Toolkit
578 } // namespace Dali