Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk/importer: re-arranged the Methods to a more logical order.

File size: 18.4 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  group->currentFace = group->firstFace;
211}
212
213/**
214   \brief initializes a new Face. (sets default Values)
215*/
216bool Object::initFace (Face* face)
217{
218  face->vertexCount = 0;
219
220  face->firstElem = NULL;
221 
222  face->materialString = NULL;
223 
224  face->next = NULL;
225
226  return true;
227}
228
229/**
230   \brief finalizes an Object.
231   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.
232*/
233bool Object::cleanup(void)
234{
235  //  if (verbose >=3)
236    printf("finalizing the 3D-Object\n"); 
237
238  if (vertices != NULL)
239    delete vertices;
240  if (vTexture != NULL)
241    delete vTexture;
242  if (normals != NULL)
243    delete normals;
244
245  if (material != NULL)
246    delete material;
247  return true; 
248}
249
250/**
251   \brief Imports a obj file and handles the the relative location
252   \param fileName The file to import
253*/
254bool Object::importFile (char* fileName)
255{
256  if (verbose >=3)
257    printf("preparing to read in file: %s\n", fileName);   
258  objFileName = fileName;
259  this->readFromObjFile (objFileName);
260  return true;
261}
262
263/**
264   \brief Reads in the .obj File and sets all the Values.
265   This function does read the file, parses it for the occurence of things like vertices, faces and so on, and executes the specific tasks
266   \param fileName the File that will be parsed (.obj-file)
267*/
268bool Object::readFromObjFile (char* fileName)
269{
270  OBJ_FILE = new ifstream(fileName);
271  if (!OBJ_FILE->is_open())
272    {
273      if (verbose >=1)
274        printf ("unable to open .OBJ file: %s\n Loading Box Object instead.\n", fileName);
275      BoxObject();
276      return false;
277    }
278  objFileName = fileName;
279  char Buffer[10000];
280  while(!OBJ_FILE->eof())
281    {
282      OBJ_FILE->getline(Buffer, 10000);
283      if (verbose >=4)
284        printf ("Read input line: %s\n",Buffer);
285     
286
287      // case vertice
288      if (!strncmp(Buffer, "v ", 2))
289        {
290          readVertex(Buffer+2);
291        }
292
293      // case face
294      else if (!strncmp(Buffer, "f ", 2))
295        {
296          readFace (Buffer+2);
297        }
298     
299      else if (!strncmp(Buffer, "mtllib ", 7))
300        {
301          readMtlLib (Buffer+7);
302        }
303
304      else if (!strncmp(Buffer, "usemtl ", 7))
305        {
306          readUseMtl (Buffer+7);
307        }
308
309      // case VertexNormal
310      else if (!strncmp(Buffer, "vn ", 3))
311      {
312        readVertexNormal(Buffer+3);
313      }
314
315      // case VertexTextureCoordinate
316      else if (!strncmp(Buffer, "vt ", 3))
317      {
318        readVertexTexture(Buffer+3);
319      }
320      // case group
321      else if (!strncmp(Buffer, "g ", 2))
322        {
323          readGroup (Buffer+2);
324        }
325      else if (!strncmp(Buffer, "s ", 2))
326        {
327          if (verbose >= 1)
328            printf("smoothing groups not supportet yet. line: %s\n", Buffer);
329        }
330    }
331  OBJ_FILE->close();
332  return true;
333
334}
335
336/**
337   \brief parses a group String
338   This function initializes a new Group.
339   With it you should be able to import .obj-files with more than one Objects inside.
340   \param groupString the new Group to create
341*/
342bool Object::readGroup (char* groupString)
343{
344  // setting the group name if not default.
345  if (strcmp(currentGroup->name, "default"))
346    {
347      currentGroup->name = new char [strlen(groupString)];
348      strcpy(currentGroup->name, groupString);
349    }
350  if (groupCount != 0 && currentGroup->faceCount>0)
351    {
352      Group* newGroup = new Group;
353      //      finalizeGroup(currentGroup);
354      currentGroup->next = newGroup;
355      initGroup(newGroup);
356      currentGroup = newGroup; // must be after init see initGroup for more info
357    }
358
359  ++groupCount;
360
361}
362
363/**
364   \brief parses a vertex-String
365   If a vertex line is found this function will inject it into the vertex-Array
366   \param vertexString The String that will be parsed.
367*/
368bool Object::readVertex (char* vertexString)
369{
370  char subbuffer1[20];
371  char subbuffer2[20];
372  char subbuffer3[20];
373  sscanf (vertexString, "%s %s %s", subbuffer1, subbuffer2, subbuffer3);
374  if (verbose >= 3)
375    printf ("reading in a vertex: %s %s %s\n", subbuffer1, subbuffer2, subbuffer3);
376  vertices->addEntry(atof(subbuffer1)*scaleFactor, atof(subbuffer2)*scaleFactor, atof(subbuffer3)*scaleFactor);
377  return true;
378}
379
380/**
381   \brief parses a face-string
382   If a face line is found this function will add it to the glList.
383   The function makes a difference between QUADS and TRIANGLES, and will if changed re-open, set and re-close the gl-processe.
384   \param faceString The String that will be parsed.
385*/
386bool Object::readFace (char* faceString)
387{
388  if (currentGroup->faceCount >0)
389    currentGroup->currentFace = currentGroup->currentFace->next = new Face;
390  initFace (currentGroup->currentFace);
391
392  FaceElement* tmpElem = currentGroup->currentFace->firstElem = new FaceElement;
393
394  while(strcmp (faceString, "\0"))
395    {
396      if (currentGroup->currentFace->vertexCount>0)
397          tmpElem = tmpElem->next = new FaceElement;
398      tmpElem->next = NULL;
399
400      char tmpValue [50];
401      sscanf (faceString, "%s", tmpValue);
402      tmpElem->value = new char [strlen(tmpValue)];
403      strcpy (tmpElem->value, tmpValue);
404
405      faceString += strlen(tmpElem->value);
406      if (strcmp (faceString, "\0"))
407        faceString++;
408      currentGroup->currentFace->vertexCount++;
409    }
410
411  currentGroup->faceCount += currentGroup->currentFace->vertexCount -2;
412}
413
414/**
415   \brief parses a vertexNormal-String
416   If a vertexNormal line is found this function will inject it into the vertexNormal-Array
417   \param normalString The String that will be parsed.
418*/
419bool Object::readVertexNormal (char* normalString)
420{
421  char subbuffer1[20];
422  char subbuffer2[20];
423  char subbuffer3[20];
424  sscanf (normalString, "%s %s %s", subbuffer1, subbuffer2, subbuffer3);
425  if (verbose >=3 )
426    printf("found vertex-Normal %s, %s, %s\n", subbuffer1,subbuffer2,subbuffer3);
427  normals->addEntry(atof(subbuffer1), atof(subbuffer2), atof(subbuffer3));
428  return true;
429}
430
431/**
432   \brief parses a vertexTextureCoordinate-String
433   If a vertexTextureCoordinate line is found this function will inject it into the vertexTexture-Array
434   \param vTextureString The String that will be parsed.
435*/
436bool Object::readVertexTexture (char* vTextureString)
437{
438  char subbuffer1[20];
439  char subbuffer2[20];
440  sscanf (vTextureString, "%s %s", subbuffer1, subbuffer2);
441  if (verbose >=3 )
442    printf("found vertex-Texture %s, %s\n", subbuffer1,subbuffer2);
443  vTexture->addEntry(atof(subbuffer1));
444  vTexture->addEntry(atof(subbuffer2));
445  return true;
446}
447
448/**
449    \brief Function to read in a mtl File.
450    this Function parses all Lines of an mtl File
451    \param mtlFile The .mtl file to read
452*/
453bool Object::readMtlLib (char* mtlFile)
454{
455  MTL_FILE = new ifstream (mtlFile);
456  if (!MTL_FILE->is_open())
457    {
458      if (verbose >= 1)
459        printf ("unable to open file: %s\n", mtlFile);
460      return false;
461    }
462  mtlFileName = mtlFile;
463  if (verbose >=2)
464    printf ("Opening mtlFile: %s\n", mtlFileName);
465  char Buffer[500];
466  Material* tmpMat = material;
467  while(!MTL_FILE->eof())
468    {
469      MTL_FILE->getline(Buffer, 500);
470      if (verbose >= 4)
471        printf("found line in mtlFile: %s\n", Buffer);
472     
473
474      // create new Material
475      if (!strncmp(Buffer, "newmtl ", 7))
476        {
477          tmpMat = tmpMat->addMaterial(Buffer+7);
478          //      printf ("%s, %p\n", tmpMat->getName(), tmpMat);
479        }
480      // setting a illumMode
481      else if (!strncmp(Buffer, "illum ", 6))
482        {
483          tmpMat->setIllum(Buffer+6);
484
485        }
486      // setting Diffuse Color
487      else if (!strncmp(Buffer, "Kd ", 3))
488        {
489          tmpMat->setDiffuse(Buffer+3);
490        }
491      // setting Ambient Color
492      else if (!strncmp(Buffer, "Ka ", 3))
493        {
494          tmpMat->setAmbient(Buffer+3);
495        }
496      // setting Specular Color
497      else if (!strncmp(Buffer, "Ks ", 3))
498        {
499          tmpMat->setSpecular(Buffer+3);
500        }
501      // setting The Specular Shininess
502      else if (!strncmp(Buffer, "Ns ", 3))
503        {
504          tmpMat->setShininess(Buffer+3);
505        }
506      // setting up transparency
507      else if (!strncmp(Buffer, "d ", 2))
508        {
509          tmpMat->setTransparency(Buffer+2);
510        }
511      else if (!strncpy(Buffer, "Tf ", 3))
512        {
513          tmpMat->setTransparency(Buffer+3);
514        }
515
516    }
517  return true;
518}
519
520/**
521   \brief Function that selects a material, if changed in the obj file.
522   \param matString the Material that will be set.
523*/
524bool Object::readUseMtl (char* matString)
525{
526  if (!strcmp (mtlFileName, ""))
527    {
528      if (verbose >= 1)
529        printf ("Not using new defined material, because no mtlFile found yet\n");
530      return false;
531    }
532     
533  if (currentGroup->faceCount >0)
534    currentGroup->currentFace = currentGroup->currentFace->next = new Face;
535  initFace (currentGroup->currentFace);
536 
537  currentGroup->currentFace->materialString = new char[strlen(matString)];
538  strcpy (currentGroup->currentFace->materialString, matString);
539 
540  if (currentGroup->faceCount == 0)
541    currentGroup->faceCount ++;
542
543}
544
545/**
546   \brief reads and includes the Faces/Materials into the openGL state Machine
547*/
548bool Object::importToGL (void)
549{
550
551  // finalize the Arrays
552  vertices->finalizeArray();
553  vTexture->finalizeArray();
554  normals->finalizeArray();
555
556  currentGroup = firstGroup;
557
558  while (currentGroup != NULL)
559    {
560
561      // creating a glList for the Group
562      if ((currentGroup->listNumber = glGenLists(1)) == 0)
563        {
564          printf ("list could not be created for this Object\n");
565          return false;
566        }
567      glNewList (currentGroup->listNumber, GL_COMPILE);
568
569      // Putting Faces to GL
570      Face* tmpFace = currentGroup->firstFace;
571      while (tmpFace != NULL)
572        {
573          if (tmpFace->vertexCount == 0 && tmpFace->materialString != NULL)
574            {
575              if (currentGroup->faceMode != -1)
576                glEnd();
577              currentGroup->faceMode = 0;
578              if (verbose >= 2)
579                printf ("using material %s for coming Faces.\n", tmpFace->materialString);
580              material->search(tmpFace->materialString)->select();
581
582            }
583
584          else if (tmpFace->vertexCount == 3)
585            {
586              if (currentGroup->faceMode != 3)
587                {
588                  if (currentGroup->faceMode != -1)
589                    glEnd();
590                  glBegin(GL_TRIANGLES);
591                }
592             
593              currentGroup->faceMode = 3;
594              if (verbose >=3)
595                printf ("found triag.\n");
596            }
597         
598          else if (tmpFace->vertexCount == 4)
599            {
600              if (currentGroup->faceMode != 4)
601                {
602                  if (currentGroup->faceMode != -1)
603                    glEnd();
604                  glBegin(GL_QUADS);
605                }
606              currentGroup->faceMode = 4;
607              if (verbose >=3 )
608                printf ("found quad.\n");
609            }
610         
611          else if (tmpFace->vertexCount > 4)
612            {
613              if (currentGroup->faceMode != -1)
614                glEnd();
615              glBegin(GL_POLYGON);
616              if (verbose >=3)
617                printf ("Polygon with %i faces found.", tmpFace->vertexCount);
618              currentGroup->faceMode = tmpFace->vertexCount;
619            }
620         
621          FaceElement* tmpElem = tmpFace->firstElem;
622          while (tmpElem != NULL)
623            {
624              //      printf ("%s\n", tmpElem->value);
625              addGLElement(tmpElem->value);
626              tmpElem = tmpElem->next;
627            }
628          tmpFace = tmpFace->next;
629        }
630      glEnd();
631      glEndList();
632      currentGroup = currentGroup->next;
633    } 
634}
635
636/**
637   \brief Adds a Face-element (one vertex of a face) with all its information.
638   It does this by searching:
639   1. The Vertex itself
640   2. The VertexNormale
641   3. The VertexTextureCoordinate
642   merging this information, the face will be drawn.
643
644*/
645bool Object::addGLElement (char* elementString)
646{
647  if (verbose >=3)
648    printf ("importing grafical Element to openGL: %s\n", elementString);
649  char* vertex = elementString;
650
651  char* texture;
652  if ((texture = strstr (vertex, "/")) != NULL)
653    {
654      texture[0] = '\0';
655      texture ++;
656      glTexCoord2fv(vTexture->getArray()+(atoi(texture)-1)*2);
657
658      char* normal;
659      if ((normal = strstr (texture, "/")) !=NULL)
660        {
661          normal[0] = '\0';
662          normal ++;
663          //glArrayElement(atoi(vertex)-1);
664          glNormal3fv(normals->getArray() +(atoi(normal)-1)*3);
665        }
666    }
667  glVertex3fv(vertices->getArray() +(atoi(vertex)-1)*3);
668
669}
670
671
672/**
673   \brief Includes a default object
674   This will inject a Cube, because this is the most basic object.
675*/
676void Object::BoxObject(void)
677{
678  readVertex ("-0.500000 -0.500000 0.500000");
679  readVertex ("0.500000 -0.500000 0.500000");
680  readVertex ("-0.500000 0.500000 0.500000");
681  readVertex ("0.500000 0.500000 0.500000");
682  readVertex ("-0.500000 0.500000 -0.500000");
683  readVertex ("0.500000 0.500000 -0.500000");
684  readVertex ("-0.500000 -0.500000 -0.500000");
685  readVertex ("0.500000 -0.500000 -0.500000");
686
687  readVertexTexture ("0.000000 0.000000");
688  readVertexTexture ("1.000000 0.000000");
689  readVertexTexture ("0.000000 1.000000");
690  readVertexTexture ("1.000000 1.000000");
691  readVertexTexture ("0.000000 2.000000");
692  readVertexTexture ("1.000000 2.000000");
693  readVertexTexture ("0.000000 3.000000");
694  readVertexTexture ("1.000000 3.000000");
695  readVertexTexture ("0.000000 4.000000");
696  readVertexTexture ("1.000000 4.000000");
697  readVertexTexture ("2.000000 0.000000");
698  readVertexTexture ("2.000000 1.000000");
699  readVertexTexture ("-1.000000 0.000000");
700  readVertexTexture ("-1.000000 1.000000");
701 
702  readVertexNormal ("0.000000 0.000000 1.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 1.000000 0.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 0.000000 -1.000000");
711  readVertexNormal ("0.000000 0.000000 -1.000000");
712  readVertexNormal ("0.000000 0.000000 -1.000000");
713  readVertexNormal ("0.000000 0.000000 -1.000000");
714  readVertexNormal ("0.000000 -1.000000 0.000000");
715  readVertexNormal ("0.000000 -1.000000 0.000000");
716  readVertexNormal ("0.000000 -1.000000 0.000000");
717  readVertexNormal ("0.000000 -1.000000 0.000000");
718  readVertexNormal ("1.000000 0.000000 0.000000");
719  readVertexNormal ("1.000000 0.000000 0.000000");
720  readVertexNormal ("1.000000 0.000000 0.000000");
721  readVertexNormal ("1.000000 0.000000 0.000000");
722  readVertexNormal ("-1.000000 0.000000 0.000000");
723  readVertexNormal ("-1.000000 0.000000 0.000000");
724  readVertexNormal ("-1.000000 0.000000 0.000000");
725  readVertexNormal ("-1.000000 0.000000 0.000000");
726
727  readFace ("1/1/1 2/2/2 4/4/3 3/3/4");
728  readFace ("3/3/5 4/4/6 6/6/7 5/5/8");
729  readFace ("5/5/9 6/6/10 8/8/11 7/7/12");
730  readFace ("7/7/13 8/8/14 2/10/15 1/9/16");
731  readFace ("2/2/17 8/11/18 6/12/19 4/4/20");
732  readFace ("7/13/21 1/1/22 3/3/23 5/14/24");
733}
Note: See TracBrowser for help on using the repository browser.