Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk/importer: fixed Material Problem

File size: 19.8 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 >= 2)
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* tmpMat;
647              if ((tmpMat = material->search(tmpFace->materialString)) != NULL)
648                tmpMat->select();
649
650            }
651
652          else if (tmpFace->vertexCount == 3)
653            {
654              if (currentGroup->faceMode != 3)
655                {
656                  if (currentGroup->faceMode != -1)
657                    glEnd();
658                  glBegin(GL_TRIANGLES);
659                }
660             
661              currentGroup->faceMode = 3;
662              if (verbose >=3)
663                printf ("found triag.\n");
664            }
665         
666          else if (tmpFace->vertexCount == 4)
667            {
668              if (currentGroup->faceMode != 4)
669                {
670                  if (currentGroup->faceMode != -1)
671                    glEnd();
672                  glBegin(GL_QUADS);
673                }
674              currentGroup->faceMode = 4;
675              if (verbose >=3 )
676                printf ("found quad.\n");
677            }
678         
679          else if (tmpFace->vertexCount > 4)
680            {
681              if (currentGroup->faceMode != -1)
682                glEnd();
683              glBegin(GL_POLYGON);
684              if (verbose >=3)
685                printf ("Polygon with %i faces found.", tmpFace->vertexCount);
686              currentGroup->faceMode = tmpFace->vertexCount;
687            }
688         
689          FaceElement* tmpElem = tmpFace->firstElem;
690          while (tmpElem != NULL)
691            {
692              //      printf ("%s\n", tmpElem->value);
693              addGLElement(tmpElem->value);
694              tmpElem = tmpElem->next;
695            }
696          tmpFace = tmpFace->next;
697        }
698      glEnd();
699      glEndList();
700      currentGroup = currentGroup->next;
701    } 
702}
703
704/**
705   \brief Adds a Face-element (one vertex of a face) with all its information.
706   It does this by searching:
707   1. The Vertex itself
708   2. The VertexNormale
709   3. The VertexTextureCoordinate
710   merging this information, the face will be drawn.
711
712*/
713bool Object::addGLElement (char* elementString)
714{
715  if (verbose >=3)
716    printf ("importing grafical Element to openGL: %s\n", elementString);
717  char vertex [100];
718  strcpy (vertex, elementString);
719
720  char* texture;
721  if ((texture = strstr (vertex, "/")) != NULL)
722    {
723      texture[0] = '\0';
724      texture ++;
725      glTexCoord2fv(vTexture->getArray()+(atoi(texture)-1)*2);
726
727      char* normal;
728      if ((normal = strstr (texture, "/")) !=NULL)
729        {
730          normal[0] = '\0';
731          normal ++;
732          //glArrayElement(atoi(vertex)-1);
733          glNormal3fv(normals->getArray() +(atoi(normal)-1)*3);
734        }
735    }
736  glVertex3fv(vertices->getArray() +(atoi(vertex)-1)*3);
737
738}
739
740
741/**
742   \brief Includes a default object
743   This will inject a Cube, because this is the most basic object.
744*/
745void Object::BoxObject(void)
746{
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  readVertex ("-0.500000 -0.500000 -0.500000");
754  readVertex ("0.500000 -0.500000 -0.500000");
755
756  readVertexTexture ("0.000000 0.000000");
757  readVertexTexture ("1.000000 0.000000");
758  readVertexTexture ("0.000000 1.000000");
759  readVertexTexture ("1.000000 1.000000");
760  readVertexTexture ("0.000000 2.000000");
761  readVertexTexture ("1.000000 2.000000");
762  readVertexTexture ("0.000000 3.000000");
763  readVertexTexture ("1.000000 3.000000");
764  readVertexTexture ("0.000000 4.000000");
765  readVertexTexture ("1.000000 4.000000");
766  readVertexTexture ("2.000000 0.000000");
767  readVertexTexture ("2.000000 1.000000");
768  readVertexTexture ("-1.000000 0.000000");
769  readVertexTexture ("-1.000000 1.000000");
770 
771  readVertexNormal ("0.000000 0.000000 1.000000");
772  readVertexNormal ("0.000000 0.000000 1.000000");
773  readVertexNormal ("0.000000 0.000000 1.000000");
774  readVertexNormal ("0.000000 0.000000 1.000000");
775  readVertexNormal ("0.000000 1.000000 0.000000");
776  readVertexNormal ("0.000000 1.000000 0.000000");
777  readVertexNormal ("0.000000 1.000000 0.000000");
778  readVertexNormal ("0.000000 1.000000 0.000000");
779  readVertexNormal ("0.000000 0.000000 -1.000000");
780  readVertexNormal ("0.000000 0.000000 -1.000000");
781  readVertexNormal ("0.000000 0.000000 -1.000000");
782  readVertexNormal ("0.000000 0.000000 -1.000000");
783  readVertexNormal ("0.000000 -1.000000 0.000000");
784  readVertexNormal ("0.000000 -1.000000 0.000000");
785  readVertexNormal ("0.000000 -1.000000 0.000000");
786  readVertexNormal ("0.000000 -1.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  readVertexNormal ("-1.000000 0.000000 0.000000");
794  readVertexNormal ("-1.000000 0.000000 0.000000");
795
796  readFace ("1/1/1 2/2/2 4/4/3 3/3/4");
797  readFace ("3/3/5 4/4/6 6/6/7 5/5/8");
798  readFace ("5/5/9 6/6/10 8/8/11 7/7/12");
799  readFace ("7/7/13 8/8/14 2/10/15 1/9/16");
800  readFace ("2/2/17 8/11/18 6/12/19 4/4/20");
801  readFace ("7/13/21 1/1/22 3/3/23 5/14/24");
802}
Note: See TracBrowser for help on using the repository browser.