[dali_1.1.8] Merge branch '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     pntAcum += (int)mPoints.Size();
423     texAcum += (int)mTextures.Size();
424     nrmAcum += (int)mNormals.Size();
425
426     CenterAndScale(true, mPoints);
427
428     face = 0;
429
430     mSceneLoaded = true;
431
432     return true;
433   }
434
435   return false;
436
437 }
438
439 void ObjLoader::LoadMaterial(char* objBuffer, std::streampos fileSize, std::string& texture0Url, std::string& texture1Url, std::string& texture2Url)
440 {
441   float fR,fG,fB;
442
443   std::string info;
444
445   std::string input = objBuffer;
446   std::istringstream ss(input);
447   ss.imbue(std::locale("C"));
448
449   std::string line;
450   std::getline(ss, line);
451
452   while (std::getline(ss, line))
453   {
454     std::istringstream isline(line, std::istringstream::in);
455     std::string tag;
456
457     isline >> tag;
458
459     if (tag == "newmtl")  //name of the material
460     {
461       isline >> info;
462     }
463     else if (tag == "Kd") //diffuse color
464     {
465       isline >> fR >> fG >> fB;
466     }
467     else if (tag == "Kd") //Ambient color
468     {
469       isline >> fR >> fG >> fB;
470     }
471     else if (tag == "Tf") //color
472     {
473     }
474     else if (tag == "Ni")
475     {
476     }
477     else if (tag == "map_Kd")
478     {
479       isline >> info;
480       texture0Url = info;
481     }
482     else if (tag == "bump")
483     {
484       isline >> info;
485       texture1Url = info;
486     }
487     else if (tag == "map_Ks")
488     {
489       isline >> info;
490       texture2Url = info;
491     }
492   }
493
494   mMaterialLoaded = true;
495 }
496
497 Geometry ObjLoader::CreateGeometry(Toolkit::Model3dView::IlluminationType illuminationType)
498 {
499   Dali::Vector<Vertex> vertices;
500   Dali::Vector<Vector2> textures;
501   Dali::Vector<VertexExt> verticesExt;
502   Dali::Vector<int> indices;
503
504   CreateGeometryArray(vertices, textures, verticesExt, indices);
505
506   //All vertices need at least Position and Normal
507   Property::Map vertexFormat;
508   vertexFormat["aPosition"] = Property::VECTOR3;
509   vertexFormat["aNormal"] = Property::VECTOR3;
510   PropertyBuffer surfaceVertices = PropertyBuffer::New( vertexFormat, vertices.Size() );
511   surfaceVertices.SetData( &vertices[0] );
512
513   Geometry surface = Geometry::New();
514   surface.AddVertexBuffer( surfaceVertices );
515
516   //Some need texture coordinates
517   if( (illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP ) || (illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_TEXTURE ) )
518   {
519     Property::Map textureFormat;
520     textureFormat["aTexCoord"] = Property::VECTOR2;
521     PropertyBuffer extraVertices = PropertyBuffer::New( textureFormat, textures.Size() );
522     extraVertices.SetData( &textures[0] );
523
524     surface.AddVertexBuffer( extraVertices );
525   }
526
527   //Some need tangent and bitangent
528   if( illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP )
529   {
530     Property::Map vertexExtFormat;
531     vertexExtFormat["aTangent"] = Property::VECTOR3;
532     vertexExtFormat["aBiNormal"] = Property::VECTOR3;
533     PropertyBuffer extraVertices = PropertyBuffer::New( vertexExtFormat, verticesExt.Size() );
534     extraVertices.SetData( &verticesExt[0] );
535
536     surface.AddVertexBuffer( extraVertices );
537   }
538
539   if (indices.Size())
540   {
541     //Indices
542     Property::Map indicesVertexFormat;
543     indicesVertexFormat["aIndices"] = Property::INTEGER;
544     PropertyBuffer indicesToVertices = PropertyBuffer::New( indicesVertexFormat, indices.Size() );
545     indicesToVertices.SetData(&indices[0]);
546
547     surface.SetIndexBuffer ( indicesToVertices );
548   }
549
550   surface.SetRequiresDepthTesting(true);
551   //surface.SetProperty(Geometry::Property::GEOMETRY_HALF_EXTENTS, GetSize() * 0.5);
552
553   vertices.Clear();
554   verticesExt.Clear();
555   indices.Clear();
556
557   return surface;
558 }
559
560 Vector3 ObjLoader::GetCenter()
561 {
562   Vector3 center = GetSize() * 0.5 + mSceneAABB.pointMin;
563   return center;
564 }
565
566 Vector3 ObjLoader::GetSize()
567 {
568   Vector3 size = mSceneAABB.pointMax - mSceneAABB.pointMin;
569   return size;
570 }
571
572 void ObjLoader::ClearArrays()
573 {
574   mPoints.Clear();
575   mTextures.Clear();
576   mNormals.Clear();
577   mTangents.Clear();
578   mBiTangents.Clear();
579
580   mTriangles.Clear();
581
582   mSceneLoaded = false;
583 }
584
585 } // namespace Internal
586 } // namespace Toolkit
587 } // namespace Dali