Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk/importer: Changed importToGL-process. now the import process startts after the end of reading the File.
Group-specific arrays have been reverted to obj-file-specific.
other minor bug-fixes.

THIS VERSION IS NOT COMPLETED. will do this in the next few releases

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