Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: merged branches/parenting back to the.
merged with command:
svn merge branches/parenting trunk -r 3247:HEAD
resolved all conflicts in favor of parenting.

File size: 25.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 Crates a 3D-Model and loads in a File.
39   \param fileName file to parse and load (must be a .obj file)
40*/
41Model::Model(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-Model, 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 model will be scaled with.
56*/
57Model::Model(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 Model.
71
72   Looks if any from model allocated space is still in use, and if so deleted it.
73*/
74Model::~Model()
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 Models of all Groups.
100   It does this by just calling the Lists that must have been created earlier.
101*/
102void Model::draw (void) const
103{
104  PRINTF(2)("drawing the 3D-Models\n"); 
105  Group* walker = this->firstGroup;
106  while (walker != NULL)
107    {
108      PRINTF(3)("Drawing model %s\n", walker->name);
109      glCallList (walker->listNumber);
110      walker = walker->next;
111    }
112}
113
114/**
115   \brief Draws the Model 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 Model::draw (int groupNumber) const 
121{
122  if (groupNumber >= this->groupCount)
123    {
124      PRINTF(1)("You requested model number %i, but this File only contains of %i Models.\n", groupNumber-1, this->groupCount);
125      return;
126    }
127  PRINTF(2)("drawing the requested 3D-Models 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 model 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)("Model number %i in %s not Found.\n", groupNumber, this->objFileName);
142  return;
143
144}
145
146/**
147   \brief Draws the Model 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 Model::draw (char* groupName) const
153{
154  PRINTF(2)("drawing the requested 3D-Models if found.\n"); 
155  Group* walker = this->firstGroup;
156  while (walker != NULL)
157    {
158      if (!strcmp(walker->name, groupName))
159        {
160          PRINTF(2)("Drawing model %s\n", walker->name);
161          glCallList (walker->listNumber);
162          return;
163        }
164      walker = walker->next;
165    }
166  PRINTF(1)("Model Named %s in %s not Found.\n", groupName, this->objFileName);
167  return;
168}
169
170/**
171   \returns Count of the Models in this File
172*/
173int Model::getGroupCount (void) const
174{
175  return this->groupCount;
176}
177
178/**
179    \brief initializes the Model.
180
181    This Function initializes all the needed arrays, Lists and clientStates.
182    It also defines default values.
183*/
184bool Model::initialize (void)
185{
186  PRINTF(2)("new 3D-Model 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 model
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 Model::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 Model::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 Model.
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 Model::cleanup(void)
248{
249  PRINTF(3)("cleaning up the 3D-Model 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 Model::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 Model::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 Model::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 Model::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 Model::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 Model instead.\n", fileName);
375      BoxModel();
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 Models inside.
446*/
447bool Model::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 Model::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 Model::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 Model::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 Model::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 Model::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(3)("Opening mtlFile: %s\n", fileName);
601
602  ifstream* MTL_FILE = new ifstream (fileName);
603  if (MTL_FILE->fail())
604    {
605      PRINTF(1)("unable to open file: %s\n", fileName);
606      MTL_FILE->close();
607      delete []fileName;
608      delete MTL_FILE;
609      return false;
610    }
611  char Buffer[500];
612  Material* tmpMat = material;
613  while(!MTL_FILE->eof())
614    {
615      MTL_FILE->getline(Buffer, 500);
616      PRINTF(4)("found line in mtlFile: %s\n", Buffer);
617     
618
619      // create new Material
620      if (!strncmp(Buffer, "newmtl ", 7))
621        {
622          tmpMat = tmpMat->addMaterial(Buffer+7);
623          //      PRINTF(2)("%s, %p\n", tmpMat->getName(), tmpMat);
624        }
625      // setting a illumMode
626      else if (!strncmp(Buffer, "illum ", 6))
627        {
628          tmpMat->setIllum(Buffer+6);
629
630        }
631      // setting Diffuse Color
632      else if (!strncmp(Buffer, "Kd ", 3))
633        {
634          tmpMat->setDiffuse(Buffer+3);
635        }
636      // setting Ambient Color
637      else if (!strncmp(Buffer, "Ka ", 3))
638        {
639          tmpMat->setAmbient(Buffer+3);
640        }
641      // setting Specular Color
642      else if (!strncmp(Buffer, "Ks ", 3))
643        {
644          tmpMat->setSpecular(Buffer+3);
645        }
646      // setting The Specular Shininess
647      else if (!strncmp(Buffer, "Ns ", 3))
648        {
649          tmpMat->setShininess(Buffer+3);
650        }
651      // setting up transparency
652      else if (!strncmp(Buffer, "d ", 2))
653        {
654          tmpMat->setTransparency(Buffer+2);
655        }
656      else if (!strncmp(Buffer, "Tf ", 3))
657        {
658          tmpMat->setTransparency(Buffer+3);
659        }
660     
661      else if (!strncmp(Buffer, "map_Kd ", 7))
662        {
663          tmpMat->setDiffuseMap(Buffer+7);
664        }
665      else if (!strncmp(Buffer, "map_Ka ", 7))
666        {
667          tmpMat->setAmbientMap(Buffer+7);
668        }
669      else if (!strncmp(Buffer, "map_Ks ", 7))
670        {
671          tmpMat->setSpecularMap(Buffer+7);
672        }
673      else if (!strncmp(Buffer, "bump ", 5))
674        {
675          tmpMat->setBump(Buffer+7);
676        }
677     
678
679    }
680  MTL_FILE->close();
681  delete []fileName;
682  delete MTL_FILE;
683  return true;
684}
685
686/**
687   \brief Function that selects a material, if changed in the obj file.
688   \param matString the Material that will be set.
689*/
690bool Model::readUseMtl (char* matString)
691{
692  if (!this->mtlFileName)
693    {
694      PRINTF(4)("Not using new defined material, because no mtlFile found yet\n");
695      return false;
696    }
697     
698  if (this->currentGroup->faceCount >0)
699    this->currentGroup->currentFace = this->currentGroup->currentFace->next = new Face;
700  this->initFace (this->currentGroup->currentFace);
701 
702  this->currentGroup->currentFace->materialString = new char[strlen(matString)+1];
703  strcpy (this->currentGroup->currentFace->materialString, matString);
704 
705  if (this->currentGroup->faceCount == 0)
706    this->currentGroup->faceCount ++;
707
708}
709
710/**
711   \brief reads and includes the Faces/Materials into the openGL state Machine
712*/
713bool Model::importToGL (void)
714{
715
716  // finalize the Arrays
717  this->vertices->finalizeArray();
718  this->vTexture->finalizeArray();
719  if (normals->getCount() == 0) // vertices-Array must be uilt for this
720    this->buildVertexNormals();
721  this->normals->finalizeArray();
722
723  this->currentGroup = this->firstGroup;
724
725  while (this->currentGroup != NULL)
726    {
727
728      // creating a glList for the Group
729      if ((this->currentGroup->listNumber = glGenLists(1)) == 0)
730        {
731          PRINTF(1)("list could not be created for this Model\n");
732          return false;
733        }
734      glNewList (this->currentGroup->listNumber, GL_COMPILE);
735
736      // Putting Faces to GL
737      Face* tmpFace = this->currentGroup->firstFace;
738      while (tmpFace != NULL)
739        {
740          if (tmpFace->vertexCount == 0 && tmpFace->materialString != NULL)
741            {
742              if (this->currentGroup->faceMode != -1)
743                glEnd();
744              this->currentGroup->faceMode = 0;
745              PRINTF(2)("using material %s for coming Faces.\n", tmpFace->materialString);
746              Material* tmpMat;
747              if ((tmpMat = material->search(tmpFace->materialString)) != NULL)
748                tmpMat->select();
749
750            }
751
752          else if (tmpFace->vertexCount == 3)
753            {
754              if (this->currentGroup->faceMode != 3)
755                {
756                  if (this->currentGroup->faceMode != -1)
757                    glEnd();
758                  glBegin(GL_TRIANGLES);
759                }
760             
761              this->currentGroup->faceMode = 3;
762              PRINTF(3)("found triag.\n");
763            }
764         
765          else if (tmpFace->vertexCount == 4)
766            {
767              if (this->currentGroup->faceMode != 4)
768                {
769                  if (this->currentGroup->faceMode != -1)
770                    glEnd();
771                  glBegin(GL_QUADS);
772                }
773              this->currentGroup->faceMode = 4;
774              PRINTF(3)("found quad.\n");
775            }
776         
777          else if (tmpFace->vertexCount > 4)
778            {
779              if (this->currentGroup->faceMode != -1)
780                glEnd();
781              glBegin(GL_POLYGON);
782              PRINTF(3)("Polygon with %i faces found.", tmpFace->vertexCount);
783              this->currentGroup->faceMode = tmpFace->vertexCount;
784            }
785         
786          FaceElement* tmpElem = tmpFace->firstElem;
787          while (tmpElem != NULL)
788            {
789              //      PRINTF(2)("%s\n", tmpElem->value);
790              this->addGLElement(tmpElem);
791              tmpElem = tmpElem->next;
792            }
793          tmpFace = tmpFace->next;
794        }
795      glEnd();
796      glEndList();
797
798      this->currentGroup = this->currentGroup->next;
799    } 
800}
801
802/**
803   \brief Adds a Face-element (one vertex of a face) with all its information.
804   \param elem The FaceElement to add to the OpenGL-environment.
805
806   It does this by searching:
807   1. The Vertex itself
808   2. The VertexNormale
809   3. The VertexTextureCoordinate
810   merging this information, the face will be drawn.
811*/
812bool Model::addGLElement (FaceElement* elem)
813{
814  PRINTF(3)("importing grafical Element to openGL.\n");
815
816  if (elem->texCoordNumber != -1)
817    glTexCoord2fv(this->vTexture->getArray() + elem->texCoordNumber * 2);
818  if (elem->normalNumber != -1)
819    glNormal3fv(this->normals->getArray() + elem->normalNumber * 3);
820  if (elem->vertexNumber != -1)
821    glVertex3fv(this->vertices->getArray() + elem->vertexNumber * 3);
822
823}
824
825/**
826   \brief A routine that is able to create normals.
827
828   The algorithm does the following:
829   1. It calculates creates Vectors for each normale, and sets them to zero.
830   2. It then Walks through a) all the Groups b) all the Faces c) all the FaceElements
831   3. It searches for a points two neighbours per Face, takes Vecotrs to them calculates FaceNormals and adds it to the Points Normal.
832   4. It goes through all the normale-Points and calculates the VertexNormale and includes it in the normals-Array.
833*/
834bool Model::buildVertexNormals ()
835{
836 
837  PRINTF(2)("Normals are being calculated.\n");
838
839  Vector* normArray = new Vector [vertices->getCount()/3];
840  for (int i=0; i<vertices->getCount()/3;i++)
841    normArray[i] = Vector(.0,.0,.0);
842 
843  int firstTouch;
844  int secondTouch;
845  Vector prevV;
846  Vector nextV;
847  Vector curV;
848
849  Group* tmpGroup = firstGroup;
850  while (tmpGroup)
851    {
852      Face* tmpFace = tmpGroup->firstFace;
853      while (tmpFace)
854        {
855          if (tmpFace->firstElem)
856            {
857              FaceElement* firstElem = tmpFace->firstElem;
858              FaceElement* prevElem;
859              FaceElement* curElem = firstElem;
860              FaceElement* nextElem;
861              FaceElement* lastElem;
862              // 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.
863              while (curElem)
864                {
865                  prevElem = curElem;
866                  curElem = curElem->next;
867                }
868              lastElem = prevElem;
869             
870              curElem = firstElem;
871              for (int j=0; j<tmpFace->vertexCount; j++)
872                {
873                  if (!(nextElem = curElem->next))
874                    nextElem = firstElem;
875                  curElem->normalNumber = curElem->vertexNumber;
876                 
877                  curV = Vector (vertices->getArray()[curElem->vertexNumber*3], vertices->getArray()[curElem->vertexNumber*3+1], vertices->getArray()[curElem->vertexNumber*3+2]);
878                  prevV = Vector (vertices->getArray()[prevElem->vertexNumber*3], vertices->getArray()[prevElem->vertexNumber*3+1], vertices->getArray()[prevElem->vertexNumber*3+2]) - curV;
879                  nextV = Vector (vertices->getArray()[nextElem->vertexNumber*3], vertices->getArray()[nextElem->vertexNumber*3+1], vertices->getArray()[nextElem->vertexNumber*3+2]) - curV;
880                  normArray[curElem->vertexNumber] = normArray[curElem->vertexNumber] + nextV.cross(prevV);
881
882                  prevElem = curElem;
883                  curElem = curElem->next;
884                }
885            }
886          tmpFace = tmpFace->next;
887        }
888      tmpGroup = tmpGroup->next;
889    }
890
891  for (int i=0; i<vertices->getCount()/3;i++)
892    {
893      normArray[i].normalize();
894      PRINTF(3)("Found Normale number %d: (%f; %f, %f).\n", i, normArray[i].x, normArray[i].y, normArray[i].z);
895
896      this->normals->addEntry(normArray[i].x, normArray[i].y, normArray[i].z);
897
898    }
899  delete []normArray; 
900 
901}
902
903
904/**
905   \brief Includes a default model
906
907   This will inject a Cube, because this is the most basic model.
908*/
909void Model::BoxModel(void)
910{
911  this->readVertex ("-0.5 -0.5 0.5");
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
920  this->readVertexTexture ("0.0 0.0");
921  this->readVertexTexture ("1.0 0.0");
922  this->readVertexTexture ("0.0 1.0");
923  this->readVertexTexture ("1.0 1.0");
924  this->readVertexTexture ("0.0 2.0");
925  this->readVertexTexture ("1.0 2.0");
926  this->readVertexTexture ("0.0 3.0");
927  this->readVertexTexture ("1.0 3.0");
928  this->readVertexTexture ("0.0 4.0");
929  this->readVertexTexture ("1.0 4.0");
930  this->readVertexTexture ("2.0 0.0");
931  this->readVertexTexture ("2.0 1.0");
932  this->readVertexTexture ("-1.0 0.0");
933  this->readVertexTexture ("-1.0 1.0");
934
935  this->readVertexNormal ("0.0 0.0 1.0");
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 1.0 0.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 0.0 -1.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 -1.0 0.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 ("1.0 0.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
960  /* normaleLess-testingMode
961  this->readFace ("1 2 4 3");
962  this->readFace ("3 4 6 5");
963  this->readFace ("5 6 8 7");
964  this->readFace ("7 8 2 1");
965  this->readFace ("2 8 6 4");
966  this->readFace ("7 1 3 5");
967  */
968
969  this->readFace ("1/1/1 2/2/2 4/4/3 3/3/4");
970  this->readFace ("3/3/5 4/4/6 6/6/7 5/5/8");
971  this->readFace ("5/5/9 6/6/10 8/8/11 7/7/12");
972  this->readFace ("7/7/13 8/8/14 2/10/15 1/9/16");
973  this->readFace ("2/2/17 8/11/18 6/12/19 4/4/20");
974  this->readFace ("7/13/21 1/1/22 3/3/23 5/14/24");
975
976}
Note: See TracBrowser for help on using the repository browser.