source: GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/ObjConverter.cpp @ 3295

Revision 3295, 15.5 KB checked in by mattausch, 16 years ago (diff)
Line 
1#include "ObjConverter.h"
2#include "SimpleTri.h"
3#include "SimpleVec.h"
4#include "gzstream.h"
5#include <iostream>
6
7
8using namespace std;
9
10//#define USE_TEXTURE
11
12
13static void LoadIndices(char *str,
14                                                const VertexArray &vertices,
15                                                const VertexArray &normals,
16                                                const vector<pair<float, float> > &texcoords,
17                                                VertexArray &faceVertices,
18                                                VertexArray &faceNormals,
19                                                vector<Texcoord> &faceTexcoords
20                                                )
21{
22        vector<string> triples;
23
24        char *next_token;
25
26        // extract the triples of the form v/t/n v/t/n ...
27        char *pch = strtok_s(str + 1, " ", &next_token);
28
29        while (pch)
30        {
31                string s(pch);
32                triples.push_back(s);
33               
34                pch = strtok_s(NULL, " ", &next_token);   
35        }
36
37        // throw away last symbol (\n)
38        triples.back().resize(triples.back().size() - 1);
39
40        vector<int> indices;
41        vector<int> nIndices;
42        vector<int> tIndices;
43
44        char seps[] = " ";
45        char seps2[] = "/";
46
47        for (size_t i = 0; i < triples.size(); ++ i)
48        {
49                //cout << "triple " << i << " " << triples[i] << endl;
50                size_t found;
51                found = triples[i].find_first_of(seps2);
52                size_t prevfound = 0;
53
54                // extract vertex, normal, texture indices
55                string str = triples[i].substr(prevfound, found);
56
57                int index = (int)strtol(str.c_str(), NULL, 10) - 1;
58                int tIndex = index;
59                int nIndex = index;     
60               
61                // try to extract texture and normal indices
62                prevfound = found + 1;
63                found = triples[i].find_first_of(seps2, prevfound); 
64
65                if (found != string::npos)
66                {
67                        str = triples[i].substr(prevfound, found);
68
69                        int idx = (int)strtol(str.c_str(), NULL, 10) - 1;
70                        if (idx > 0) tIndex = idx;
71                }
72               
73                if (found != string::npos)
74                {
75                        str = triples[i].substr(found + 1);
76
77                        int idx = (int)strtol(str.c_str(), NULL, 10) - 1;
78                        if (idx > 0) nIndex = idx;
79                }
80
81                // store indices
82                if (index >= 0)
83                {
84                        indices.push_back(index);
85                        nIndices.push_back(nIndex);
86                        tIndices.push_back(tIndex);
87
88                        //cout << index << " " << tIndex << " " << nIndex << endl;
89                }
90
91                // new triangle found
92                if (indices.size() > 2)
93                {
94                        // change orientation of faces?
95#if 1
96                        int idx1 = 0;
97                        int idx2 = (int)indices.size() - 2;
98                        int idx3 = (int)indices.size() - 1;
99#else
100                        int idx3 = 0;
101                        int idx2 = (int)indices.size() - 2;
102                        int idx1 = (int)indices.size() - 1;
103#endif
104                        faceVertices.push_back(vertices[indices[idx1]]);
105                        faceVertices.push_back(vertices[indices[idx2]]);
106                        faceVertices.push_back(vertices[indices[idx3]]);
107
108
109                        if (!normals.empty())
110                        {
111                                faceNormals.push_back(normals[nIndices[idx1]]);
112                                faceNormals.push_back(normals[nIndices[idx2]]);
113                                faceNormals.push_back(normals[nIndices[idx3]]);
114                        }
115                        else
116                        {
117                                // no face normals? => create normals
118                                const SimpleTri tri(vertices[indices[idx1]],
119                                                        vertices[indices[idx2]],
120                                                                        vertices[indices[idx3]]);
121                                const SimpleVec n = tri.GetNormal();
122
123                                faceNormals.push_back(n);
124                                faceNormals.push_back(n);
125                                faceNormals.push_back(n);
126                        }
127
128                        if (!texcoords.empty())
129                        {
130                                faceTexcoords.push_back(texcoords[tIndices[idx1]]);
131                                faceTexcoords.push_back(texcoords[tIndices[idx2]]);
132                                faceTexcoords.push_back(texcoords[tIndices[idx3]]);
133                        }
134                }
135        }
136}
137
138
139ObjConverter::ObjConverter()
140{}
141
142
143ObjConverter::~ObjConverter()
144{
145        for (size_t i = 0; i < mGeometry.size(); ++ i)
146                delete mGeometry[i];
147       
148        mGeometry.clear();
149}
150
151
152void ObjConverter::LoadShape(const VertexArray &faceVertices,
153                                                         const VertexArray &faceNormals,
154                                                         const vector<Texcoord> &faceTexcoords,
155                                                         Material *mat)
156{
157        int numElements = (int)faceVertices.size();
158        Geometry *geom = new Geometry();
159
160        // convert the triangles to geometry
161        geom->mVertices = new SimpleVec[numElements];
162        geom->mNormals = new SimpleVec[numElements];
163        geom->mTexcoords = new Texcoord[numElements];
164
165        geom->mVertexCount = numElements;
166        geom->mTexcoordCount = (int)faceTexcoords.size();
167
168        geom->mMaterial = mat;
169
170        cout << "creating new geometry with " << numElements << " vertices" << endl;
171
172        for (int i = 0; i < numElements; ++ i)
173        {
174#if 0
175                // convert to our camera system: change y and z
176                geom->mVertices[i].x = faceVertices[i].x;
177                geom->mVertices[i].y = -faceVertices[i].z;
178                geom->mVertices[i].z = faceVertices[i].y;
179       
180                geom->mNormals[i].x = faceNormals[i].x;
181                geom->mNormals[i].y = -faceNormals[i].z;
182                geom->mNormals[i].z = faceNormals[i].y;
183
184#else
185                geom->mVertices[i].x = faceVertices[i].x;
186                geom->mVertices[i].y = faceVertices[i].y;
187                geom->mVertices[i].z = faceVertices[i].z;
188       
189                geom->mNormals[i].x = faceNormals[i].x;
190                geom->mNormals[i].y = faceNormals[i].y;
191                geom->mNormals[i].z = faceNormals[i].z;
192
193#endif
194
195                if (i < geom->mTexcoordCount)
196                {
197                        geom->mTexcoords[i].first = faceTexcoords[i].first;
198                        geom->mTexcoords[i].second = faceTexcoords[i].second;
199                }
200        }
201
202        mGeometry.push_back(geom);
203}
204
205
206bool ObjConverter::Convert(const string &filename, const std::string &outputFilename)
207{
208        mNumShapes = 0;
209       
210        for (size_t i = 0; i < mGeometry.size(); ++ i)
211                delete mGeometry[i];
212       
213        mGeometry.clear();
214
215        if (!ReadFile(filename))
216        {
217                cerr << "could not read file" << endl;
218                return false;
219        }
220
221        if (!WriteFile(outputFilename))
222        {
223                cerr << "could not write file" << endl;
224                return false;
225        }
226
227
228        return true;
229}
230
231
232bool ObjConverter::ReadFile(const string &filename)
233{
234        FILE *file;
235
236        if ((file = fopen(filename.c_str(), "r")) == NULL)
237        {       
238                return false;
239        }
240       
241        Material *currentMat = NULL;
242        VertexArray faceVertices;
243        VertexArray faceNormals;
244        vector<Texcoord> faceTexcoords;
245
246        VertexArray vertices;
247        VertexArray normals;
248        vector<Texcoord> texcoords;
249
250        vector<int> indices;
251
252        int line = 0;
253        const int len = 10000;
254        char str[len];
255
256        while (fgets(str, len, file) != NULL)
257        {
258                switch (str[0])
259                {
260                case 'v': // vertex or normal
261                        {
262                                float x, y, z;
263
264                                switch (str[1])
265                                {
266                                case 'n' :
267                                        sscanf(str + 2, "%f %f %f", &x, &y, &z);
268                                        normals.push_back(SimpleVec(x, y, z));
269                                        break;
270                                case 't':
271                                        sscanf(str + 2, "%f %f", &x, &y);
272                                        texcoords.push_back(pair<float, float>(x, y));
273                                        break;
274                                default:
275                                        sscanf(str + 1, "%f %f %f", &x, &y, &z);
276                                        //const float scale = 5e-3f;
277                                        const float scale = 5.0f;
278                                        vertices.push_back(SimpleVec(x * scale, y * scale, z* scale));
279                                        //cout <<"v " << x << " " << y << " "<< z << " ";
280                                }
281                                break;
282                        }
283                case 'f':
284                        {
285                                //////////
286                                //-- indices in the current line
287
288                                LoadIndices(str,
289                                                vertices, normals, texcoords,
290                                                faceVertices, faceNormals, faceTexcoords);
291
292                                break;
293                        }   // end face
294                case 'g': // load a new shape
295                        {
296                                if (!faceVertices.empty())
297                                {
298                                        ++ mNumShapes;
299
300                                        if (!currentMat) cout << "here3" << endl;
301                                        LoadShape(faceVertices, faceNormals, faceTexcoords, currentMat);
302
303                                        faceVertices.clear();
304                                        faceNormals.clear();
305                                        faceTexcoords.clear();
306
307                                        currentMat = NULL;
308                                }
309                        }
310                        break;
311                case 'u': // usemtl => material
312                        {
313                                string matName(str + 7);
314                                // throw away linebreak character
315                                matName.resize(matName.size() - 1);
316
317                                currentMat = mMaterialTable[matName];
318                                //cout << "matname: " << matName << endl;
319                        }
320
321                        break;
322                default:
323                        // throw away line
324                        break;
325                }
326
327                ++ line;
328        }
329
330        if (!faceVertices.empty())
331        {
332                ++ mNumShapes;
333
334                LoadShape(faceVertices, faceNormals, faceTexcoords, currentMat);
335
336                faceVertices.clear();
337                faceNormals.clear();
338                faceTexcoords.clear();
339        }
340
341        fclose(file);
342       
343        return true;
344}
345
346
347void ObjConverter::WriteGeometry(ogzstream &str, Geometry *geom)
348{
349        int vertexCount = geom->mVertexCount;
350        str.write(reinterpret_cast<char *>(&vertexCount), sizeof(int));
351 
352        str.write(reinterpret_cast<char *>(geom->mVertices), sizeof(SimpleVec) * vertexCount);
353        str.write(reinterpret_cast<char *>(geom->mNormals), sizeof(SimpleVec) * vertexCount);
354
355        int texCoordCount = geom->mTexcoordCount;
356        str.write(reinterpret_cast<char *>(&texCoordCount), sizeof(int));
357
358        if (texCoordCount)
359                str.write(reinterpret_cast<char *>(geom->mTexcoords), sizeof(float) * texCoordCount * 2);
360       
361
362        ///////
363        //-- texture
364/*
365#ifdef USE_TEXTURE
366        int texId = 0;
367#else
368        int texId = -1;
369#endif
370
371        str.write(reinterpret_cast<char *>(&texId), sizeof(int));
372
373        bool alphaTestEnabled = false;
374        //bool cullFaceEnabled = false;
375        bool cullFaceEnabled = true;
376
377        str.write(reinterpret_cast<char *>(&alphaTestEnabled), sizeof(bool));
378        str.write(reinterpret_cast<char *>(&cullFaceEnabled), sizeof(bool));
379
380        // material
381        bool hasMaterial = true;
382        //bool hasMaterial = false;
383        str.write(reinterpret_cast<char *>(&hasMaterial), sizeof(bool));
384       
385        if (hasMaterial)
386        {
387                SimpleVec ambient, diffuse, spec, emm;
388
389                ambient.x = ambient.y = ambient.z = 0.2f;
390                //diffuse.x = diffuse.y = diffuse.z = 1.0f;
391                diffuse.x = 0.7f; diffuse.y = 0.5f; diffuse.z = 0.2f;
392                spec.x    = spec.y    = spec.z    =  .0f;
393                emm = spec;
394
395                // only write rgb part of the material
396                str.write(reinterpret_cast<char *>(&ambient), sizeof(SimpleVec));
397                str.write(reinterpret_cast<char *>(&diffuse), sizeof(SimpleVec));
398                str.write(reinterpret_cast<char *>(&spec), sizeof(SimpleVec));
399                str.write(reinterpret_cast<char *>(&emm), sizeof(SimpleVec));
400        }
401*/
402}
403
404#if 0
405
406bool ObjConverter::WriteFile(const string &filename)
407{
408        ogzstream ofile(filename.c_str());
409
410        if (!ofile.is_open())
411                return false;
412       
413
414        /////////
415        //-- write textures
416
417#ifdef USE_TEXTURE
418        int textureCount = 1;
419#else
420        int textureCount = 0;
421#endif
422        ofile.write(reinterpret_cast<char *>(&textureCount), sizeof(int));
423
424        if (textureCount > 0)
425        {
426                // hack
427                const string texName("wood.jpg");
428
429                int texnameSize = (int)texName.length() + 1;
430                ofile.write(reinterpret_cast<char *>(&texnameSize), sizeof(int));
431
432                ofile.write(texName.c_str(), sizeof(char) * texnameSize);
433
434                int boundS = 1, boundT = 1;
435
436                ofile.write(reinterpret_cast<char *>(&boundS), sizeof(int));
437                ofile.write(reinterpret_cast<char *>(&boundT), sizeof(int));
438        }
439
440
441        ///////////
442        //-- write shapes
443
444        ofile.write(reinterpret_cast<char *>(&mNumShapes), sizeof(int));
445
446        vector<Geometry *>::const_iterator it, it_end = mGeometry.end();
447
448        for (it = mGeometry.begin(); it != it_end; ++ it)
449        {
450                WriteGeometry(ofile, *it);
451        }
452
453
454        int entityCount = 1;
455        ofile.write(reinterpret_cast<char *>(&entityCount), sizeof(int));
456
457
458        //////////
459        //-- write single scene entity
460
461        // no transformation
462        bool hasTrafo = false;
463        ofile.write(reinterpret_cast<char *>(&hasTrafo), sizeof(bool));
464
465        // a dummy lod
466        int numLODs = 1;
467        ofile.write(reinterpret_cast<char *>(&numLODs), sizeof(int));
468
469        float dist = 0;
470        ofile.write(reinterpret_cast<char *>(&dist), sizeof(float));
471
472        ofile.write(reinterpret_cast<char *>(&mNumShapes), sizeof(int));
473
474        // all shapes belong to this scene entity
475        for (int i = 0; i < mNumShapes; ++ i)
476        {
477                int shapeId = i;
478                ofile.write(reinterpret_cast<char *>(&shapeId), sizeof(int));
479        }
480
481        return true;
482}
483
484#else
485
486bool ObjConverter::WriteFile(const string &filename)
487{
488        ogzstream ofile(filename.c_str());
489
490        if (!ofile.is_open())
491                return false;
492       
493
494        /////////
495        //-- write textures
496
497        int textureCount = (int)mTextures.size();
498
499        ofile.write(reinterpret_cast<char *>(&textureCount), sizeof(int));
500
501        TextureArray::const_iterator tit, tit_end = mTextures.end();
502       
503        for (tit = mTextures.begin(); tit != tit_end; ++ tit)
504        {
505                const string texName = (*tit);
506
507                int texnameSize = (int)texName.length() + 1;
508                ofile.write(reinterpret_cast<char *>(&texnameSize), sizeof(int));
509
510                ofile.write(texName.c_str(), sizeof(char) * texnameSize);
511
512                int boundS = 1, boundT = 1;
513
514                ofile.write(reinterpret_cast<char *>(&boundS), sizeof(int));
515                ofile.write(reinterpret_cast<char *>(&boundT), sizeof(int));
516        }
517
518
519        ///////////
520        //-- write shapes
521
522        ofile.write(reinterpret_cast<char *>(&mNumShapes), sizeof(int));
523
524        vector<Geometry *>::const_iterator it, it_end = mGeometry.end();
525
526        for (it = mGeometry.begin(); it != it_end; ++ it)
527        {
528                WriteGeometry(ofile, *it);
529
530               
531                /////////
532                //-- material
533
534                Material *mat = (*it)->mMaterial;
535
536                if (!mat) cerr << "error: no material specified!!" << endl;
537
538                ofile.write(reinterpret_cast<char *>(&mat->texture), sizeof(int));
539
540                bool alphaTestEnabled = false;
541                //bool cullFaceEnabled = false;
542                bool cullFaceEnabled = true;
543               
544                ofile.write(reinterpret_cast<char *>(&alphaTestEnabled), sizeof(bool));
545                ofile.write(reinterpret_cast<char *>(&cullFaceEnabled), sizeof(bool));
546
547                // material
548                bool hasMaterial = true;
549                ofile.write(reinterpret_cast<char *>(&hasMaterial), sizeof(bool));
550       
551                SimpleVec ambient, diffuse, spec, emm;
552
553                ambient.x = ambient.y = ambient.z = 0.2f;
554                //diffuse.x = diffuse.y = diffuse.z = 1.0f;
555                diffuse.x = mat->rgb[0]; diffuse.y =mat->rgb[1]; diffuse.z = mat->rgb[2];
556                spec.x = spec.y = spec.z = .0f;
557                emm = spec;
558
559                // only write rgb part of the material
560                ofile.write(reinterpret_cast<char *>(&ambient), sizeof(SimpleVec));
561                ofile.write(reinterpret_cast<char *>(&diffuse), sizeof(SimpleVec));
562                ofile.write(reinterpret_cast<char *>(&spec), sizeof(SimpleVec));
563                ofile.write(reinterpret_cast<char *>(&emm), sizeof(SimpleVec));
564        }
565
566
567        //int entityCount = 1;
568        int entityCount = mNumShapes;
569        ofile.write(reinterpret_cast<char *>(&entityCount), sizeof(int));
570
571
572        //////////
573        //-- q: write single scene entity with all shapes or many entities with one shape
574
575        // all shapes belong to this scene entity
576        for (int i = 0; i < mNumShapes; ++ i)
577        {
578                // no transformation
579                bool hasTrafo = false;
580                ofile.write(reinterpret_cast<char *>(&hasTrafo), sizeof(bool));
581
582                // a dummy lod
583                int numLODs = 1;
584                ofile.write(reinterpret_cast<char *>(&numLODs), sizeof(int));
585
586                float dist = 0;
587                ofile.write(reinterpret_cast<char *>(&dist), sizeof(float));
588
589                //ofile.write(reinterpret_cast<char *>(&mNumShapes), sizeof(int));
590                int one = 1;
591                ofile.write(reinterpret_cast<char *>(&one), sizeof(int));
592
593                int shapeId = i;
594                ofile.write(reinterpret_cast<char *>(&shapeId), sizeof(int));
595        }
596
597        return true;
598}
599#endif
600
601
602bool ObjConverter::LoadMaterials(const std::string &matFileName)
603{
604        FILE *file;
605
606        if ((file = fopen(matFileName.c_str(), "r")) == NULL)
607        {       
608                return false;
609        }
610       
611        int line = 0;
612        const int len = 10000;
613        char str[len];
614
615        Material *currentMat = NULL;
616
617
618        while (fgets(str, len, file) != NULL)
619        {
620                //sscanf(str + 1, "%f %f %f", &x, &y, &z);
621                vector<string> strings;
622
623                char *next_token;
624
625                // extract the triples of the form v/t/n v/t/n ...
626                char *pch = strtok_s(str, " \n", &next_token);
627
628                while (pch)
629                {
630                        string s(pch);
631                        strings.push_back(s);
632
633                        pch = strtok_s(NULL, " \n", &next_token);       
634                }
635
636                if ((strings.size() == 2) && (strcmp(strings[0].c_str(), "newmtl") == 0))
637                {
638                        currentMat = new Material();
639                        mMaterialTable[strings[1].c_str()] = currentMat;
640                }
641
642                if ((strings.size() == 2) && (strcmp(strings[0].c_str(), "map_Kd") == 0))
643                {
644                        TextureTable::const_iterator it = mTextureTable.find(strings[1]);
645
646                        int id;
647
648                        if (it == mTextureTable.end()) // parameter not found
649                        {
650                                mTextures.push_back(strings[1]);
651                                id = (int)mTextures.size();
652                                mTextureTable[strings[1]] = id;
653                        }
654                        else
655                        {
656                                id = (*it).second;
657                        }
658
659                        currentMat->texture = id;
660                }
661
662                if ((strings.size() == 4) && (strcmp(strings[0].c_str(),"Kd") == 0))
663                {
664                        currentMat->rgb[0] = (float)atof(strings[1].c_str());
665                        currentMat->rgb[1] = (float)atof(strings[2].c_str());
666                        currentMat->rgb[2] = (float)atof(strings[3].c_str());
667                }
668
669                ++ line;
670        }
671
672        return true;
673}
Note: See TracBrowser for help on using the repository browser.