Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/trunk/importer/object.cc @ 2934

Last change on this file since 2934 was 2934, checked in by bensch, 20 years ago

orxonox/trunk/importer: reimplemented bool Object::readFace (char* faceString), now it is able also to import polygons.

File size: 18.6 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   ### File Specific:
12   main-programmer: Benjamin Grauer
13   co-programmer: ...
14*/
15
16#include "object.h"
17
18/**
19   \brief Creates a 3D-Object, but does not load any 3D-models
20   pretty useless
21*/
22Object::Object ()
23{
24
25  initialize();
26
27  BoxObject();
28
29  finalize();
30}
31
32/**
33   \brief Crates a 3D-Object and loads in a File
34   \param fileName file to parse and load (must be a .obj file)
35*/
36Object::Object(char* fileName)
37{
38  initialize();
39
40  importFile (fileName);
41
42  finalize();
43}
44
45/**
46   \brief Crates a 3D-Object, loads in a File and scales it.
47   \param fileName file to parse and load (must be a .obj file)
48   \param scaling The factor that the object will be scaled with.
49*/
50
51Object::Object(char* fileName, float scaling)
52{
53  initialize();
54  scaleFactor = scaling;
55
56  importFile (fileName);
57
58  finalize();
59}
60
61/**
62   \brief deletes an Object
63*/
64Object::~Object()
65{
66  if (verbose >= 2)
67    printf ("Deleting display List.\n");
68  Group* walker = firstGroup;
69  while (walker != NULL)
70    {
71      glDeleteLists (walker->listNumber, 1);
72      Group* lastWalker = walker;
73      walker = walker->nextGroup;
74      delete lastWalker;
75    } 
76}
77
78/**
79    \brief initializes the Object
80    This Function initializes all the needed arrays, Lists and clientStates
81*/
82bool Object::initialize (void)
83{
84  if (verbose >=3)
85    printf("new 3D-Object is being created\n"); 
86
87  // setting the start group;
88  firstGroup = new Group;
89  currentGroup = firstGroup;
90  groupCount = 0;
91 
92  initGroup (currentGroup);
93  mtlFileName = "";
94  scaleFactor = 1;
95  material = new Material();
96
97  glEnableClientState (GL_VERTEX_ARRAY);
98  //  glEnableClientState (GL_NORMAL_ARRAY);
99  //  glEnableClientState (GL_TEXTURE_COORD_ARRAY);
100
101
102  return true;
103}
104
105/**
106   \brief Imports a obj file and handles the the relative location
107   \param fileName The file to import
108*/
109bool Object::importFile (char* fileName)
110{
111  if (verbose >=3)
112    printf("preparing to read in file: %s\n", fileName);   
113  objFileName = fileName;
114  this->readFromObjFile (objFileName);
115  return true;
116}
117
118/**
119  \brief finalizes an Object.
120   This funcion is needed, to close the glList and all the other lists.
121*/
122bool Object::finalize(void)
123{
124  //  if (verbose >=3)
125    printf("finalizing the 3D-Object\n"); 
126  finalizeGroup (currentGroup);
127  if (material != NULL)
128    delete material;
129  return true;
130}
131
132/**
133   \brief Draws the Objects of all Groups.
134   It does this by just calling the Lists that must have been created earlier.
135*/
136void Object::draw (void)
137{
138  if (verbose >=2)
139    printf("drawing the 3D-Objects\n"); 
140  Group* walker = firstGroup;
141  while (walker != NULL)
142    {
143      if (verbose >= 3)
144        printf ("Drawing object %s\n", walker->name);
145      glCallList (walker->listNumber);
146      walker = walker->nextGroup;
147    }
148}
149
150/**
151   \brief Draws the Object number groupNumber
152   It does this by just calling the List that must have been created earlier.
153   \param groupNumber The number of the group that will be displayed.
154*/
155void Object::draw (int groupNumber)
156{
157  if (groupNumber >= groupCount)
158    {
159      if (verbose>=2)
160        printf ("You requested object number %i, but this File only contains of %i Objects.\n", groupNumber-1, groupCount);
161      return;
162    }
163  if (verbose >=2)
164    printf("drawing the requested 3D-Objects if found.\n"); 
165  Group* walker = firstGroup;
166  int counter = 0;
167  while (walker != NULL)
168    {
169      if (counter == groupNumber)
170        {
171          if (verbose >= 2)
172            printf ("Drawing object number %s named %s\n", counter, walker->name);
173          glCallList (walker->listNumber);
174          return;
175        }
176      ++counter;
177      walker = walker->nextGroup;
178    }
179  if (verbose >= 2)
180    printf("Object number %i in %s not Found.\n", groupNumber, objFileName);
181  return;
182
183}
184
185/**
186   \brief Draws the Object with a specific groupname
187   It does this by just calling the List that must have been created earlier.
188   \param groupName The name of the group that will be displayed.
189*/
190void Object::draw (char* groupName)
191{
192  if (verbose >=2)
193    printf("drawing the requested 3D-Objects if found.\n"); 
194  Group* walker = firstGroup;
195  while (walker != NULL)
196    {
197      if (!strcmp(walker->name, groupName))
198        {
199          if (verbose >= 2)
200            printf ("Drawing object %s\n", walker->name);
201          glCallList (walker->listNumber);
202          return;
203        }
204      walker = walker->nextGroup;
205    }
206  if (verbose >= 2)
207    printf("Object Named %s in %s not Found.\n", groupName, objFileName);
208  return;
209}
210
211/**
212   \returns Count of the Objects in this File
213*/
214int Object::getGroupCount (void)
215{
216  return groupCount;
217}
218
219/**
220   \brief initializes a new Group object
221*/
222bool Object::initGroup(Group* group)
223{
224  if (verbose >= 2)
225    printf("Adding new Group\n");
226  group->name = "";
227  group->faceMode = -1;
228  group->faceCount =0; 
229  if ((group->listNumber = glGenLists(1)) == 0 )
230    {
231      printf ("list could not be created for this Object\n");
232      return false;
233    }
234 
235  if (groupCount == 0)
236    {
237      group->firstVertex = 0;
238      group->firstNormal = 0;
239      group->firstNormal = 0;
240    }
241  else
242    {
243      group->firstVertex = currentGroup->firstVertex + currentGroup->vertices->getCount()/3;
244      group->firstNormal = currentGroup->firstNormal + currentGroup->normals->getCount()/3;
245      group->firstVertexTexture = currentGroup->firstVertexTexture + currentGroup->vTexture->getCount()/2;
246    }
247  if (verbose >=2)
248    printf ("Creating new Arrays, with starting points v:%i, vt:%i, vn:%i .\n", group->firstVertex, group->firstVertexTexture, group->firstNormal);
249  group->vertices = new Array();
250  group->normals = new Array();
251  group->vTexture = new Array();
252
253  glNewList (group->listNumber, GL_COMPILE);
254}
255
256/**
257   \brief finalizes a Group.
258   \param group the group to finalize.
259*/
260bool Object::finalizeGroup(Group* group)
261{
262  if (verbose >=2)
263    printf ("Finalize group %s.\n", group->name);
264  glEnd();
265  glEndList();
266}
267/**
268   \brief deletes the Arrays of the Group to save space.
269   \param group the group to delete the arrays from.
270*/
271bool Object::cleanupGroup(Group* group)
272{
273  if (verbose >=2)
274    printf ("cleaning up group %s.\n", group->name);
275 
276  delete group->vertices;
277  delete group->normals;
278  delete group->vTexture;
279}
280
281/**
282   \brief Reads in the .obj File and sets all the Values.
283   This function does read the file, parses it for the occurence of things like vertices, faces and so on, and executes the specific tasks
284   \param fileName the File that will be parsed (.obj-file)
285*/
286bool Object::readFromObjFile (char* fileName)
287{
288  OBJ_FILE = new ifstream(fileName);
289  if (!OBJ_FILE->is_open())
290    {
291      if (verbose >=1)
292        printf ("unable to open .OBJ file: %s\n Loading Box Object instead.\n", fileName);
293      BoxObject();
294      return false;
295    }
296  objFileName = fileName;
297  char Buffer[10000];
298  while(!OBJ_FILE->eof())
299    {
300      OBJ_FILE->getline(Buffer, 10000);
301      if (verbose >=4)
302        printf ("Read input line: %s\n",Buffer);
303     
304
305      // case vertice
306      if (!strncmp(Buffer, "v ", 2))
307        {
308          readVertex(Buffer+2);
309        }
310
311      // case face
312      else if (!strncmp(Buffer, "f ", 2))
313        {
314          readFace (Buffer+2);
315        }
316     
317      else if (!strncmp(Buffer, "mtllib", 6))
318        {
319          readMtlLib (Buffer+7);
320        }
321
322      else if (!strncmp(Buffer, "usemtl", 6))
323        {
324          readUseMtl (Buffer+7);
325        }
326
327      // case VertexNormal
328      else if (!strncmp(Buffer, "vn ", 2))
329      {
330        readVertexNormal(Buffer+3);
331      }
332
333      // case VertexTextureCoordinate
334      else if (!strncmp(Buffer, "vt ", 2))
335      {
336        readVertexTexture(Buffer+3);
337      }
338      // case group
339      else if (!strncmp(Buffer, "g", 1))
340        {
341          readGroup (Buffer+2);
342        }
343    }
344  OBJ_FILE->close();
345  return true;
346
347}
348
349/**
350   \brief parses a vertex-String
351   If a vertex line is found this function will inject it into the vertex-Array
352   \param vertexString The String that will be parsed.
353*/
354bool Object::readVertex (char* vertexString)
355{
356  readingVertices = true;
357  char subbuffer1[20];
358  char subbuffer2[20];
359  char subbuffer3[20];
360  sscanf (vertexString, "%s %s %s", subbuffer1, subbuffer2, subbuffer3);
361  if (verbose >= 3)
362    printf ("reading in a vertex: %s %s %s\n", subbuffer1, subbuffer2, subbuffer3);
363  currentGroup->vertices->addEntry(atof(subbuffer1)*scaleFactor, atof(subbuffer2)*scaleFactor, atof(subbuffer3)*scaleFactor);
364  return true;
365}
366
367/**
368   \brief parses a face-string
369   If a face line is found this function will add it to the glList.
370   The function makes a difference between QUADS and TRIANGLES, and will if changed re-open, set and re-close the gl-processe.
371   \param faceString The String that will be parsed.
372*/
373bool Object::readFace (char* faceString)
374{
375  // finalize the Arrays;
376  if (readingVertices == true)
377    {
378      currentGroup->vertices->finalizeArray();
379      //      glVertexPointer(3, GL_FLOAT, 0, currentGroup->vertices->getArray());
380      currentGroup->normals->finalizeArray();
381      //      glNormalPointer(GL_FLOAT, 0, currentGroup->normals->getArray());
382      currentGroup->vTexture->finalizeArray();
383    }
384
385  readingVertices = false;
386  currentGroup->faceCount++;
387
388  int elemCount = 0;
389 
390  FaceElement* firstElem = new FaceElement;
391  FaceElement* tmpElem = firstElem;
392
393 
394  while(strcmp (faceString, "\0"))
395    {
396      if (elemCount>0)
397          tmpElem = tmpElem->next = new FaceElement;
398      tmpElem->next = NULL;
399
400
401      sscanf (faceString, "%s", tmpElem->value);
402      faceString += strlen(tmpElem->value);
403      if (strcmp (faceString, "\0"))
404        faceString++;
405      elemCount++;
406
407
408    }
409 
410 
411  if (elemCount == 3)
412    {
413      if (currentGroup->faceMode != 3)
414        {
415          if (currentGroup->faceMode != -1)
416            glEnd();
417          glBegin(GL_TRIANGLES);
418        }
419     
420      currentGroup->faceMode = 3;
421      if (verbose >=3)
422        printf ("found triag.\n");
423    }
424 
425  else if (elemCount == 4)
426    {
427      if (currentGroup->faceMode != 4)
428        {
429          if (currentGroup->faceMode != -1)
430            glEnd();
431          glBegin(GL_QUADS);
432        }
433      currentGroup->faceMode = 4;
434      if (verbose >=3 )
435        printf ("found quad.\n");
436    }
437 
438  else if (elemCount > 4)
439    {
440      if (currentGroup->faceMode != -1)
441        glEnd();
442      glBegin(GL_POLYGON);
443      if (verbose >=3)
444        printf ("Polygon with %i faces found.", elemCount);
445      currentGroup->faceMode = elemCount;
446    }
447
448  tmpElem = firstElem;
449  while (tmpElem != NULL)
450    {
451      //      printf ("%s\n", tmpElem->value);
452      addGLElement(tmpElem->value);
453      tmpElem = tmpElem->next;
454    }
455
456}
457
458/**
459   \brief Adds a Face-element (one vertex of a face) with all its information.
460   It does this by searching:
461   1. The Vertex itself
462   2. The VertexNormale
463   3. The VertexTextureCoordinate
464   merging this information, the face will be drawn.
465
466*/
467bool Object::addGLElement (char* elementString)
468{
469  if (verbose >=3)
470    printf ("importing grafical Element to openGL\n");
471  char* vertex = elementString;
472
473  char* texture;
474  if ((texture = strstr (vertex, "/")) != NULL)
475    {
476      texture[0] = '\0';
477      texture ++;
478      if (verbose>=3)
479        printf ("includeing texture #%i, and mapping it to group texture #%i, textureArray has %i entries.\n", atoi(texture), (atoi(texture)-1 - currentGroup->firstVertexTexture)*3, currentGroup->vTexture->getCount());
480      glTexCoord2fv(currentGroup->vTexture->getArray()+(atoi(texture)-1 - currentGroup->firstVertexTexture)*2);
481
482      char* normal;
483      if ((normal = strstr (texture, "/")) !=NULL)
484        {
485          normal[0] = '\0';
486          normal ++;
487          //glArrayElement(atoi(vertex)-1);
488          glNormal3fv(currentGroup->normals->getArray() +(atoi(normal)-1 - currentGroup->firstNormal)*3);
489        }
490    }
491  if (verbose>=3)
492    printf ("includeing vertex #%i, and mapping it to group vertex #%i, vertexArray has %i entries.\n", atoi(vertex), (atoi(vertex)-1 - currentGroup->firstVertex)*3, currentGroup->vertices->getCount());
493  glVertex3fv(currentGroup->vertices->getArray() +(atoi(vertex)-1 - currentGroup->firstVertex)*3);
494
495}
496
497/**
498   \brief parses a vertexNormal-String
499   If a vertexNormal line is found this function will inject it into the vertexNormal-Array
500   \param normalString The String that will be parsed.
501*/
502bool Object::readVertexNormal (char* normalString)
503{
504  readingVertices = true;
505  char subbuffer1[20];
506  char subbuffer2[20];
507  char subbuffer3[20];
508  sscanf (normalString, "%s %s %s", subbuffer1, subbuffer2, subbuffer3);
509  if (verbose >=3 )
510    printf("found vertex-Normal %s, %s, %s\n", subbuffer1,subbuffer2,subbuffer3);
511  currentGroup->normals->addEntry(atof(subbuffer1), atof(subbuffer2), atof(subbuffer3));
512  return true;
513}
514
515/**
516   \brief parses a vertexTextureCoordinate-String
517   If a vertexTextureCoordinate line is found this function will inject it into the vertexTexture-Array
518   \param vTextureString The String that will be parsed.
519*/
520bool Object::readVertexTexture (char* vTextureString)
521{
522  readingVertices = true;
523  char subbuffer1[20];
524  char subbuffer2[20];
525  sscanf (vTextureString, "%s %s", subbuffer1, subbuffer2);
526  if (verbose >=3 )
527    printf("found vertex-Texture %s, %s\n", subbuffer1,subbuffer2);
528  currentGroup->vTexture->addEntry(atof(subbuffer1));
529  currentGroup->vTexture->addEntry(atof(subbuffer2));
530  return true;
531}
532
533/**
534   \brief parses a group String
535   This function initializes a new Group.
536   With it you should be able to import .obj-files with more than one Objects inside.
537   \param groupString the new Group to create
538*/
539bool Object::readGroup (char* groupString)
540{
541  // setting the group name if not default.
542  if (strcmp(currentGroup->name, "default"))
543    {
544      currentGroup->name = (char*) malloc ( strlen(groupString) * sizeof (char));
545      strcpy(currentGroup->name, groupString);
546    }
547  if (groupCount != 0 && currentGroup->faceCount>0)
548    {
549      Group* newGroup = new Group;
550      finalizeGroup(currentGroup);
551      currentGroup->nextGroup = newGroup;
552      initGroup(newGroup);
553      cleanupGroup(currentGroup); // deletes the arrays of the group; must be after initGroup.
554      currentGroup = newGroup; // must be after init see initGroup for more info
555    }
556
557  ++groupCount;
558
559}
560
561/**
562    \brief Function to read in a mtl File.
563    this Function parses all Lines of an mtl File
564    \param mtlFile The .mtl file to read
565*/
566bool Object::readMtlLib (char* mtlFile)
567{
568  MTL_FILE = new ifstream (mtlFile);
569  if (!MTL_FILE->is_open())
570    {
571      if (verbose >= 1)
572        printf ("unable to open file: %s\n", mtlFile);
573      return false;
574    }
575  mtlFileName = mtlFile;
576  if (verbose >=2)
577    printf ("Opening mtlFile: %s\n", mtlFileName);
578  char Buffer[500];
579  Material* tmpMat = material;
580  while(!MTL_FILE->eof())
581    {
582      MTL_FILE->getline(Buffer, 500);
583      if (verbose >= 4)
584        printf("found line in mtlFile: %s\n", Buffer);
585     
586
587      // create new Material
588      if (!strncmp(Buffer, "newmtl ", 2))
589        {
590          tmpMat = tmpMat->addMaterial(Buffer+7);
591          //      printf ("%s, %p\n", tmpMat->getName(), tmpMat);
592        }
593      // setting a illumMode
594      else if (!strncmp(Buffer, "illum", 5))
595        {
596          tmpMat->setIllum(Buffer+6);
597
598        }
599      // setting Diffuse Color
600      else if (!strncmp(Buffer, "Kd", 2))
601        {
602          tmpMat->setDiffuse(Buffer+3);
603        }
604      // setting Ambient Color
605      else if (!strncmp(Buffer, "Ka", 2))
606        {
607          tmpMat->setAmbient(Buffer+3);
608        }
609      // setting Specular Color
610      else if (!strncmp(Buffer, "Ks", 2))
611        {
612          tmpMat->setSpecular(Buffer+3);
613        }
614      // setting The Specular Shininess
615      else if (!strncmp(Buffer, "Ns", 2))
616        {
617          tmpMat->setShininess(Buffer+3);
618        }
619      // setting up transparency
620      else if (!strncmp(Buffer, "d", 1))
621        {
622          tmpMat->setTransparency(Buffer+2);
623        }
624      else if (!strncpy(Buffer, "Tf", 2))
625        {
626          tmpMat->setTransparency(Buffer+3);
627        }
628
629    }
630  return true;
631}
632
633/**
634   \brief Function that selects a material, if changed in the obj file.
635   \param matString the Material that will be set.
636*/
637
638bool Object::readUseMtl (char* matString)
639{
640  if (!strcmp (mtlFileName, ""))
641    {
642      if (verbose >= 1)
643        printf ("Not using new defined material, because no mtlFile found yet\n");
644      return false;
645    }
646     
647  if (currentGroup->faceMode != -1)
648    glEnd();
649  currentGroup->faceMode = 0;
650  if (verbose >= 2)
651    printf ("using material %s for coming Faces.\n", matString);
652  material->search(matString)->select();
653}
654
655/**
656   \brief Includes a default object
657   This will inject a Cube, because this is the most basic object.
658*/
659void Object::BoxObject(void)
660{
661  readVertex ("-0.500000 -0.500000 0.500000");
662  readVertex ("0.500000 -0.500000 0.500000");
663  readVertex ("-0.500000 0.500000 0.500000");
664  readVertex ("0.500000 0.500000 0.500000");
665  readVertex ("-0.500000 0.500000 -0.500000");
666  readVertex ("0.500000 0.500000 -0.500000");
667  readVertex ("-0.500000 -0.500000 -0.500000");
668  readVertex ("0.500000 -0.500000 -0.500000");
669  readVertexTexture ("0.000000 0.000000");
670  readVertexTexture ("1.000000 0.000000");
671  readVertexTexture ("0.000000 1.000000");
672  readVertexTexture ("1.000000 1.000000");
673  readVertexTexture ("0.000000 2.000000");
674  readVertexTexture ("1.000000 2.000000");
675  readVertexTexture ("0.000000 3.000000");
676  readVertexTexture ("1.000000 3.000000");
677  readVertexTexture ("0.000000 4.000000");
678  readVertexTexture ("1.000000 4.000000");
679  readVertexTexture ("2.000000 0.000000");
680  readVertexTexture ("2.000000 1.000000");
681  readVertexTexture ("-1.000000 0.000000");
682  readVertexTexture ("-1.000000 1.000000");
683 
684  readVertexNormal ("0.000000 0.000000 1.000000");
685  readVertexNormal ("0.000000 0.000000 1.000000");
686  readVertexNormal ("0.000000 0.000000 1.000000");
687  readVertexNormal ("0.000000 0.000000 1.000000");
688  readVertexNormal ("0.000000 1.000000 0.000000");
689  readVertexNormal ("0.000000 1.000000 0.000000");
690  readVertexNormal ("0.000000 1.000000 0.000000");
691  readVertexNormal ("0.000000 1.000000 0.000000");
692  readVertexNormal ("0.000000 0.000000 -1.000000");
693  readVertexNormal ("0.000000 0.000000 -1.000000");
694  readVertexNormal ("0.000000 0.000000 -1.000000");
695  readVertexNormal ("0.000000 0.000000 -1.000000");
696  readVertexNormal ("0.000000 -1.000000 0.000000");
697  readVertexNormal ("0.000000 -1.000000 0.000000");
698  readVertexNormal ("0.000000 -1.000000 0.000000");
699  readVertexNormal ("0.000000 -1.000000 0.000000");
700  readVertexNormal ("1.000000 0.000000 0.000000");
701  readVertexNormal ("1.000000 0.000000 0.000000");
702  readVertexNormal ("1.000000 0.000000 0.000000");
703  readVertexNormal ("1.000000 0.000000 0.000000");
704  readVertexNormal ("-1.000000 0.000000 0.000000");
705  readVertexNormal ("-1.000000 0.000000 0.000000");
706  readVertexNormal ("-1.000000 0.000000 0.000000");
707  readVertexNormal ("-1.000000 0.000000 0.000000");
708
709  readFace ("1/1/1 2/2/2 4/4/3 3/3/4");
710  readFace ("3/3/5 4/4/6 6/6/7 5/5/8");
711  readFace ("5/5/9 6/6/10 8/8/11 7/7/12");
712  readFace ("7/7/13 8/8/14 2/10/15 1/9/16");
713  readFace ("2/2/17 8/11/18 6/12/19 4/4/20");
714  readFace ("7/13/21 1/1/22 3/3/23 5/14/24");
715}
Note: See TracBrowser for help on using the repository browser.