Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk/importer: set first normal before, now it is correct. line-stepping corrected

File size: 18.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  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*/
50Object::Object(char* fileName, float scaling)
51{
52  initialize();
53  scaleFactor = scaling;
54
55  importFile (fileName);
56
57  finalize();
58}
59
60/**
61   \brief deletes an Object
62*/
63Object::~Object()
64{
65  if (verbose >= 2)
66    printf ("Deleting display List.\n");
67  Group* walker = firstGroup;
68  while (walker != NULL)
69    {
70      glDeleteLists (walker->listNumber, 1);
71      Group* lastWalker = walker;
72      walker = walker->nextGroup;
73      delete lastWalker;
74    } 
75}
76
77/**
78    \brief initializes the Object
79    This Function initializes all the needed arrays, Lists and clientStates
80*/
81bool Object::initialize (void)
82{
83  if (verbose >=3)
84    printf("new 3D-Object is being created\n"); 
85
86  // setting the start group;
87  firstGroup = new Group;
88  currentGroup = firstGroup;
89  groupCount = 0;
90 
91  initGroup (firstGroup);
92  mtlFileName = "";
93  scaleFactor = 1;
94  material = new Material();
95
96  //  glEnableClientState (GL_VERTEX_ARRAY);
97  //  glEnableClientState (GL_NORMAL_ARRAY);
98  //  glEnableClientState (GL_TEXTURE_COORD_ARRAY);
99
100
101  return true;
102}
103
104/**
105   \brief Imports a obj file and handles the the relative location
106   \param fileName The file to import
107*/
108bool Object::importFile (char* fileName)
109{
110  if (verbose >=3)
111    printf("preparing to read in file: %s\n", fileName);   
112  objFileName = fileName;
113  this->readFromObjFile (objFileName);
114  return true;
115}
116
117/**
118  \brief finalizes an Object.
119   This funcion is needed, to close the glList and all the other lists.
120*/
121bool Object::finalize(void)
122{
123  //  if (verbose >=3)
124    printf("finalizing the 3D-Object\n"); 
125  finalizeGroup (currentGroup);
126  if (material != NULL)
127    delete material;
128  return true;
129}
130
131/**
132   \brief Draws the Objects of all Groups.
133   It does this by just calling the Lists that must have been created earlier.
134*/
135void Object::draw (void)
136{
137  if (verbose >=2)
138    printf("drawing the 3D-Objects\n"); 
139  Group* walker = firstGroup;
140  while (walker != NULL)
141    {
142      if (verbose >= 3)
143        printf ("Drawing object %s\n", walker->name);
144      glCallList (walker->listNumber);
145      walker = walker->nextGroup;
146    }
147}
148
149/**
150   \brief Draws the Object number groupNumber
151   It does this by just calling the List that must have been created earlier.
152   \param groupNumber The number of the group that will be displayed.
153*/
154void Object::draw (int groupNumber)
155{
156  if (groupNumber >= groupCount)
157    {
158      if (verbose>=2)
159        printf ("You requested object number %i, but this File only contains of %i Objects.\n", groupNumber-1, groupCount);
160      return;
161    }
162  if (verbose >=2)
163    printf("drawing the requested 3D-Objects if found.\n"); 
164  Group* walker = firstGroup;
165  int counter = 0;
166  while (walker != NULL)
167    {
168      if (counter == groupNumber)
169        {
170          if (verbose >= 2)
171            printf ("Drawing object number %s named %s\n", counter, walker->name);
172          glCallList (walker->listNumber);
173          return;
174        }
175      ++counter;
176      walker = walker->nextGroup;
177    }
178  if (verbose >= 2)
179    printf("Object number %i in %s not Found.\n", groupNumber, objFileName);
180  return;
181
182}
183
184/**
185   \brief Draws the Object with a specific groupname
186   It does this by just calling the List that must have been created earlier.
187   \param groupName The name of the group that will be displayed.
188*/
189void Object::draw (char* groupName)
190{
191  if (verbose >=2)
192    printf("drawing the requested 3D-Objects if found.\n"); 
193  Group* walker = firstGroup;
194  while (walker != NULL)
195    {
196      if (!strcmp(walker->name, groupName))
197        {
198          if (verbose >= 2)
199            printf ("Drawing object %s\n", walker->name);
200          glCallList (walker->listNumber);
201          return;
202        }
203      walker = walker->nextGroup;
204    }
205  if (verbose >= 2)
206    printf("Object Named %s in %s not Found.\n", groupName, objFileName);
207  return;
208}
209
210/**
211   \returns Count of the Objects in this File
212*/
213int Object::getGroupCount (void)
214{
215  return groupCount;
216}
217
218/**
219   \brief initializes a new Group object
220*/
221bool Object::initGroup(Group* group)
222{
223  if (verbose >= 2)
224    printf("Adding new Group\n");
225  group->name = "";
226  group->faceMode = -1;
227  group->faceCount = 0; 
228  if ((group->listNumber = glGenLists(1)) == 0 )
229    {
230      printf ("list could not be created for this Object\n");
231      return false;
232    }
233 
234  if (groupCount == 0)
235    {
236      group->firstVertex = 0;
237      group->firstNormal = 0;
238      group->firstVertexTexture = 0;
239    }
240  else
241    {
242      group->firstVertex = currentGroup->firstVertex + currentGroup->vertices->getCount()/3;
243      group->firstNormal = currentGroup->firstNormal + currentGroup->normals->getCount()/3;
244      group->firstVertexTexture = currentGroup->firstVertexTexture + currentGroup->vTexture->getCount()/2;
245    }
246  if (verbose >=2)
247    printf ("Creating new Arrays, with starting points v:%i, vt:%i, vn:%i .\n", group->firstVertex, group->firstVertexTexture, group->firstNormal);
248  group->vertices = new Array();
249  group->normals = new Array();
250  group->vTexture = new Array();
251
252  glNewList (group->listNumber, GL_COMPILE);
253}
254
255/**
256   \brief finalizes a Group.
257   \param group the group to finalize.
258*/
259bool Object::finalizeGroup(Group* group)
260{
261  if (verbose >=2)
262    printf ("Finalize group %s.\n", group->name);
263  glEnd();
264  glEndList();
265}
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  FaceElement* delElem;
450  while (tmpElem != NULL)
451    {
452      //      printf ("%s\n", tmpElem->value);
453      addGLElement(tmpElem->value);
454      delElem = tmpElem;
455      tmpElem = tmpElem->next;
456      delete delElem;
457    }
458
459}
460
461/**
462   \brief Adds a Face-element (one vertex of a face) with all its information.
463   It does this by searching:
464   1. The Vertex itself
465   2. The VertexNormale
466   3. The VertexTextureCoordinate
467   merging this information, the face will be drawn.
468
469*/
470bool Object::addGLElement (char* elementString)
471{
472  if (verbose >=3)
473    printf ("importing grafical Element to openGL\n");
474  char* vertex = elementString;
475
476  char* texture;
477  if ((texture = strstr (vertex, "/")) != NULL)
478    {
479      texture[0] = '\0';
480      texture ++;
481      if (verbose>=3)
482        printf ("includeing texture #%i, and mapping it to group texture #%i, textureArray has %i entries.\n", atoi(texture), (atoi(texture)-1 - currentGroup->firstVertexTexture)*2, currentGroup->vTexture->getCount());
483      glTexCoord2fv(currentGroup->vTexture->getArray()+(atoi(texture)-1 - currentGroup->firstVertexTexture)*2);
484
485      char* normal;
486      if ((normal = strstr (texture, "/")) !=NULL)
487        {
488          normal[0] = '\0';
489          normal ++;
490          //glArrayElement(atoi(vertex)-1);
491          glNormal3fv(currentGroup->normals->getArray() +(atoi(normal)-1 - currentGroup->firstNormal)*3);
492        }
493    }
494  if (verbose>=3)
495    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());
496  glVertex3fv(currentGroup->vertices->getArray() +(atoi(vertex)-1 - currentGroup->firstVertex)*3);
497
498}
499
500/**
501   \brief parses a vertexNormal-String
502   If a vertexNormal line is found this function will inject it into the vertexNormal-Array
503   \param normalString The String that will be parsed.
504*/
505bool Object::readVertexNormal (char* normalString)
506{
507  readingVertices = true;
508  char subbuffer1[20];
509  char subbuffer2[20];
510  char subbuffer3[20];
511  sscanf (normalString, "%s %s %s", subbuffer1, subbuffer2, subbuffer3);
512  if (verbose >=3 )
513    printf("found vertex-Normal %s, %s, %s\n", subbuffer1,subbuffer2,subbuffer3);
514  currentGroup->normals->addEntry(atof(subbuffer1), atof(subbuffer2), atof(subbuffer3));
515  return true;
516}
517
518/**
519   \brief parses a vertexTextureCoordinate-String
520   If a vertexTextureCoordinate line is found this function will inject it into the vertexTexture-Array
521   \param vTextureString The String that will be parsed.
522*/
523bool Object::readVertexTexture (char* vTextureString)
524{
525  readingVertices = true;
526  char subbuffer1[20];
527  char subbuffer2[20];
528  sscanf (vTextureString, "%s %s", subbuffer1, subbuffer2);
529  if (verbose >=3 )
530    printf("found vertex-Texture %s, %s\n", subbuffer1,subbuffer2);
531  currentGroup->vTexture->addEntry(atof(subbuffer1));
532  currentGroup->vTexture->addEntry(atof(subbuffer2));
533  return true;
534}
535
536/**
537   \brief parses a group String
538   This function initializes a new Group.
539   With it you should be able to import .obj-files with more than one Objects inside.
540   \param groupString the new Group to create
541*/
542bool Object::readGroup (char* groupString)
543{
544  // setting the group name if not default.
545  if (strcmp(currentGroup->name, "default"))
546    {
547      currentGroup->name = (char*) malloc ( strlen(groupString) * sizeof (char));
548      strcpy(currentGroup->name, groupString);
549    }
550  if (groupCount != 0 && currentGroup->faceCount>0)
551    {
552      Group* newGroup = new Group;
553      finalizeGroup(currentGroup);
554      currentGroup->nextGroup = newGroup;
555      initGroup(newGroup);
556      cleanupGroup(currentGroup); // deletes the arrays of the group; must be after initGroup.
557      currentGroup = newGroup; // must be after init see initGroup for more info
558    }
559
560  ++groupCount;
561
562}
563
564/**
565    \brief Function to read in a mtl File.
566    this Function parses all Lines of an mtl File
567    \param mtlFile The .mtl file to read
568*/
569bool Object::readMtlLib (char* mtlFile)
570{
571  MTL_FILE = new ifstream (mtlFile);
572  if (!MTL_FILE->is_open())
573    {
574      if (verbose >= 1)
575        printf ("unable to open file: %s\n", mtlFile);
576      return false;
577    }
578  mtlFileName = mtlFile;
579  if (verbose >=2)
580    printf ("Opening mtlFile: %s\n", mtlFileName);
581  char Buffer[500];
582  Material* tmpMat = material;
583  while(!MTL_FILE->eof())
584    {
585      MTL_FILE->getline(Buffer, 500);
586      if (verbose >= 4)
587        printf("found line in mtlFile: %s\n", Buffer);
588     
589
590      // create new Material
591      if (!strncmp(Buffer, "newmtl ", 2))
592        {
593          tmpMat = tmpMat->addMaterial(Buffer+7);
594          //      printf ("%s, %p\n", tmpMat->getName(), tmpMat);
595        }
596      // setting a illumMode
597      else if (!strncmp(Buffer, "illum", 5))
598        {
599          tmpMat->setIllum(Buffer+6);
600
601        }
602      // setting Diffuse Color
603      else if (!strncmp(Buffer, "Kd", 2))
604        {
605          tmpMat->setDiffuse(Buffer+3);
606        }
607      // setting Ambient Color
608      else if (!strncmp(Buffer, "Ka", 2))
609        {
610          tmpMat->setAmbient(Buffer+3);
611        }
612      // setting Specular Color
613      else if (!strncmp(Buffer, "Ks", 2))
614        {
615          tmpMat->setSpecular(Buffer+3);
616        }
617      // setting The Specular Shininess
618      else if (!strncmp(Buffer, "Ns", 2))
619        {
620          tmpMat->setShininess(Buffer+3);
621        }
622      // setting up transparency
623      else if (!strncmp(Buffer, "d", 1))
624        {
625          tmpMat->setTransparency(Buffer+2);
626        }
627      else if (!strncpy(Buffer, "Tf", 2))
628        {
629          tmpMat->setTransparency(Buffer+3);
630        }
631
632    }
633  return true;
634}
635
636/**
637   \brief Function that selects a material, if changed in the obj file.
638   \param matString the Material that will be set.
639*/
640bool Object::readUseMtl (char* matString)
641{
642  if (!strcmp (mtlFileName, ""))
643    {
644      if (verbose >= 1)
645        printf ("Not using new defined material, because no mtlFile found yet\n");
646      return false;
647    }
648     
649  if (currentGroup->faceMode != -1)
650    glEnd();
651  currentGroup->faceMode = 0;
652  if (verbose >= 2)
653    printf ("using material %s for coming Faces.\n", matString);
654  material->search(matString)->select();
655}
656
657/**
658   \brief Includes a default object
659   This will inject a Cube, because this is the most basic object.
660*/
661void Object::BoxObject(void)
662{
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  readVertex ("-0.500000 -0.500000 -0.500000");
670  readVertex ("0.500000 -0.500000 -0.500000");
671
672  readVertexTexture ("0.000000 0.000000");
673  readVertexTexture ("1.000000 0.000000");
674  readVertexTexture ("0.000000 1.000000");
675  readVertexTexture ("1.000000 1.000000");
676  readVertexTexture ("0.000000 2.000000");
677  readVertexTexture ("1.000000 2.000000");
678  readVertexTexture ("0.000000 3.000000");
679  readVertexTexture ("1.000000 3.000000");
680  readVertexTexture ("0.000000 4.000000");
681  readVertexTexture ("1.000000 4.000000");
682  readVertexTexture ("2.000000 0.000000");
683  readVertexTexture ("2.000000 1.000000");
684  readVertexTexture ("-1.000000 0.000000");
685  readVertexTexture ("-1.000000 1.000000");
686 
687  readVertexNormal ("0.000000 0.000000 1.000000");
688  readVertexNormal ("0.000000 0.000000 1.000000");
689  readVertexNormal ("0.000000 0.000000 1.000000");
690  readVertexNormal ("0.000000 0.000000 1.000000");
691  readVertexNormal ("0.000000 1.000000 0.000000");
692  readVertexNormal ("0.000000 1.000000 0.000000");
693  readVertexNormal ("0.000000 1.000000 0.000000");
694  readVertexNormal ("0.000000 1.000000 0.000000");
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 ("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  readVertexNormal ("-1.000000 0.000000 0.000000");
709  readVertexNormal ("-1.000000 0.000000 0.000000");
710  readVertexNormal ("-1.000000 0.000000 0.000000");
711
712  readFace ("1/1/1 2/2/2 4/4/3 3/3/4");
713  readFace ("3/3/5 4/4/6 6/6/7 5/5/8");
714  readFace ("5/5/9 6/6/10 8/8/11 7/7/12");
715  readFace ("7/7/13 8/8/14 2/10/15 1/9/16");
716  readFace ("2/2/17 8/11/18 6/12/19 4/4/20");
717  readFace ("7/13/21 1/1/22 3/3/23 5/14/24");
718}
Note: See TracBrowser for help on using the repository browser.