Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 3068 was 3068, checked in by bensch, 19 years ago

orxonox/trunk/importer: cleanup-procedure created, that deletes all the unneded stuff like faces, faceElements (does not really delete faceElements :( )

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