Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/trunk/src/object.cc @ 2933

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

orxonox/trunk: merged importer to src again

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