Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/trunk/src/importer/model.cc @ 3396

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

orxonox/trunk: splitted obj-loader out of the model-class: this will enable different kinds of Filetypes to be included with the importer.
Althought there is a name-field error, the Model gets loaded and unloaded as good as previously

File size: 19.3 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 "model.h"
17int verbose = 1; //! \todo should be GLOBAL
18using namespace std;
19
20/**
21   \brief Creates a 3D-Model, but does not load any 3D-models.
22
23   This Constructor is pretty useless, because why load no model in an model-loader??
24*/
25Model::Model ()
26{
27
28  this->initialize();
29
30  this->BoxModel();
31
32  this->importToGL ();
33
34  this->cleanup();
35}
36
37/**
38   \brief deletes an Model.
39
40   Looks if any from model allocated space is still in use, and if so deleted it.
41*/
42Model::~Model()
43{
44  PRINTF(0)("Deleting Model ");
45  if (this->name)
46    {
47      PRINT(0)("%s\n");
48      delete []this->name;
49    }
50  else
51      PRINT(0)("\n");
52
53  PRINTF(2)("Deleting display Lists.\n");
54  Group* walker = this->firstGroup;
55  while (walker != NULL)
56    {
57      glDeleteLists (walker->listNumber, 1);
58      Group* delWalker = walker;
59      walker = walker->next;
60      delete delWalker;
61    }
62
63  PRINTF(2)("Deleting Materials.\n");
64  if (this->material)
65    delete this->material;
66}
67
68/**
69   \brief Draws the Models of all Groups.
70   It does this by just calling the Lists that must have been created earlier.
71*/
72void Model::draw (void) const
73{
74  PRINTF(2)("drawing the 3D-Models\n"); 
75  Group* walker = this->firstGroup;
76  while (walker != NULL)
77    {
78      PRINTF(3)("Drawing model %s\n", walker->name);
79      glCallList (walker->listNumber);
80      walker = walker->next;
81    }
82}
83
84/**
85   \brief Draws the Model number groupNumber
86   \param groupNumber The number of the group that will be displayed.
87
88   It does this by just calling the List that must have been created earlier.
89*/
90void Model::draw (int groupNumber) const 
91{
92  if (groupNumber >= this->groupCount)
93    {
94      PRINTF(1)("You requested model number %i, but this File only contains of %i Models.\n", groupNumber-1, this->groupCount);
95      return;
96    }
97  PRINTF(2)("drawing the requested 3D-Models if found.\n"); 
98  Group* walker = this->firstGroup;
99  int counter = 0;
100  while (walker != NULL)
101    {
102      if (counter == groupNumber)
103        {
104          PRINTF(2)("Drawing model number %i named %s\n", counter, walker->name);
105          glCallList (walker->listNumber);
106          return;
107        }
108      ++counter;
109      walker = walker->next;
110    }
111  PRINTF(1)("Model number %i in %s not Found.\n", groupNumber, this->name);
112  return;
113
114}
115
116/**
117   \brief Draws the Model with a specific groupName
118   \param groupName The name of the group that will be displayed.
119
120   It does this by just calling the List that must have been created earlier.
121*/
122void Model::draw (char* groupName) const
123{
124  PRINTF(2)("drawing the requested 3D-Models if found.\n"); 
125  Group* walker = this->firstGroup;
126  while (walker != NULL)
127    {
128      if (!strcmp(walker->name, groupName))
129        {
130          PRINTF(2)("Drawing model %s\n", walker->name);
131          glCallList (walker->listNumber);
132          return;
133        }
134      walker = walker->next;
135    }
136  PRINTF(1)("Model Named %s in %s not Found.\n", groupName, this->name);
137  return;
138}
139
140/**
141   \returns Count of the Models in this File
142*/
143int Model::getGroupCount (void) const
144{
145  return this->groupCount;
146}
147
148/**
149    \brief initializes the Model.
150
151    This Function initializes all the needed arrays, Lists and clientStates.
152    It also defines default values.
153*/
154bool Model::initialize (void)
155{
156  PRINTF(2)("new 3D-Model is being created\n"); 
157
158  this->name = NULL;
159  // setting the start group;
160  this->firstGroup = new Group;
161  this->currentGroup = this->firstGroup;
162  this->groupCount = 0;
163 
164  this->initGroup (this->currentGroup);
165  this->scaleFactor = 1;
166  this->material = new Material();
167
168  this->vertices = new Array();
169  this->vTexture = new Array();
170  this->normals = new Array();
171
172  return true;
173}
174
175/**
176   \brief initializes a new Group model
177   \param group the group that should be initialized.
178   \todo Maybe Group should be a Class, because it does a lot of stuff
179   
180*/
181bool Model::initGroup(Group* group)
182{
183  PRINTF(3)("Adding new Group\n");
184  group->name = "";
185  group->faceMode = -1;
186  group->faceCount = 0; 
187  group->next = NULL;
188
189  group->firstFace = new Face;
190  this->initFace (group->firstFace);
191  group->currentFace = group->firstFace;
192}
193
194/**
195   \brief initializes a new Face. (sets default Values)
196   \param face The face to initialize
197*/
198bool Model::initFace (Face* face)
199{
200  face->vertexCount = 0;
201
202  face->firstElem = NULL;
203 
204  face->materialString = NULL;
205 
206  face->next = NULL;
207
208  return true;
209}
210
211/**
212   \brief finalizes an Model.
213   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.
214*/
215bool Model::cleanup(void)
216{
217  PRINTF(3)("cleaning up the 3D-Model to save Memory.\n");
218
219  if (this->vertices)
220    delete this->vertices;
221  if (this->vTexture)
222    delete this->vTexture;
223  if (this->normals)
224    delete this->normals;
225
226  this->cleanupGroup(this->firstGroup);
227  return true; 
228}
229
230/**
231   \brief Cleans up all groups starting from group.
232   \param group the first Group to clean
233*/
234bool Model::cleanupGroup (Group* group)
235{
236  PRINTF(3)("Cleaning up group\n");
237  if (group->firstFace != NULL)
238    {
239      cleanupFace (group->firstFace);
240      delete group->firstFace;
241    }
242
243  if (group->next !=NULL)
244    cleanupGroup (group->next);
245  return true;
246}
247
248/**
249   \brief Cleans up all Faces starting from face until NULL is reached.
250   \param face the first face to clean.
251*/
252bool Model::cleanupFace (Face* face)
253{
254  PRINTF(3)("Cleaning up Face\n");
255
256  if (face->materialString != NULL)
257      delete []face->materialString;
258  if (face->firstElem != NULL)
259    {
260      this->cleanupFaceElement(face->firstElem);
261      delete face->firstElem;
262    }
263     
264  if (face->next != NULL)
265    {
266      this->cleanupFace (face->next);
267      delete face->next;
268    }
269     
270}
271
272
273/**
274   \brief Cleans up all FaceElements starting from faceElem.
275   \param faceElem the first FaceElement to clean.
276*/
277bool Model::cleanupFaceElement(FaceElement* faceElem)
278{
279  if (faceElem->next != NULL)
280    {
281      this->cleanupFaceElement (faceElem->next);
282      delete faceElem->next;
283    }
284}
285
286/**
287   \brief parses a group String
288   \param groupString the new Group to create
289
290   This function initializes a new Group.
291   With it you should be able to import .obj-files with more than one Models inside.
292*/
293bool Model::addGroup (char* groupString)
294{
295  PRINTF(3)("Read Group: %s.\n", groupString);
296  if (this->groupCount != 0 && this->currentGroup->faceCount>0)
297    {
298      //      finalizeGroup(currentGroup);
299      this->currentGroup = this->currentGroup->next = new Group;
300      this->initGroup(this->currentGroup);
301    }
302  // setting the group name if not default.
303  if (strcmp(groupString, "default"))
304    {
305      this->currentGroup->name = new char [strlen(groupString)+1];
306      strcpy(this->currentGroup->name, groupString);
307    }
308  ++this->groupCount;
309
310}
311
312/**
313   \brief parses a vertex-String
314   \param vertexString The String that will be parsed.
315
316   If a vertex line is found this function will inject it into the vertex-Array
317*/
318bool Model::addVertex (char* vertexString)
319{
320  float subbuffer1;
321  float subbuffer2;
322  float subbuffer3;
323  sscanf (vertexString, "%f %f %f", &subbuffer1, &subbuffer2, &subbuffer3);
324  PRINTF(3)("reading in a vertex: %f %f %f\n", &subbuffer1, &subbuffer2, &subbuffer3);
325  this->vertices->addEntry(subbuffer1*scaleFactor, subbuffer2*scaleFactor, subbuffer3*scaleFactor);
326  return true;
327}
328
329/**
330   \brief parses a face-string
331   \param faceString The String that will be parsed.
332
333   If a face line is found this function will add it to the glList.
334   The function makes a difference between QUADS and TRIANGLES, and will if changed re-open, set and re-close the gl-processe.
335*/
336bool Model::addFace (char* faceString)
337{
338  if (this->currentGroup->faceCount >0)
339    this->currentGroup->currentFace = this->currentGroup->currentFace->next = new Face;
340  this->initFace (this->currentGroup->currentFace);
341
342  FaceElement* tmpElem = this->currentGroup->currentFace->firstElem = new FaceElement;
343  tmpElem->next = NULL;
344  while(strcmp (faceString, "\0"))
345    {
346      if (this->currentGroup->currentFace->vertexCount>0)
347          tmpElem = tmpElem->next = new FaceElement;
348      tmpElem->next = NULL;
349
350      char tmpValue [50];
351      int tmpLen;
352      char* vertex = NULL;
353      char* texture = NULL;
354      char* normal = NULL;
355
356      sscanf (faceString, "%s", tmpValue);
357      tmpLen = strlen(tmpValue);
358      vertex = tmpValue;
359
360      if ((texture = strstr (vertex, "/")) != NULL)
361        {
362          texture[0] = '\0';
363          texture ++;
364         
365          if ((normal = strstr (texture, "/")) !=NULL)
366            {
367              normal[0] = '\0';
368              normal ++;
369            }     
370        }
371      if (vertex)
372        tmpElem->vertexNumber = atoi(vertex)-1;
373      else
374        tmpElem->vertexNumber = -1;
375      if (texture)
376        tmpElem->texCoordNumber = atoi(texture)-1;
377      else
378        tmpElem->texCoordNumber = -1;
379      if (normal)
380        tmpElem->normalNumber = atoi(normal)-1;
381      else
382        tmpElem->normalNumber = -1;
383
384      faceString += tmpLen;
385      if (strcmp (faceString, "\0"))
386        faceString++;
387      this->currentGroup->currentFace->vertexCount++;
388    }
389
390  this->currentGroup->faceCount += this->currentGroup->currentFace->vertexCount -2;
391}
392
393/**
394   \brief parses a vertexNormal-String
395   \param normalString The String that will be parsed.
396
397   If a vertexNormal line is found this function will inject it into the vertexNormal-Array
398*/
399bool Model::addVertexNormal (char* normalString)
400{
401  float subbuffer1;
402  float subbuffer2;
403  float subbuffer3;
404  sscanf (normalString, "%f %f %f", &subbuffer1, &subbuffer2, &subbuffer3);
405  PRINTF(3)("found vertex-Normal %f, %f, %f\n", &subbuffer1,&subbuffer2,&subbuffer3);
406  this->normals->addEntry(subbuffer1, subbuffer2, subbuffer3);
407  return true;
408}
409
410/**
411   \brief parses a vertexTextureCoordinate-String
412   \param vTextureString The String that will be parsed.
413
414   If a vertexTextureCoordinate line is found,
415   this function will inject it into the vertexTexture-Array
416*/
417bool Model::addVertexTexture (char* vTextureString)
418{
419  float subbuffer1;
420  float subbuffer2;
421  sscanf (vTextureString, "%f %f", &subbuffer1, &subbuffer2);
422  PRINTF(3)("found vertex-Texture %f, %f\n", &subbuffer1, &subbuffer2);
423  this->vTexture->addEntry(subbuffer1);
424  this->vTexture->addEntry(subbuffer2);
425  return true;
426}
427
428/**
429   \brief Function that selects a material, if changed in the obj file.
430   \param matString the Material that will be set.
431*/
432bool Model::addUseMtl (char* matString)
433{
434  /*
435  if (!this->mtlFileName)
436    {
437      PRINTF(4)("Not using new defined material, because no mtlFile found yet\n");
438      return false;
439    }
440  */     
441  if (this->currentGroup->faceCount >0)
442    this->currentGroup->currentFace = this->currentGroup->currentFace->next = new Face;
443  this->initFace (this->currentGroup->currentFace);
444 
445  this->currentGroup->currentFace->materialString = new char[strlen(matString)+1];
446  strcpy (this->currentGroup->currentFace->materialString, matString);
447 
448  if (this->currentGroup->faceCount == 0)
449    this->currentGroup->faceCount ++;
450
451}
452
453/**
454   \brief reads and includes the Faces/Materials into the openGL state Machine
455*/
456bool Model::importToGL (void)
457{
458
459  // finalize the Arrays
460  this->vertices->finalizeArray();
461  this->vTexture->finalizeArray();
462  if (normals->getCount() == 0) // vertices-Array must be uilt for this
463    this->buildVertexNormals();
464  this->normals->finalizeArray();
465
466  this->currentGroup = this->firstGroup;
467
468  while (this->currentGroup != NULL)
469    {
470
471      // creating a glList for the Group
472      if ((this->currentGroup->listNumber = glGenLists(1)) == 0)
473        {
474          PRINTF(1)("list could not be created for this Model\n");
475          return false;
476        }
477      glNewList (this->currentGroup->listNumber, GL_COMPILE);
478
479      // Putting Faces to GL
480      Face* tmpFace = this->currentGroup->firstFace;
481      while (tmpFace != NULL)
482        {
483          if (tmpFace->vertexCount == 0 && tmpFace->materialString != NULL)
484            {
485              if (this->currentGroup->faceMode != -1)
486                glEnd();
487              this->currentGroup->faceMode = 0;
488              Material* tmpMat;
489              if ((tmpMat = material->search(tmpFace->materialString)) != NULL)
490                {
491                  tmpMat->select();
492                  PRINTF(2)("using material %s for coming Faces.\n", tmpFace->materialString);
493                }
494              else 
495                PRINTF(1)("material %s not found.\n", tmpFace->materialString);
496
497
498            }
499
500          else if (tmpFace->vertexCount == 3)
501            {
502              if (this->currentGroup->faceMode != 3)
503                {
504                  if (this->currentGroup->faceMode != -1)
505                    glEnd();
506                  glBegin(GL_TRIANGLES);
507                }
508             
509              this->currentGroup->faceMode = 3;
510              PRINTF(3)("found triag.\n");
511            }
512         
513          else if (tmpFace->vertexCount == 4)
514            {
515              if (this->currentGroup->faceMode != 4)
516                {
517                  if (this->currentGroup->faceMode != -1)
518                    glEnd();
519                  glBegin(GL_QUADS);
520                }
521              this->currentGroup->faceMode = 4;
522              PRINTF(3)("found quad.\n");
523            }
524         
525          else if (tmpFace->vertexCount > 4)
526            {
527              if (this->currentGroup->faceMode != -1)
528                glEnd();
529              glBegin(GL_POLYGON);
530              PRINTF(3)("Polygon with %i faces found.", tmpFace->vertexCount);
531              this->currentGroup->faceMode = tmpFace->vertexCount;
532            }
533         
534          FaceElement* tmpElem = tmpFace->firstElem;
535          while (tmpElem != NULL)
536            {
537              //      PRINTF(2)("%s\n", tmpElem->value);
538              this->addGLElement(tmpElem);
539              tmpElem = tmpElem->next;
540            }
541          tmpFace = tmpFace->next;
542        }
543      glEnd();
544      glEndList();
545
546      this->currentGroup = this->currentGroup->next;
547    } 
548}
549
550/**
551   \brief Adds a Face-element (one vertex of a face) with all its information.
552   \param elem The FaceElement to add to the OpenGL-environment.
553
554   It does this by searching:
555   1. The Vertex itself
556   2. The VertexNormale
557   3. The VertexTextureCoordinate
558   merging this information, the face will be drawn.
559*/
560bool Model::addGLElement (FaceElement* elem)
561{
562  PRINTF(3)("importing grafical Element to openGL.\n");
563
564  if (elem->texCoordNumber != -1)
565    glTexCoord2fv(this->vTexture->getArray() + elem->texCoordNumber * 2);
566  if (elem->normalNumber != -1)
567    glNormal3fv(this->normals->getArray() + elem->normalNumber * 3);
568  if (elem->vertexNumber != -1)
569    glVertex3fv(this->vertices->getArray() + elem->vertexNumber * 3);
570
571}
572
573/**
574   \brief A routine that is able to create normals.
575
576   The algorithm does the following:
577   1. It calculates creates Vectors for each normale, and sets them to zero.
578   2. It then Walks through a) all the Groups b) all the Faces c) all the FaceElements
579   3. It searches for a points two neighbours per Face, takes Vecotrs to them calculates FaceNormals and adds it to the Points Normal.
580   4. It goes through all the normale-Points and calculates the VertexNormale and includes it in the normals-Array.
581*/
582bool Model::buildVertexNormals ()
583{
584 
585  PRINTF(2)("Normals are being calculated.\n");
586
587  Vector* normArray = new Vector [vertices->getCount()/3];
588  for (int i=0; i<vertices->getCount()/3;i++)
589    normArray[i] = Vector(.0,.0,.0);
590 
591  int firstTouch;
592  int secondTouch;
593  Vector prevV;
594  Vector nextV;
595  Vector curV;
596
597  Group* tmpGroup = firstGroup;
598  while (tmpGroup)
599    {
600      Face* tmpFace = tmpGroup->firstFace;
601      while (tmpFace)
602        {
603          if (tmpFace->firstElem)
604            {
605              FaceElement* firstElem = tmpFace->firstElem;
606              FaceElement* prevElem;
607              FaceElement* curElem = firstElem;
608              FaceElement* nextElem;
609              FaceElement* lastElem;
610              // find last Element of the Chain. !! IMPORTANT:the last Element of the Chain must point to NULL, or it will resolv into an infinity-loop.
611              while (curElem)
612                {
613                  prevElem = curElem;
614                  curElem = curElem->next;
615                }
616              lastElem = prevElem;
617             
618              curElem = firstElem;
619              for (int j=0; j<tmpFace->vertexCount; j++)
620                {
621                  if (!(nextElem = curElem->next))
622                    nextElem = firstElem;
623                  curElem->normalNumber = curElem->vertexNumber;
624                 
625                  curV = Vector (vertices->getArray()[curElem->vertexNumber*3], vertices->getArray()[curElem->vertexNumber*3+1], vertices->getArray()[curElem->vertexNumber*3+2]);
626                  prevV = Vector (vertices->getArray()[prevElem->vertexNumber*3], vertices->getArray()[prevElem->vertexNumber*3+1], vertices->getArray()[prevElem->vertexNumber*3+2]) - curV;
627                  nextV = Vector (vertices->getArray()[nextElem->vertexNumber*3], vertices->getArray()[nextElem->vertexNumber*3+1], vertices->getArray()[nextElem->vertexNumber*3+2]) - curV;
628                  normArray[curElem->vertexNumber] = normArray[curElem->vertexNumber] + nextV.cross(prevV);
629
630                  prevElem = curElem;
631                  curElem = curElem->next;
632                }
633            }
634          tmpFace = tmpFace->next;
635        }
636      tmpGroup = tmpGroup->next;
637    }
638
639  for (int i=0; i<vertices->getCount()/3;i++)
640    {
641      normArray[i].normalize();
642      PRINTF(3)("Found Normale number %d: (%f; %f, %f).\n", i, normArray[i].x, normArray[i].y, normArray[i].z);
643
644      this->normals->addEntry(normArray[i].x, normArray[i].y, normArray[i].z);
645
646    }
647  delete []normArray; 
648 
649}
650
651
652/**
653   \brief Includes a default model
654
655   This will inject a Cube, because this is the most basic model.
656*/
657void Model::BoxModel(void)
658{
659  this->addVertex ("-0.5 -0.5 0.5");
660  this->addVertex ("0.5 -0.5 0.5");
661  this->addVertex ("-0.5 0.5 0.5");
662  this->addVertex ("0.5 0.5 0.5");
663  this->addVertex ("-0.5 0.5 -0.5");
664  this->addVertex ("0.5 0.5 -0.5");
665  this->addVertex ("-0.5 -0.5 -0.5");
666  this->addVertex ("0.5 -0.5 -0.5");
667
668  this->addVertexTexture ("0.0 0.0");
669  this->addVertexTexture ("1.0 0.0");
670  this->addVertexTexture ("0.0 1.0");
671  this->addVertexTexture ("1.0 1.0");
672  this->addVertexTexture ("0.0 2.0");
673  this->addVertexTexture ("1.0 2.0");
674  this->addVertexTexture ("0.0 3.0");
675  this->addVertexTexture ("1.0 3.0");
676  this->addVertexTexture ("0.0 4.0");
677  this->addVertexTexture ("1.0 4.0");
678  this->addVertexTexture ("2.0 0.0");
679  this->addVertexTexture ("2.0 1.0");
680  this->addVertexTexture ("-1.0 0.0");
681  this->addVertexTexture ("-1.0 1.0");
682
683  this->addVertexNormal ("0.0 0.0 1.0");
684  this->addVertexNormal ("0.0 0.0 1.0");
685  this->addVertexNormal ("0.0 0.0 1.0");
686  this->addVertexNormal ("0.0 0.0 1.0");
687  this->addVertexNormal ("0.0 1.0 0.0");
688  this->addVertexNormal ("0.0 1.0 0.0");
689  this->addVertexNormal ("0.0 1.0 0.0");
690  this->addVertexNormal ("0.0 1.0 0.0");
691  this->addVertexNormal ("0.0 0.0 -1.0");
692  this->addVertexNormal ("0.0 0.0 -1.0");
693  this->addVertexNormal ("0.0 0.0 -1.0");
694  this->addVertexNormal ("0.0 0.0 -1.0");
695  this->addVertexNormal ("0.0 -1.0 0.0");
696  this->addVertexNormal ("0.0 -1.0 0.0");
697  this->addVertexNormal ("0.0 -1.0 0.0");
698  this->addVertexNormal ("0.0 -1.0 0.0");
699  this->addVertexNormal ("1.0 0.0 0.0");
700  this->addVertexNormal ("1.0 0.0 0.0");
701  this->addVertexNormal ("1.0 0.0 0.0");
702  this->addVertexNormal ("1.0 0.0 0.0");
703  this->addVertexNormal ("-1.0 0.0 0.0");
704  this->addVertexNormal ("-1.0 0.0 0.0");
705  this->addVertexNormal ("-1.0 0.0 0.0");
706  this->addVertexNormal ("-1.0 0.0 0.0");
707
708  /* normaleLess-testingMode
709  this->addFace ("1 2 4 3");
710  this->addFace ("3 4 6 5");
711  this->addFace ("5 6 8 7");
712  this->addFace ("7 8 2 1");
713  this->addFace ("2 8 6 4");
714  this->addFace ("7 1 3 5");
715  */
716
717  this->addFace ("1/1/1 2/2/2 4/4/3 3/3/4");
718  this->addFace ("3/3/5 4/4/6 6/6/7 5/5/8");
719  this->addFace ("5/5/9 6/6/10 8/8/11 7/7/12");
720  this->addFace ("7/7/13 8/8/14 2/10/15 1/9/16");
721  this->addFace ("2/2/17 8/11/18 6/12/19 4/4/20");
722  this->addFace ("7/13/21 1/1/22 3/3/23 5/14/24");
723
724}
Note: See TracBrowser for help on using the repository browser.