Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk/importer: imports again. Materials are still missing

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