Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/branches/nico/src/importer/object.cc @ 3283

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

orxonox/branches: updated branches: buerli, nico, sound. And moved bezierTrack to old.bezierTrack. Conflicts resolved in a usefull order.
Conflics mostly resolved in favor of trunk
merge.

File size: 25.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"
17int verbose = 1; //! \todo should be GLOBAL
18using namespace std;
19
20/**
21   \brief Creates a 3D-Object, but does not load any 3D-models.
22
23   This Constructor is pretty useless, because why load no object in an object-loader??
24*/
25Object::Object ()
26{
27
28  this->initialize();
29
30  this->BoxObject();
31
32  this->importToGL ();
33
34  this->cleanup();
35}
36
37/**
38   \brief Crates a 3D-Object and loads in a File.
39   \param fileName file to parse and load (must be a .obj file)
40*/
41Object::Object(char* fileName)
42{
43  this->initialize();
44
45  this->importFile (fileName);
46
47  this->importToGL ();
48
49  this->cleanup();
50}
51
52/**
53   \brief Crates a 3D-Object, loads in a File and scales it.
54   \param fileName file to parse and load (must be a .obj file)
55   \param scaling The factor that the object will be scaled with.
56*/
57Object::Object(char* fileName, float scaling)
58{
59  this->initialize();
60  this->scaleFactor = scaling;
61
62  this->importFile (fileName);
63
64  this->importToGL ();
65
66  this->cleanup();
67}
68
69/**
70   \brief deletes an Object.
71
72   Looks if any from object allocated space is still in use, and if so deleted it.
73*/
74Object::~Object()
75{
76  PRINTF(2)("Deleting display Lists.\n");
77  Group* walker = this->firstGroup;
78  while (walker != NULL)
79    {
80      glDeleteLists (walker->listNumber, 1);
81      Group* delWalker = walker;
82      walker = walker->next;
83      delete delWalker;
84    }
85
86  if (this->objPath)
87    delete []this->objPath;
88  if (this->objFileName)
89    delete []this->objFileName;
90  if (this->mtlFileName)
91    delete []this->mtlFileName;
92  PRINTF(2)("Deleting Materials.\n");
93  if (this->material)
94    delete this->material;
95}
96
97
98/**
99   \brief Draws the Objects of all Groups.
100   It does this by just calling the Lists that must have been created earlier.
101*/
102void Object::draw (void) const
103{
104  PRINTF(2)("drawing the 3D-Objects\n"); 
105  Group* walker = this->firstGroup;
106  while (walker != NULL)
107    {
108      PRINTF(3)("Drawing object %s\n", walker->name);
109      glCallList (walker->listNumber);
110      walker = walker->next;
111    }
112}
113
114/**
115   \brief Draws the Object number groupNumber
116   \param groupNumber The number of the group that will be displayed.
117
118   It does this by just calling the List that must have been created earlier.
119*/
120void Object::draw (int groupNumber) const 
121{
122  if (groupNumber >= this->groupCount)
123    {
124      PRINTF(1)("You requested object number %i, but this File only contains of %i Objects.\n", groupNumber-1, this->groupCount);
125      return;
126    }
127  PRINTF(2)("drawing the requested 3D-Objects if found.\n"); 
128  Group* walker = this->firstGroup;
129  int counter = 0;
130  while (walker != NULL)
131    {
132      if (counter == groupNumber)
133        {
134          PRINTF(2)("Drawing object number %i named %s\n", counter, walker->name);
135          glCallList (walker->listNumber);
136          return;
137        }
138      ++counter;
139      walker = walker->next;
140    }
141  PRINTF(1)("Object number %i in %s not Found.\n", groupNumber, this->objFileName);
142  return;
143
144}
145
146/**
147   \brief Draws the Object with a specific groupName
148   \param groupName The name of the group that will be displayed.
149
150   It does this by just calling the List that must have been created earlier.
151*/
152void Object::draw (char* groupName) const
153{
154  PRINTF(2)("drawing the requested 3D-Objects if found.\n"); 
155  Group* walker = this->firstGroup;
156  while (walker != NULL)
157    {
158      if (!strcmp(walker->name, groupName))
159        {
160          PRINTF(2)("Drawing object %s\n", walker->name);
161          glCallList (walker->listNumber);
162          return;
163        }
164      walker = walker->next;
165    }
166  PRINTF(1)("Object Named %s in %s not Found.\n", groupName, this->objFileName);
167  return;
168}
169
170/**
171   \returns Count of the Objects in this File
172*/
173int Object::getGroupCount (void) const
174{
175  return this->groupCount;
176}
177
178/**
179    \brief initializes the Object.
180
181    This Function initializes all the needed arrays, Lists and clientStates.
182    It also defines default values.
183*/
184bool Object::initialize (void)
185{
186  PRINTF(2)("new 3D-Object is being created\n"); 
187
188  // setting the start group;
189  this->firstGroup = new Group;
190  this->currentGroup = this->firstGroup;
191  this->groupCount = 0;
192 
193  this->initGroup (this->currentGroup);
194  this->objPath = NULL;
195  this->objFileName = NULL;
196  this->mtlFileName = NULL;
197  this->scaleFactor = 1;
198  this->material = new Material();
199
200  this->vertices = new Array();
201  this->vTexture = new Array();
202  this->normals = new Array();
203
204  return true;
205}
206
207/**
208   \brief initializes a new Group object
209   \param group the group that should be initialized.
210   \todo Maybe Group should be a Class, because it does a lot of stuff
211   
212*/
213bool Object::initGroup(Group* group)
214{
215  PRINTF(3)("Adding new Group\n");
216  group->name = "";
217  group->faceMode = -1;
218  group->faceCount = 0; 
219  group->next = NULL;
220
221  group->firstFace = new Face;
222  this->initFace (group->firstFace);
223  group->currentFace = group->firstFace;
224}
225
226/**
227   \brief initializes a new Face. (sets default Values)
228   \param face The face to initialize
229*/
230bool Object::initFace (Face* face)
231{
232  face->vertexCount = 0;
233
234  face->firstElem = NULL;
235 
236  face->materialString = NULL;
237 
238  face->next = NULL;
239
240  return true;
241}
242
243/**
244   \brief finalizes an Object.
245   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.
246*/
247bool Object::cleanup(void)
248{
249  PRINTF(3)("cleaning up the 3D-Object to save Memory.\n");
250
251  if (this->vertices)
252    delete this->vertices;
253  if (this->vTexture)
254    delete this->vTexture;
255  if (this->normals)
256    delete this->normals;
257
258  this->cleanupGroup(this->firstGroup);
259  return true; 
260}
261
262/**
263   \brief Cleans up all groups starting from group.
264   \param group the first Group to clean
265*/
266bool Object::cleanupGroup (Group* group)
267{
268  PRINTF(3)("Cleaning up group\n");
269  if (group->firstFace != NULL)
270    {
271      cleanupFace (group->firstFace);
272      delete group->firstFace;
273    }
274
275  if (group->next !=NULL)
276    cleanupGroup (group->next);
277  return true;
278}
279
280/**
281   \brief Cleans up all Faces starting from face until NULL is reached.
282   \param face the first face to clean.
283*/
284bool Object::cleanupFace (Face* face)
285{
286  PRINTF(3)("Cleaning up Face\n");
287
288  if (face->materialString != NULL)
289      delete []face->materialString;
290  if (face->firstElem != NULL)
291    {
292      this->cleanupFaceElement(face->firstElem);
293      delete face->firstElem;
294    }
295     
296  if (face->next != NULL)
297    {
298      this->cleanupFace (face->next);
299      delete face->next;
300    }
301     
302}
303
304
305/**
306   \brief Cleans up all FaceElements starting from faceElem.
307   \param faceElem the first FaceElement to clean.
308*/
309bool Object::cleanupFaceElement(FaceElement* faceElem)
310{
311  if (faceElem->next != NULL)
312    {
313      this->cleanupFaceElement (faceElem->next);
314      delete faceElem->next;
315    }
316}
317
318/**
319   \brief Imports a obj file and handles the the relative location
320   \param fileName The file to import
321*/
322bool Object::importFile (char* fileName)
323{
324  PRINTF(3)("preparing to read in file: %s\n", fileName);
325
326
327#ifdef __WIN32__
328  // win32 path reading
329  char pathSplitter= '\\';
330#else /* __WIN32__ */
331  // unix path reading
332  char pathSplitter='/';
333#endif /* __WIN32__ */
334  char* tmpName = fileName;
335  if (tmpName[0] == pathSplitter)
336    tmpName++;
337  char* name = tmpName;
338  while (( tmpName = strchr (tmpName+1, pathSplitter)))
339    {
340      name = tmpName+1;
341    }
342  this->objPath = new char[name-fileName];
343  strncpy(this->objPath, fileName, name-fileName);
344  this->objPath[name-fileName] = '\0';
345  if (verbose >=2)
346    if (strlen(objPath)> 0)
347      PRINTF(0)("Resolved file %s to folder: %s.\n", name, objPath);
348    else
349      PRINTF(0)("Resolved file %s.\n", name);
350 
351  if (this->material)
352    this->material->addTexturePath(this->objPath);
353  this->objFileName = new char[strlen(name)+1];
354  strcpy (this->objFileName, name);
355  this->readFromObjFile ();
356  return true;
357}
358
359/**
360   \brief Reads in the .obj File and sets all the Values.
361   This function does read the file, parses it for the occurence of things like vertices, faces and so on, and executes the specific tasks
362*/
363bool Object::readFromObjFile (void)
364{
365  char* fileName = new char [strlen(objPath)+strlen(objFileName)+1];
366  if (this->objFileName != NULL && !strcmp(this->objFileName, ""))
367    return false;
368  strcpy(fileName, this->objPath);
369  strcat(fileName, this->objFileName);
370
371  ifstream* OBJ_FILE = new ifstream(fileName);
372  if (OBJ_FILE->fail())
373    {
374      PRINTF(1)("unable to open .OBJ file: %s\n Loading Box Object instead.\n", fileName);
375      BoxObject();
376      OBJ_FILE->close();
377      delete []fileName;
378      delete OBJ_FILE;
379      return false;
380    }
381  PRINTF(2)("Reading from opened file %s\n", fileName);
382  char Buffer[10000];
383  while(!OBJ_FILE->eof())
384    {
385      OBJ_FILE->getline(Buffer, 10000);
386      PRINTF(3)("Read input line: %s\n", Buffer);
387     
388
389      // case vertice
390      if (!strncmp(Buffer, "v ", 2))
391        {
392          this->readVertex(Buffer+2);
393        }
394
395      // case face
396      else if (!strncmp(Buffer, "f ", 2))
397        {
398          this->readFace (Buffer+2);
399        }
400     
401      else if (!strncmp(Buffer, "mtllib ", 7))
402        {
403          this->readMtlLib (Buffer+7);
404        }
405
406      else if (!strncmp(Buffer, "usemtl ", 7))
407        {
408          this->readUseMtl (Buffer+7);
409        }
410
411      // case VertexNormal
412      else if (!strncmp(Buffer, "vn ", 3))
413        {
414          this->readVertexNormal(Buffer+3);
415        }
416     
417      // case VertexTextureCoordinate
418      else if (!strncmp(Buffer, "vt ", 3))
419        {
420          this->readVertexTexture(Buffer+3);
421        }
422      // case group
423      else if (!strncmp(Buffer, "g ", 2))
424        {
425          this->readGroup (Buffer+2);
426        }
427      else if (!strncmp(Buffer, "s ", 2)) //! \todo smoothing groups have to be implemented
428        {
429          if (verbose >= 2)
430            PRINTF(2)("smoothing groups not supportet yet. line: %s\n", Buffer);
431        }
432    }
433  OBJ_FILE->close();
434  delete OBJ_FILE;
435  delete []fileName;
436  return true;
437
438}
439
440/**
441   \brief parses a group String
442   \param groupString the new Group to create
443
444   This function initializes a new Group.
445   With it you should be able to import .obj-files with more than one Objects inside.
446*/
447bool Object::readGroup (char* groupString)
448{
449  PRINTF(3)("Read Group: %s.\n", groupString);
450  if (this->groupCount != 0 && this->currentGroup->faceCount>0)
451    {
452      //      finalizeGroup(currentGroup);
453      this->currentGroup = this->currentGroup->next = new Group;
454      this->initGroup(this->currentGroup);
455    }
456  // setting the group name if not default.
457  if (strcmp(groupString, "default"))
458    {
459      this->currentGroup->name = new char [strlen(groupString)+1];
460      strcpy(this->currentGroup->name, groupString);
461    }
462  ++this->groupCount;
463
464}
465
466/**
467   \brief parses a vertex-String
468   \param vertexString The String that will be parsed.
469
470   If a vertex line is found this function will inject it into the vertex-Array
471*/
472bool Object::readVertex (char* vertexString)
473{
474  float subbuffer1;
475  float subbuffer2;
476  float subbuffer3;
477  sscanf (vertexString, "%f %f %f", &subbuffer1, &subbuffer2, &subbuffer3);
478  PRINTF(3)("reading in a vertex: %f %f %f\n", &subbuffer1, &subbuffer2, &subbuffer3);
479  this->vertices->addEntry(subbuffer1*scaleFactor, subbuffer2*scaleFactor, subbuffer3*scaleFactor);
480  return true;
481}
482
483/**
484   \brief parses a face-string
485   \param faceString The String that will be parsed.
486
487   If a face line is found this function will add it to the glList.
488   The function makes a difference between QUADS and TRIANGLES, and will if changed re-open, set and re-close the gl-processe.
489*/
490bool Object::readFace (char* faceString)
491{
492  if (this->currentGroup->faceCount >0)
493    this->currentGroup->currentFace = this->currentGroup->currentFace->next = new Face;
494  this->initFace (this->currentGroup->currentFace);
495
496  FaceElement* tmpElem = this->currentGroup->currentFace->firstElem = new FaceElement;
497  tmpElem->next = NULL;
498  while(strcmp (faceString, "\0"))
499    {
500      if (this->currentGroup->currentFace->vertexCount>0)
501          tmpElem = tmpElem->next = new FaceElement;
502      tmpElem->next = NULL;
503
504      char tmpValue [50];
505      int tmpLen;
506      char* vertex = NULL;
507      char* texture = NULL;
508      char* normal = NULL;
509
510      sscanf (faceString, "%s", tmpValue);
511      tmpLen = strlen(tmpValue);
512      vertex = tmpValue;
513
514      if ((texture = strstr (vertex, "/")) != NULL)
515        {
516          texture[0] = '\0';
517          texture ++;
518         
519          if ((normal = strstr (texture, "/")) !=NULL)
520            {
521              normal[0] = '\0';
522              normal ++;
523            }     
524        }
525      if (vertex)
526        tmpElem->vertexNumber = atoi(vertex)-1;
527      else
528        tmpElem->vertexNumber = -1;
529      if (texture)
530        tmpElem->texCoordNumber = atoi(texture)-1;
531      else
532        tmpElem->texCoordNumber = -1;
533      if (normal)
534        tmpElem->normalNumber = atoi(normal)-1;
535      else
536        tmpElem->normalNumber = -1;
537
538      faceString += tmpLen;
539      if (strcmp (faceString, "\0"))
540        faceString++;
541      this->currentGroup->currentFace->vertexCount++;
542    }
543
544  this->currentGroup->faceCount += this->currentGroup->currentFace->vertexCount -2;
545}
546
547/**
548   \brief parses a vertexNormal-String
549   \param normalString The String that will be parsed.
550
551   If a vertexNormal line is found this function will inject it into the vertexNormal-Array
552*/
553bool Object::readVertexNormal (char* normalString)
554{
555  float subbuffer1;
556  float subbuffer2;
557  float subbuffer3;
558  sscanf (normalString, "%f %f %f", &subbuffer1, &subbuffer2, &subbuffer3);
559  PRINTF(3)("found vertex-Normal %f, %f, %f\n", &subbuffer1,&subbuffer2,&subbuffer3);
560  this->normals->addEntry(subbuffer1, subbuffer2, subbuffer3);
561  return true;
562}
563
564/**
565   \brief parses a vertexTextureCoordinate-String
566   \param vTextureString The String that will be parsed.
567
568   If a vertexTextureCoordinate line is found,
569   this function will inject it into the vertexTexture-Array
570*/
571bool Object::readVertexTexture (char* vTextureString)
572{
573  float subbuffer1;
574  float subbuffer2;
575  sscanf (vTextureString, "%f %f", &subbuffer1, &subbuffer2);
576  PRINTF(3)("found vertex-Texture %f, %f\n", &subbuffer1, &subbuffer2);
577  this->vTexture->addEntry(subbuffer1);
578  this->vTexture->addEntry(subbuffer2);
579  return true;
580}
581
582/**
583    \brief Function to read in a mtl File.
584    \param mtlFile The .mtl file to read
585
586    This Function parses all Lines of an mtl File.
587    The reason for it not to be in the materials-class is,
588    that a material does not have to be able to read itself in from a File.
589
590*/
591bool Object::readMtlLib (char* mtlFile)
592{
593  this->mtlFileName = new char [strlen(mtlFile)+1];
594  strcpy(this->mtlFileName, mtlFile);
595  char* fileName = new char [strlen(objPath) + strlen(this->mtlFileName)+1];
596  strcpy(fileName, this->objPath);
597  strcat(fileName, this->mtlFileName);
598 
599
600  PRINTF(2)("Opening mtlFile: %s\n", fileName);
601
602  ifstream* MTL_FILE = new ifstream (fileName);
603  if (MTL_FILE->fail())
604    {
605      if (verbose >= 1)
606        PRINTF(2)("unable to open file: %s\n", fileName);
607      MTL_FILE->close();
608      delete []fileName;
609      delete MTL_FILE;
610      return false;
611    }
612  char Buffer[500];
613  Material* tmpMat = material;
614  while(!MTL_FILE->eof())
615    {
616      MTL_FILE->getline(Buffer, 500);
617      PRINTF(4)("found line in mtlFile: %s\n", Buffer);
618     
619
620      // create new Material
621      if (!strncmp(Buffer, "newmtl ", 7))
622        {
623          tmpMat = tmpMat->addMaterial(Buffer+7);
624          //      PRINTF(2)("%s, %p\n", tmpMat->getName(), tmpMat);
625        }
626      // setting a illumMode
627      else if (!strncmp(Buffer, "illum ", 6))
628        {
629          tmpMat->setIllum(Buffer+6);
630
631        }
632      // setting Diffuse Color
633      else if (!strncmp(Buffer, "Kd ", 3))
634        {
635          tmpMat->setDiffuse(Buffer+3);
636        }
637      // setting Ambient Color
638      else if (!strncmp(Buffer, "Ka ", 3))
639        {
640          tmpMat->setAmbient(Buffer+3);
641        }
642      // setting Specular Color
643      else if (!strncmp(Buffer, "Ks ", 3))
644        {
645          tmpMat->setSpecular(Buffer+3);
646        }
647      // setting The Specular Shininess
648      else if (!strncmp(Buffer, "Ns ", 3))
649        {
650          tmpMat->setShininess(Buffer+3);
651        }
652      // setting up transparency
653      else if (!strncmp(Buffer, "d ", 2))
654        {
655          tmpMat->setTransparency(Buffer+2);
656        }
657      else if (!strncmp(Buffer, "Tf ", 3))
658        {
659          tmpMat->setTransparency(Buffer+3);
660        }
661     
662      else if (!strncmp(Buffer, "map_Kd ", 7))
663        {
664          tmpMat->setDiffuseMap(Buffer+7);
665        }
666      else if (!strncmp(Buffer, "map_Ka ", 7))
667        {
668          tmpMat->setAmbientMap(Buffer+7);
669        }
670      else if (!strncmp(Buffer, "map_Ks ", 7))
671        {
672          tmpMat->setSpecularMap(Buffer+7);
673        }
674      else if (!strncmp(Buffer, "bump ", 5))
675        {
676          tmpMat->setBump(Buffer+7);
677        }
678     
679
680    }
681  MTL_FILE->close();
682  delete []fileName;
683  delete MTL_FILE;
684  return true;
685}
686
687/**
688   \brief Function that selects a material, if changed in the obj file.
689   \param matString the Material that will be set.
690*/
691bool Object::readUseMtl (char* matString)
692{
693  if (!this->mtlFileName)
694    {
695      PRINTF(4)("Not using new defined material, because no mtlFile found yet\n");
696      return false;
697    }
698     
699  if (this->currentGroup->faceCount >0)
700    this->currentGroup->currentFace = this->currentGroup->currentFace->next = new Face;
701  this->initFace (this->currentGroup->currentFace);
702 
703  this->currentGroup->currentFace->materialString = new char[strlen(matString)+1];
704  strcpy (this->currentGroup->currentFace->materialString, matString);
705 
706  if (this->currentGroup->faceCount == 0)
707    this->currentGroup->faceCount ++;
708
709}
710
711/**
712   \brief reads and includes the Faces/Materials into the openGL state Machine
713*/
714bool Object::importToGL (void)
715{
716
717  // finalize the Arrays
718  this->vertices->finalizeArray();
719  this->vTexture->finalizeArray();
720  if (normals->getCount() == 0) // vertices-Array must be uilt for this
721    this->buildVertexNormals();
722  this->normals->finalizeArray();
723
724  this->currentGroup = this->firstGroup;
725
726  while (this->currentGroup != NULL)
727    {
728
729      // creating a glList for the Group
730      if ((this->currentGroup->listNumber = glGenLists(1)) == 0)
731        {
732          PRINTF(1)("list could not be created for this Object\n");
733          return false;
734        }
735      glNewList (this->currentGroup->listNumber, GL_COMPILE);
736
737      // Putting Faces to GL
738      Face* tmpFace = this->currentGroup->firstFace;
739      while (tmpFace != NULL)
740        {
741          if (tmpFace->vertexCount == 0 && tmpFace->materialString != NULL)
742            {
743              if (this->currentGroup->faceMode != -1)
744                glEnd();
745              this->currentGroup->faceMode = 0;
746              PRINTF(2)("using material %s for coming Faces.\n", tmpFace->materialString);
747              Material* tmpMat;
748              if ((tmpMat = material->search(tmpFace->materialString)) != NULL)
749                tmpMat->select();
750
751            }
752
753          else if (tmpFace->vertexCount == 3)
754            {
755              if (this->currentGroup->faceMode != 3)
756                {
757                  if (this->currentGroup->faceMode != -1)
758                    glEnd();
759                  glBegin(GL_TRIANGLES);
760                }
761             
762              this->currentGroup->faceMode = 3;
763              PRINTF(3)("found triag.\n");
764            }
765         
766          else if (tmpFace->vertexCount == 4)
767            {
768              if (this->currentGroup->faceMode != 4)
769                {
770                  if (this->currentGroup->faceMode != -1)
771                    glEnd();
772                  glBegin(GL_QUADS);
773                }
774              this->currentGroup->faceMode = 4;
775              PRINTF(3)("found quad.\n");
776            }
777         
778          else if (tmpFace->vertexCount > 4)
779            {
780              if (this->currentGroup->faceMode != -1)
781                glEnd();
782              glBegin(GL_POLYGON);
783              PRINTF(3)("Polygon with %i faces found.", tmpFace->vertexCount);
784              this->currentGroup->faceMode = tmpFace->vertexCount;
785            }
786         
787          FaceElement* tmpElem = tmpFace->firstElem;
788          while (tmpElem != NULL)
789            {
790              //      PRINTF(2)("%s\n", tmpElem->value);
791              this->addGLElement(tmpElem);
792              tmpElem = tmpElem->next;
793            }
794          tmpFace = tmpFace->next;
795        }
796      glEnd();
797      glEndList();
798
799      this->currentGroup = this->currentGroup->next;
800    } 
801}
802
803/**
804   \brief Adds a Face-element (one vertex of a face) with all its information.
805   \param elem The FaceElement to add to the OpenGL-environment.
806
807   It does this by searching:
808   1. The Vertex itself
809   2. The VertexNormale
810   3. The VertexTextureCoordinate
811   merging this information, the face will be drawn.
812*/
813bool Object::addGLElement (FaceElement* elem)
814{
815  PRINTF(3)("importing grafical Element to openGL.\n");
816
817  if (elem->texCoordNumber != -1)
818    glTexCoord2fv(this->vTexture->getArray() + elem->texCoordNumber * 2);
819  if (elem->normalNumber != -1)
820    glNormal3fv(this->normals->getArray() + elem->normalNumber * 3);
821  if (elem->vertexNumber != -1)
822    glVertex3fv(this->vertices->getArray() + elem->vertexNumber * 3);
823
824}
825
826/**
827   \brief A routine that is able to create normals.
828
829   The algorithm does the following:
830   1. It calculates creates Vectors for each normale, and sets them to zero.
831   2. It then Walks through a) all the Groups b) all the Faces c) all the FaceElements
832   3. It searches for a points two neighbours per Face, takes Vecotrs to them calculates FaceNormals and adds it to the Points Normal.
833   4. It goes through all the normale-Points and calculates the VertexNormale and includes it in the normals-Array.
834*/
835bool Object::buildVertexNormals ()
836{
837 
838  PRINTF(2)("Normals are being calculated.\n");
839
840  Vector* normArray = new Vector [vertices->getCount()/3];
841  for (int i=0; i<vertices->getCount()/3;i++)
842    normArray[i] = Vector(.0,.0,.0);
843 
844  int firstTouch;
845  int secondTouch;
846  Vector prevV;
847  Vector nextV;
848  Vector curV;
849
850  Group* tmpGroup = firstGroup;
851  while (tmpGroup)
852    {
853      Face* tmpFace = tmpGroup->firstFace;
854      while (tmpFace)
855        {
856          if (tmpFace->firstElem)
857            {
858              FaceElement* firstElem = tmpFace->firstElem;
859              FaceElement* prevElem;
860              FaceElement* curElem = firstElem;
861              FaceElement* nextElem;
862              FaceElement* lastElem;
863              // 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.
864              while (curElem)
865                {
866                  prevElem = curElem;
867                  curElem = curElem->next;
868                }
869              lastElem = prevElem;
870             
871              curElem = firstElem;
872              for (int j=0; j<tmpFace->vertexCount; j++)
873                {
874                  if (!(nextElem = curElem->next))
875                    nextElem = firstElem;
876                  curElem->normalNumber = curElem->vertexNumber;
877                 
878                  curV = Vector (vertices->getArray()[curElem->vertexNumber*3], vertices->getArray()[curElem->vertexNumber*3+1], vertices->getArray()[curElem->vertexNumber*3+2]);
879                  prevV = Vector (vertices->getArray()[prevElem->vertexNumber*3], vertices->getArray()[prevElem->vertexNumber*3+1], vertices->getArray()[prevElem->vertexNumber*3+2]) - curV;
880                  nextV = Vector (vertices->getArray()[nextElem->vertexNumber*3], vertices->getArray()[nextElem->vertexNumber*3+1], vertices->getArray()[nextElem->vertexNumber*3+2]) - curV;
881                  normArray[curElem->vertexNumber] = normArray[curElem->vertexNumber] + nextV.cross(prevV);
882
883                  prevElem = curElem;
884                  curElem = curElem->next;
885                }
886            }
887          tmpFace = tmpFace->next;
888        }
889      tmpGroup = tmpGroup->next;
890    }
891
892  for (int i=0; i<vertices->getCount()/3;i++)
893    {
894      normArray[i].normalize();
895      PRINTF(3)("Found Normale number %d: (%f; %f, %f).\n", i, normArray[i].x, normArray[i].y, normArray[i].z);
896
897      this->normals->addEntry(normArray[i].x, normArray[i].y, normArray[i].z);
898
899    }
900  delete []normArray; 
901 
902}
903
904
905/**
906   \brief Includes a default object
907
908   This will inject a Cube, because this is the most basic object.
909*/
910void Object::BoxObject(void)
911{
912  this->readVertex ("-0.5 -0.5 0.5");
913  this->readVertex ("0.5 -0.5 0.5");
914  this->readVertex ("-0.5 0.5 0.5");
915  this->readVertex ("0.5 0.5 0.5");
916  this->readVertex ("-0.5 0.5 -0.5");
917  this->readVertex ("0.5 0.5 -0.5");
918  this->readVertex ("-0.5 -0.5 -0.5");
919  this->readVertex ("0.5 -0.5 -0.5");
920
921  this->readVertexTexture ("0.0 0.0");
922  this->readVertexTexture ("1.0 0.0");
923  this->readVertexTexture ("0.0 1.0");
924  this->readVertexTexture ("1.0 1.0");
925  this->readVertexTexture ("0.0 2.0");
926  this->readVertexTexture ("1.0 2.0");
927  this->readVertexTexture ("0.0 3.0");
928  this->readVertexTexture ("1.0 3.0");
929  this->readVertexTexture ("0.0 4.0");
930  this->readVertexTexture ("1.0 4.0");
931  this->readVertexTexture ("2.0 0.0");
932  this->readVertexTexture ("2.0 1.0");
933  this->readVertexTexture ("-1.0 0.0");
934  this->readVertexTexture ("-1.0 1.0");
935
936  this->readVertexNormal ("0.0 0.0 1.0");
937  this->readVertexNormal ("0.0 0.0 1.0");
938  this->readVertexNormal ("0.0 0.0 1.0");
939  this->readVertexNormal ("0.0 0.0 1.0");
940  this->readVertexNormal ("0.0 1.0 0.0");
941  this->readVertexNormal ("0.0 1.0 0.0");
942  this->readVertexNormal ("0.0 1.0 0.0");
943  this->readVertexNormal ("0.0 1.0 0.0");
944  this->readVertexNormal ("0.0 0.0 -1.0");
945  this->readVertexNormal ("0.0 0.0 -1.0");
946  this->readVertexNormal ("0.0 0.0 -1.0");
947  this->readVertexNormal ("0.0 0.0 -1.0");
948  this->readVertexNormal ("0.0 -1.0 0.0");
949  this->readVertexNormal ("0.0 -1.0 0.0");
950  this->readVertexNormal ("0.0 -1.0 0.0");
951  this->readVertexNormal ("0.0 -1.0 0.0");
952  this->readVertexNormal ("1.0 0.0 0.0");
953  this->readVertexNormal ("1.0 0.0 0.0");
954  this->readVertexNormal ("1.0 0.0 0.0");
955  this->readVertexNormal ("1.0 0.0 0.0");
956  this->readVertexNormal ("-1.0 0.0 0.0");
957  this->readVertexNormal ("-1.0 0.0 0.0");
958  this->readVertexNormal ("-1.0 0.0 0.0");
959  this->readVertexNormal ("-1.0 0.0 0.0");
960
961  /* normaleLess-testingMode
962  this->readFace ("1 2 4 3");
963  this->readFace ("3 4 6 5");
964  this->readFace ("5 6 8 7");
965  this->readFace ("7 8 2 1");
966  this->readFace ("2 8 6 4");
967  this->readFace ("7 1 3 5");
968  */
969
970  this->readFace ("1/1/1 2/2/2 4/4/3 3/3/4");
971  this->readFace ("3/3/5 4/4/6 6/6/7 5/5/8");
972  this->readFace ("5/5/9 6/6/10 8/8/11 7/7/12");
973  this->readFace ("7/7/13 8/8/14 2/10/15 1/9/16");
974  this->readFace ("2/2/17 8/11/18 6/12/19 4/4/20");
975  this->readFace ("7/13/21 1/1/22 3/3/23 5/14/24");
976
977}
Note: See TracBrowser for help on using the repository browser.