soc-2008-mxcurioni: first version of lib3ds code. It does NOT work yet and has to...
[blender.git] / source / blender / freestyle / intern / scene_graph / MaxFileLoader.cpp
1
2 //
3 //  Copyright (C) : Please refer to the COPYRIGHT file distributed 
4 //   with this source distribution. 
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 2
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 //
20 ///////////////////////////////////////////////////////////////////////////////
21
22 #include "MaxFileLoader.h"
23
24 MaxFileLoader::MaxFileLoader()
25 {
26   _FileName = NULL;
27   _3dsFile = NULL;
28   _Scene = NULL;
29   _numFacesRead = 0;
30   _minEdgeSize = DBL_MAX;
31 }
32
33 MaxFileLoader::MaxFileLoader(const char *iFileName)
34 {
35   _FileName = new char[strlen(iFileName)+1];
36   strcpy(_FileName, iFileName);
37
38   _3dsFile = NULL;
39   _Scene = NULL;
40   _numFacesRead = 0;
41   _minEdgeSize = DBL_MAX;
42 }
43
44 MaxFileLoader::~MaxFileLoader()
45 {
46   if(NULL != _FileName)
47   {
48     delete [] _FileName;
49     _FileName = NULL;
50   }
51
52   if(NULL != _3dsFile)
53   {
54     lib3ds_file_free(_3dsFile);
55     _3dsFile = NULL;
56   }
57
58   _Scene = NULL;
59 }
60
61 void MaxFileLoader::setFileName(const char *iFileName)
62 {
63   if(NULL != _FileName)
64     delete [] _FileName;
65
66   _FileName = new char[strlen(iFileName)+1];
67   strcpy(_FileName, iFileName);
68 }
69
70 NodeGroup* MaxFileLoader::Load()
71 {
72   _3dsFile=lib3ds_file_load(_FileName);
73   if(NULL == _3dsFile)
74     return NULL;
75
76         /* No nodes?  Fabricate nodes to display all the meshes. */
77   if( !_3dsFile->nodes )
78   {
79     Lib3dsMesh *mesh;
80     Lib3dsNode *node;
81
82     for(mesh = _3dsFile->meshes; mesh != NULL; mesh = mesh->next)
83     {
84       node = lib3ds_node_new_object();
85       strcpy(node->name, mesh->name);
86       node->parent_id = LIB3DS_NO_PARENT;
87       node->data.object.scl_track.keyL = lib3ds_lin3_key_new();
88       node->data.object.scl_track.keyL->value[0] = 1.;
89       node->data.object.scl_track.keyL->value[1] = 1.;
90       node->data.object.scl_track.keyL->value[2] = 1.;
91       lib3ds_file_insert_node(_3dsFile, node);
92     }
93   }
94
95   lib3ds_file_eval(_3dsFile, 0);
96   
97   // creation of the scene root node
98   _Scene = new NodeGroup;
99
100   // converts the 3ds format to the scene format
101   // the RenderNode method modifies _Scene.
102   Lib3dsNode *p;
103   for (p=_3dsFile->nodes; p!=0; p=p->next) {
104     RenderNode(p);
105   }
106   //Returns the built scene.
107   return _Scene;
108 }
109
110 void lib3ds_normal_transform(Lib3dsVector c, Lib3dsMatrix m, Lib3dsVector a)
111 {
112   c[0]= (m[0][0]*a[0] + m[1][0]*a[1] + m[2][0]*a[2]);
113   c[1]= (m[0][1]*a[0] + m[1][1]*a[1] + m[2][1]*a[2]);
114   c[2]= (m[0][2]*a[0] + m[1][2]*a[1] + m[2][2]*a[2]);
115
116   //  c[0]= (m[0][0]*a[0] + m[1][0]*a[1] + m[2][0]*a[2])/m[0][0];
117   //  c[1]= (m[0][1]*a[0] + m[1][1]*a[1] + m[2][1]*a[2])/m[1][1];
118   //  c[2]= (m[0][2]*a[0] + m[1][2]*a[1] + m[2][2]*a[2])/m[2][2];
119
120   //lib3ds_vector_normalize(c);
121
122   //  c[0] = c[0]*m[0][0];
123   //  c[1] = c[1]*m[1][1];
124   //  c[2] = c[2]*m[2][2];
125
126 }
127
128
129
130 void MaxFileLoader::RenderNode(Lib3dsNode *iNode)
131 {
132   Lib3dsNode *p;
133   for (p=iNode->childs; p!=0; p=p->next) 
134     RenderNode(p);
135
136   float minBBox[3];
137   float maxBBox[3];
138   if (iNode->type==LIB3DS_OBJECT_NODE) 
139   {
140     if (strcmp(iNode->name,"$$$DUMMY")==0) 
141       return;
142
143     NodeTransform *currentMesh = new NodeTransform;
144     NodeShape * shape;
145     
146     if (!iNode->user.d) // If the shape is not built yet, just do it !
147     {
148       Lib3dsMesh *mesh=lib3ds_file_mesh_by_name(_3dsFile, iNode->name);
149       ASSERT(mesh);
150       if (!mesh) 
151         return;
152
153       // builds the shape:
154       shape = new NodeShape;
155       iNode->user.d=(unsigned long)shape; // We store as user data the NodeShape address
156
157       // We invert the matrix in order to 
158       // be able to retrieve the shape's coordinates 
159       // in its local coordinates system (origin is the iNode pivot)
160       Lib3dsMatrix M;
161       lib3ds_matrix_copy(M, mesh->matrix);
162       lib3ds_matrix_inv(M);
163       
164       // We compute a normal per vertex and manages the smoothing of the shape:
165       Lib3dsVector *normalL=(Lib3dsVector*)malloc(3*sizeof(Lib3dsVector)*mesh->faces);
166       lib3ds_mesh_calculate_normals(mesh, normalL);
167
168       // We build the rep:
169       IndexedFaceSet *rep;
170       unsigned numFaces = mesh->faces;
171       
172       unsigned vSize = 3*3*numFaces;
173       float *vertices = new float[vSize];
174       unsigned nSize = vSize;
175       float *normals = new float[nSize];
176       unsigned *numVertexPerFaces = new unsigned[numFaces];
177       vector<FrsMaterial> meshFrsMaterials;
178
179       IndexedFaceSet::TRIANGLES_STYLE *faceStyle = new IndexedFaceSet::TRIANGLES_STYLE[numFaces];
180       unsigned i;
181       for (i = 0; i <numFaces; i++) {
182         faceStyle[i] = IndexedFaceSet::TRIANGLES;
183         numVertexPerFaces[i] = 3;
184       }
185       
186       unsigned viSize = 3*numFaces;
187       unsigned *VIndices = new unsigned[viSize];
188       unsigned niSize = viSize;
189       unsigned *NIndices = new unsigned[niSize];
190       unsigned *MIndices = new unsigned[viSize]; // Material Indices
191      
192
193       float *pv = vertices;
194       float *pn = normals;
195       unsigned *pvi = VIndices;
196       unsigned *pni = NIndices;
197       unsigned *pmi = MIndices;
198       
199       unsigned currentIndex = 0;
200       unsigned currentMIndex = 0;
201
202       FrsMaterial tmpMat;
203       
204       // we want to find the min and max coordinates as we build the rep. 
205       // We initialize the min and max values whith the first vertex.
206       float pvtmp[3];
207       lib3ds_vector_transform(pvtmp, M, mesh->pointL[mesh->faceL[0].points[0]].pos);
208       minBBox[0] = pvtmp[0];
209       maxBBox[0] = pvtmp[0];
210       minBBox[1] = pvtmp[1];
211       maxBBox[1] = pvtmp[1];
212       minBBox[2] = pvtmp[2];
213       maxBBox[2] = pvtmp[2];
214
215       unsigned p;
216       real vert[3][3];
217       real norm;
218       for(p=0; p<mesh->faces; ++p) // we parse the faces of the mesh
219       {
220         Lib3dsFace *f=&mesh->faceL[p];
221         Lib3dsMaterial *mat=0;
222         if (f->material[0]) 
223           mat=lib3ds_file_material_by_name(_3dsFile, f->material);
224
225         if (mat) 
226         {
227           tmpMat.setDiffuse(mat->diffuse[0], mat->diffuse[1], mat->diffuse[2], mat->diffuse[3]);
228           tmpMat.setSpecular(mat->specular[0], mat->specular[1], mat->specular[2], mat->specular[3]);
229           float s = (float)pow(2.0, 10.0*mat->shininess);
230           if(s > 128.f)
231             s = 128.f;
232           tmpMat.setShininess(s);
233         }
234         
235         if(meshFrsMaterials.empty()){
236           meshFrsMaterials.push_back(tmpMat);
237           shape->setFrsMaterial(tmpMat);
238         }else{
239           // find if the material is aleady in the list
240           unsigned i=0;
241           bool found = false;
242           for(vector<FrsMaterial>::iterator it=meshFrsMaterials.begin(), itend=meshFrsMaterials.end();
243           it!=itend;
244           ++it){
245             if(*it == tmpMat){
246               currentMIndex = i;
247               found = true;
248               break;
249             }
250             ++i;
251           }
252           if(!found){
253             meshFrsMaterials.push_back(tmpMat);
254             currentMIndex = meshFrsMaterials.size()-1;
255           }
256         }
257         
258
259         for(i=0; i<3; ++i) // we parse the vertices of the face f
260         {
261           unsigned j;
262           lib3ds_vector_transform(pv, M, mesh->pointL[f->points[i]].pos); //fills the cells of the pv array
263           for(j=0; j<3; j++) // we parse the xyz coordinates of the vertex i
264           {
265             if(minBBox[j] > pv[j])
266               minBBox[j] = pv[j];
267
268             if(maxBBox[j] < pv[j])
269               maxBBox[j] = pv[j];
270
271             vert[i][j] = pv[j];
272           }
273           
274           // for(j=0; j<3; j++)
275           //     pn[j] = f->normal[j];
276
277           lib3ds_normal_transform(pn, M, normalL[3*p+i]); //fills the cells of the pv array
278           //lib3ds_vector_normalize(pn);
279
280           
281           *pvi = currentIndex;
282           *pni = currentIndex;
283           *pmi = currentMIndex;
284           
285
286           currentIndex +=3;
287           pv += 3;
288           pn += 3;
289           pvi++;
290           pni++;
291           pmi++;
292           
293         }
294
295         for(i=0; i<3; i++)
296         {
297           norm = 0.0;
298           for (unsigned j = 0; j < 3; j++)
299             norm += (vert[i][j] - vert[(i+1)%3][j])*(vert[i][j] - vert[(i+1)%3][j]);
300           norm = sqrt(norm);
301           if(_minEdgeSize > norm)
302             _minEdgeSize = norm;
303         }
304
305         _numFacesRead++;
306       }
307
308       free(normalL);
309
310       // We might have several times the same vertex. We want a clean 
311       // shape with no real-vertex. Here, we are making a cleaning 
312       // pass.
313       real *cleanVertices = NULL;
314       unsigned   cvSize;
315       unsigned   *cleanVIndices = NULL;
316       
317       GeomCleaner::CleanIndexedVertexArray(
318         vertices, vSize, 
319         VIndices, viSize,
320         &cleanVertices, &cvSize, 
321         &cleanVIndices);
322
323       real *cleanNormals = NULL;
324       unsigned   cnSize;
325       unsigned   *cleanNIndices = NULL;
326
327       GeomCleaner::CleanIndexedVertexArray(
328         normals, nSize, 
329         NIndices, niSize,
330         &cleanNormals, &cnSize, 
331         &cleanNIndices);
332
333       // format materials array
334       FrsMaterial** marray = new FrsMaterial*[meshFrsMaterials.size()];
335       unsigned mindex=0;
336       for(vector<FrsMaterial>::iterator m=meshFrsMaterials.begin(), mend=meshFrsMaterials.end();
337           m!=mend;
338           ++m){
339         marray[mindex] = new FrsMaterial(*m);
340         ++mindex;
341       }
342       // deallocates memory:
343       delete [] vertices;
344       delete [] normals;
345       delete [] VIndices;
346       delete [] NIndices;
347       
348       // Create the IndexedFaceSet with the retrieved attributes
349       rep = new IndexedFaceSet(cleanVertices, cvSize, 
350                                cleanNormals, cnSize,
351                                marray, meshFrsMaterials.size(),
352                                0, 0,
353                                numFaces, numVertexPerFaces, faceStyle,
354                                cleanVIndices, viSize,
355                                cleanNIndices, niSize,
356                                MIndices, viSize,
357                                0,0,
358                                0);
359           // sets the id of the rep
360           rep->setId(Id(iNode->node_id, 0));
361
362
363       const BBox<Vec3r> bbox = BBox<Vec3r>(Vec3r(minBBox[0], minBBox[1], minBBox[2]), 
364                                            Vec3r(maxBBox[0], maxBBox[1], maxBBox[2]));
365       rep->setBBox(bbox);
366       shape->AddRep(rep);
367     }
368
369     if (iNode->user.d) 
370     {
371       if(NULL != iNode->matrix)
372       {
373         Lib3dsObjectData *d = &iNode->data.object;
374         Matrix44r M44f;
375         for(unsigned i=0; i<4; i++)
376           for(unsigned j=0; j<4; j++)
377             M44f(i,j) = iNode->matrix[j][i];
378           
379           currentMesh->setMatrix(Matrix44r(M44f));
380           currentMesh->Translate(-d->pivot[0], -d->pivot[1], -d->pivot[2]);
381       }
382       shape = (NodeShape*)iNode->user.d;
383       currentMesh->AddChild(shape);
384       _Scene->AddChild(currentMesh);
385     }
386   }
387
388 }