Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/branches/md2_loader/src/lib/graphics/importer/md2Model.cc @ 4172

Last change on this file since 4172 was 4172, checked in by patrick, 19 years ago

orxonox/branches/md2_loader: reimplemente the whole md2_loader to make it more performant

File size: 19.0 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   ### File Specific:
12   main-programmer: Patrick Boenzli
13*/
14
15#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_IMPORTER
16
17#include "md2Model.h"
18#include "material.h"
19
20#include <fstream>
21#include <string>
22#include <vector>
23
24
25using namespace std;
26
27/********************************************************************************
28 *   MD2MODEL                                                                   *
29 ********************************************************************************/
30
31/**
32   \brief standard constructor
33   
34   creates a new model
35*/
36MD2Model::MD2Model () 
37{
38  this->setClassName ("MD2Model");
39
40  MD2Loader* md2loader = new MD2Loader();
41  this->model = new t3DModel;
42  md2loader->importMD2(this->model, "../data/models/tris.md2");
43  delete md2loader;
44}
45
46
47/**
48   \brief standard deconstructor
49
50*/
51MD2Model::~MD2Model () 
52{
53  // delete what has to be deleted here
54}
55
56
57void MD2Model::animate()
58{
59  if( unlikely(this->model->objectList.size() <= 0)) return;
60  /* get current animation from the list */
61  tAnimationInfo *pAnim = &(this->model->animationList[this->model->currentAnim]);
62
63  int nextFrame = (this->model->currentFrame + 1) % pAnim->endFrame;
64  if( unlikely(nextFrame == 0)) 
65    nextFrame =  pAnim->startFrame;
66
67  t3DObject *pFrame = &this->model->objectList[this->model->currentFrame];
68  t3DObject *pNextFrame = &this->model->objectList[nextFrame];
69
70  /* we have stored the texture and face information only in the first frame */
71  t3DObject *pFirstFrame = &this->model->objectList[0];
72
73  /* get the current time as a value in the domain [0..1] :)) */
74  float t = this->getCurrentTime(this->model, nextFrame);
75
76  glBegin(GL_TRIANGLES);
77  for(int j = 0; j < pFrame->numOfFaces; j++)
78    {
79      for(int whichVertex = 0; whichVertex < 3; whichVertex++)
80        {
81          int vertIndex = pFirstFrame->pFaces[j].vertIndex[whichVertex];
82          int texIndex  = pFirstFrame->pFaces[j].coordIndex[whichVertex];
83                                               
84          if( likely(pFirstFrame->pTexVerts != NULL)) 
85            {
86              glTexCoord2f(pFirstFrame->pTexVerts[texIndex].x, 
87                           pFirstFrame->pTexVerts[texIndex].y);
88            }
89                       
90          /* here comes the interpolation part */
91          CVector3 vPoint1 = pFrame->pVerts[vertIndex];
92          CVector3 vPoint2 = pNextFrame->pVerts[vertIndex];
93          glVertex3f(vPoint1.x + t * (vPoint2.x - vPoint1.x), 
94                     vPoint1.y + t * (vPoint2.y - vPoint1.y),
95                     vPoint1.z + t * (vPoint2.z - vPoint1.z));
96        }
97    }
98  glEnd();
99}
100
101
102float MD2Model::getCurrentTime(t3DModel *pModel, int nextFrame)
103{
104  /* stretch the time with animation speed (and make seconds out of it) */
105  //float t = this->dtS / kAnimationSpeed;
106       
107  if ( unlikely(this->localTime*1000.0 >=  1000.0/kAnimationSpeed) )
108    {
109      pModel->currentFrame = nextFrame;
110      this->localTime = 0.0f;
111    }
112  return (this->localTime / kAnimationSpeed);
113}
114
115
116void MD2Model::tick(float dtS)
117{
118  this->localTime += dtS;
119}
120
121/**
122   \brief draw function
123 
124   these function will take NO argument in the final version, just for testing
125*/
126void MD2Model::draw()
127{
128  if( this->model->objectList.size() <= 0) return;
129
130  t3DObject *pObject = &this->model->objectList[0];
131  glBegin(GL_TRIANGLES);
132  for(int j = 0; j < pObject->numOfFaces; j++)
133    {
134      for(int whichVertex = 0; whichVertex < 3; whichVertex++)
135        {
136          int index = pObject->pFaces[j].vertIndex[whichVertex];
137          int index2 = pObject->pFaces[j].coordIndex[whichVertex];
138          /* we invert the normals since the md2 file format uses different style */
139          /* FIX FIX FIX: ther are actualy no reasons to compute the normals every frame: change this later*/
140          glNormal3f(-pObject->pNormals[index].x, -pObject->pNormals[index].y, -pObject->pNormals[index].z);
141
142          if( likely(pObject->pTexVerts != NULL)) 
143            {
144              glTexCoord2f(pObject->pTexVerts[index2].x, pObject->pTexVerts[index2].y);
145            }
146          glVertex3f(pObject->pVerts[index].x, pObject->pVerts[index].y, pObject->pVerts[index].z);
147        }
148    }
149  glEnd();
150}
151
152/********************************************************************************
153 *   MD2LOADER                                                                  *
154 ********************************************************************************/
155
156/**
157   \brief standard deconstructor
158   creates a new model loader
159*/
160MD2Loader::MD2Loader()
161{
162  this->setClassName ("MD2Loader");
163  /* initialize all data to initial state */
164  memset(&this->header, 0, sizeof(tMd2Header));
165  this->pSkins = NULL;
166  this->pTexCoords = NULL;
167  this->pTriangles = NULL;
168  this->pFrames = NULL;
169}
170
171/**
172   \brief standard deconstructor
173*/
174MD2Loader::~MD2Loader()
175{}
176 
177
178/**
179   \brief this is called by the client to open the .Md2 file, read it, then clean up
180   \param model to load in
181   \param file name to load
182   \param texture name to load
183*/
184bool MD2Loader::importMD2(t3DModel *pModel, char *fileName, char *textureName)
185{
186  this->pFile = fopen(fileName, "rb");
187  if( unlikely(!pFile)) 
188    {
189      PRINTF(1)("Couldn't open the MD2 File for loading. Exiting.\n");
190      return false;
191    }
192  fread(&this->header, 1, sizeof(tMd2Header), pFile);
193  /* check for the header version: make sure its a md2 file :) */
194  if( likely(this->header.version != 8))
195    {
196      PRINTF(1)("Couldn't load file %s: invalid file format: stop loading\n", fileName);
197      return false;
198    }
199       
200  this->readMD2Data();
201  this->convertDataStructures(pModel);
202  this->computeNormals(pModel);
203
204  if( likely((int)textureName))
205    {
206      tMaterialInfo textureInfo;
207      strcpy(textureInfo.strFile, textureName);
208      /* since there is only one texture for a .Md2 file, the ID is always 0 */
209      textureInfo.texureId = 0;
210      textureInfo.uTile = 1;
211      /* we only have 1 material for a model */
212      pModel->numOfMaterials = 1;
213      pModel->materialList.push_back(textureInfo);
214    }
215       
216  this->cleanUp();
217  return true;
218}
219
220
221/**
222   \brief This function reads in all of the model's data, except the animation frames
223*/
224void MD2Loader::readMD2Data()
225{
226  unsigned char buffer[MD2_MAX_FRAMESIZE];
227  this->pSkins     = new tMd2Skin[this->header.numSkins];
228  this->pTexCoords = new tMd2TexCoord[this->header.numTexCoords];
229  this->pTriangles = new tMd2Face[this->header.numTriangles];
230  this->pFrames    = new tMd2Frame[this->header.numFrames];
231
232  /* we read the skins */
233  fseek(this->pFile, this->header.offsetSkins, SEEK_SET);
234  fread(this->pSkins, sizeof(tMd2Skin), this->header.numSkins, this->pFile);
235  /* read all vertex data */
236  fseek(this->pFile, this->header.offsetTexCoords, SEEK_SET);
237  fread(this->pTexCoords, sizeof(tMd2TexCoord), this->header.numTexCoords, this->pFile);
238  /* read face data for each triangle (normals) */
239  fseek(this->pFile, this->header.offsetTriangles, SEEK_SET);
240  fread(this->pTriangles, sizeof(tMd2Face), this->header.numTriangles, this->pFile);
241  /* reading all frame data */
242  fseek(this->pFile, this->header.offsetFrames, SEEK_SET);
243  for( int i = 0; i < this->header.numFrames; i++)
244    {
245      tMd2AliasFrame *pFrame = (tMd2AliasFrame *) buffer;
246      this->pFrames[i].pVertices = new tMd2Triangle [this->header.numVertices];
247
248      /* read the frame animation data */
249      fread(pFrame, 1, this->header.frameSize, this->pFile);
250      strcpy(this->pFrames[i].strName, pFrame->name);
251      tMd2Triangle *pVertices = this->pFrames[i].pVertices;
252      /*
253         scale translations, store vertices: since id used a non-opengl xyz notation, we have to swap y and z
254         and negate z axis
255      */
256      for( int j = 0; j < this->header.numVertices; j++)
257        {
258          pVertices[j].vertex[0] = pFrame->aliasVertices[j].vertex[0] * pFrame->scale[0] + pFrame->translate[0];
259          pVertices[j].vertex[2] = -1 * (pFrame->aliasVertices[j].vertex[1] * pFrame->scale[1] + pFrame->translate[1]);
260          pVertices[j].vertex[1] = pFrame->aliasVertices[j].vertex[2] * pFrame->scale[2] + pFrame->translate[2];
261        }
262    }
263}
264
265
266/**
267   \brief this function fills in the animation list for each animation by name and frame
268   \param model
269*/
270void MD2Loader::parseAnimations(t3DModel *pModel)
271{
272  tAnimationInfo animationInfo;
273  string strLastName = "";
274
275  /* the animation parse process looks a little bit wired: this is because there are no
276     fix bounds for the animation lengths, so the frames are destingushed using their names
277     which is normaly composed of <animationname><number>
278  */
279
280  for(int i = 0; i < pModel->numOfObjects; i++)
281    {
282      string strName  = this->pFrames[i].strName;
283      int frameNum = 0;
284       
285      /* erease the frame number from the frame-name */
286      for(unsigned int j = 0; j < strName.length(); j++)
287        {
288          if( isdigit(strName[j]) && j >= strName.length() - 2)
289            {
290              frameNum = atoi(&strName[j]);
291              strName.erase(j, strName.length() - j);
292              break;
293            }
294        }
295
296      printf("current: %s, last: %s\n", strName.c_str(), strLastName.c_str());
297
298      /* animations are sorted through their names: this is how its been done: */
299      if( strName != strLastName || i == pModel->numOfObjects - 1)
300        {
301          if( strLastName != "")
302            {
303              strcpy(animationInfo.strName, strLastName.c_str());
304              animationInfo.endFrame = i;
305              pModel->animationList.push_back(animationInfo);
306              memset(&animationInfo, 0, sizeof(tAnimationInfo));
307              pModel->numOfAnimations++;
308            }
309          animationInfo.startFrame = frameNum - 1 + i;
310        }
311      strLastName = strName;
312    }
313}
314
315
316/**
317   \brief this function converts the .md2 structures to our own model and object structures: decompress
318   \param model
319*/
320void MD2Loader::convertDataStructures(t3DModel *pModel)
321{
322  int j = 0, i = 0;
323       
324  memset(pModel, 0, sizeof(t3DModel));
325  pModel->numOfObjects = this->header.numFrames;
326
327  this->parseAnimations(pModel);
328
329  for (i = 0; i < pModel->numOfObjects; i++)
330    {
331      t3DObject currentFrame;
332
333      currentFrame.numOfVerts = this->header.numVertices;
334      currentFrame.numTexVertex = this->header.numTexCoords;
335      currentFrame.numOfFaces = this->header.numTriangles;
336
337      currentFrame.pVerts = new CVector3[currentFrame.numOfVerts];
338
339      for (j = 0; j < currentFrame.numOfVerts; j++)
340        {
341          currentFrame.pVerts[j].x = this->pFrames[i].pVertices[j].vertex[0];
342          currentFrame.pVerts[j].y = this->pFrames[i].pVertices[j].vertex[1];
343          currentFrame.pVerts[j].z = this->pFrames[i].pVertices[j].vertex[2];
344        }
345
346      delete this->pFrames[i].pVertices;
347
348      if( likely(i > 0))
349        {
350          pModel->objectList.push_back(currentFrame);
351          continue;
352        }
353                       
354      currentFrame.pTexVerts = new CVector2[currentFrame.numTexVertex];
355      currentFrame.pFaces = new tFace[currentFrame.numOfFaces];
356
357      for(j = 0; j < currentFrame.numTexVertex; j++)
358        {
359          currentFrame.pTexVerts[j].x = this->pTexCoords[j].u / float(this->header.skinWidth);
360          currentFrame.pTexVerts[j].y = 1 - this->pTexCoords[j].v / float(this->header.skinHeight);
361        }
362
363      for(j = 0; j < currentFrame.numOfFaces; j++)
364        {
365          currentFrame.pFaces[j].vertIndex[0] = this->pTriangles[j].vertexIndices[0];
366          currentFrame.pFaces[j].vertIndex[1] = this->pTriangles[j].vertexIndices[1];
367          currentFrame.pFaces[j].vertIndex[2] = this->pTriangles[j].vertexIndices[2];
368
369          currentFrame.pFaces[j].coordIndex[0] = this->pTriangles[j].textureIndices[0];
370          currentFrame.pFaces[j].coordIndex[1] = this->pTriangles[j].textureIndices[1];
371          currentFrame.pFaces[j].coordIndex[2] = this->pTriangles[j].textureIndices[2];
372        }
373      pModel->objectList.push_back(currentFrame);
374    }
375}
376
377
378/**
379   \brief this function conputes the normals of the model
380   \param model
381*/
382void MD2Loader::computeNormals(t3DModel *pModel)
383{
384  CVector3 vVector1, vVector2, vNormal, vPoly[3];
385
386  if( unlikely(pModel->numOfObjects <= 0))
387    return;
388  /* now computing face normals: this means just averaging the vertex normals of a face */
389  /* so for every object: */
390  for(int index = 0; index < pModel->numOfObjects; index++)
391    {
392      t3DObject *pObject = &(pModel->objectList[index]);
393
394      /* allocate all the memory we need to calculate the normals */
395      CVector3 *pNormals = new CVector3 [pObject->numOfFaces];
396      CVector3 *pTempNormals = new CVector3 [pObject->numOfFaces];
397      pObject->pNormals = new CVector3 [pObject->numOfVerts];
398
399      for(int i=0; i < pObject->numOfFaces; i++)
400        {
401          /* cache the points to make coding easier :) */
402          vPoly[0] = pObject->pVerts[pObject->pFaces[i].vertIndex[0]];
403          vPoly[1] = pObject->pVerts[pObject->pFaces[i].vertIndex[1]];
404          vPoly[2] = pObject->pVerts[pObject->pFaces[i].vertIndex[2]];
405
406          vVector1 = MathHelp::VectorDiff(vPoly[0], vPoly[2]);         
407          vVector2 = MathHelp::VectorDiff(vPoly[2], vPoly[1]);         
408                       
409          vNormal  = MathHelp::CrossProduct(vVector1, vVector2);               
410          pTempNormals[i] = vNormal;                                   
411          vNormal  = MathHelp::NormalizeVector(vNormal);                               
412
413          pNormals[i] = vNormal;
414        }
415
416      /* now calculating vertex normals */
417      CVector3 vSum = {0.0, 0.0, 0.0};
418      CVector3 vZero = vSum;
419      int shared=0;
420
421      for (int i = 0; i < pObject->numOfVerts; i++)                     
422        {
423          for (int j = 0; j < pObject->numOfFaces; j++) 
424            {                                                                                           
425              if (pObject->pFaces[j].vertIndex[0] == i || 
426                  pObject->pFaces[j].vertIndex[1] == i || 
427                  pObject->pFaces[j].vertIndex[2] == i)
428                {
429                  vSum = MathHelp::AddVector(vSum, pTempNormals[j]);
430                  shared++;                                                                                             }
431            }     
432          pObject->pNormals[i] = MathHelp::DivideVectorByScaler(vSum, float(-shared));
433          pObject->pNormals[i] = MathHelp::NormalizeVector(pObject->pNormals[i]);       
434
435          vSum = vZero;                                                                 
436          shared = 0;                                                                           
437        }
438      delete [] pTempNormals;
439      delete [] pNormals;
440    }
441}
442
443
444/**
445   \brief This function cleans up our allocated memory and closes the file
446*/
447void MD2Loader::cleanUp()
448{
449  fclose(this->pFile);                 
450       
451  if( this->pSkins) delete [] this->pSkins;             
452  if( this->pTexCoords) delete this->pTexCoords;
453  if( this->pTriangles) delete this->pTriangles;
454  if( this->pFrames) delete this->pFrames;
455}
456
457
458/********************************************************************************
459 *   MD2LOADER2                                                                 *
460 ********************************************************************************/
461
462MD2Model2::MD2Model2()
463{
464  this->pVertices = NULL;
465  this->pGLCommands = NULL;
466  this->pLightNormals = NULL; 
467
468  this->numFrames = 0;
469  this->numVertices = 0;
470  this->numGLCommands = 0;
471 
472  this->textureID = 0;
473  this->scaleFactor = 1.0f;
474
475  //this->setAnim(0);
476}
477
478
479MD2Model2::~MD2Model2()
480{
481  delete [] this->pVertices;
482  delete [] this->pGLCommands;
483  delete [] this->pLightNormals;
484}
485
486
487
488bool MD2Model2::loadModel(const char *fileName)
489{
490  FILE *pFile;                            //file stream
491  tMd2Header header;
492  char* buffer;                           //buffer for frame data
493  sFrame* frame;                          //temp frame
494  sVec3D *pVertex;
495  int* pNormals;
496
497  pFile = fopen(fileName, "rb");
498  if( unlikely(!pFile)) 
499    {
500      PRINTF(1)("Couldn't open the MD2 File for loading. Exiting.\n");
501      return false;
502    }
503  fread(&header, 1, sizeof(tMd2Header), pFile);
504  /* check for the header version: make sure its a md2 file :) */
505  if( unlikely(header.version != MD2_VERSION) && unlikely(header.ident != MD2_IDENT))
506    {
507      PRINTF(1)("Couldn't load file %s: invalid file format: stop loading\n", fileName);
508      return false;
509    }
510
511  /* got the data: map it to locals */
512  this->numFrames = header.numFrames;
513  this->numVertices = header.numVertices;
514  this->numGLCommands = header.numGlCommands;
515  /* allocate memory for the data storage */
516  this->pVertices = new sVec3D[this->numVertices * this->numFrames];
517  this->pGLCommands = new int[this->numGLCommands];
518  this->pLightNormals = new int[this->numVertices * this->numFrames];
519  buffer = new char[this->numFrames * header.frameSize];
520
521  /* read frame data from the file to a temp buffer */
522  fseek(pFile, header.offsetFrames, SEEK_SET);
523  fread(buffer, header.frameSize, this->numFrames, pFile);
524  /* read opengl commands */
525  fseek(pFile, header.offsetGlCommands, SEEK_SET);
526  fread(this->pGLCommands, sizeof(int), this->numGLCommands, pFile);
527
528  for(int i = 0; i < this->numFrames; ++i)
529    {
530      frame = (sFrame*)(buffer + header.frameSize * i); 
531      pVertex = this->pVertices + this->numVertices  * i;
532      pNormals = this->pLightNormals + this->numVertices * i;
533
534      for(int j = 0; j < this->numVertices; ++j)
535        {
536          /* SPEEDUP: *(pVerts + i + 0) = (*(frame->pVertices + i + 0)...  */
537          pVertex[i][0] = (frame->pVertices[i].v[0] * frame->scale[0]) + frame->translate[0];
538          pVertex[i][1] = (frame->pVertices[i].v[1] * frame->scale[1]) + frame->translate[1];
539          pVertex[i][2] = (frame->pVertices[i].v[2] * frame->scale[2]) + frame->translate[2];     
540
541          pNormals[i] = frame->pVertices[i].lightNormalIndex;
542        }
543    }
544
545  delete [] buffer;
546  fclose(pFile);
547}
548
549
550bool MD2Model2::loadSkin(const char* fileName)
551{
552  this->material = new Material("md2ModelTest");
553  this->material->setDiffuseMap(fileName);
554  this->material->setIllum(3);
555  this->material->setAmbient(1.0, 1.0, 1.0);
556}
557
558
559void MD2Model2::draw()
560{
561  glPushMatrix();
562  /* rotate because id software uses another orientation then the openGL default */
563  /* \todo: rotate the axis already when loading... easy :) */
564  glRotatef(-90.0, 1.0, 0.0, 0.0);
565  glRotatef(-90.0, 0.0, 0.0, 1.0);
566
567  this->renderFrame();
568
569  glPopMatrix();
570}
571
572
573/**
574   \brief initializes an array of vert with the current frame scaled vertices
575
576   we won't use the pVertices array directly, since its much easier and we need
577   saving of data anyway
578*/
579void MD2Model2::interpolate(sVec3D* verticesList)
580{
581  for(int i = 0; i < this->numFrames; ++i)
582    {
583      verticesList[i][0] = this->pVertices[i + (this->numFrames * this->animationState.currentFrame)][0] * this->scaleFactor;
584      verticesList[i][1] = this->pVertices[i + (this->numFrames * this->animationState.currentFrame)][1] * this->scaleFactor;
585      verticesList[i][2] = this->pVertices[i + (this->numFrames * this->animationState.currentFrame)][2] * this->scaleFactor;
586    }
587}
588
589
590/* hhmmm... id used a very different way to do lightning...*/
591void MD2Model2::processLighting()
592{
593}
594
595
596void MD2Model2::renderFrame()
597{
598  static sVec3D verticesList[MD2_MAX_VERTICES]; /* performance: created only once in a lifetime */
599  int* pCommands = this->pGLCommands;
600
601  /* some face culling stuff */
602  glPushAttrib(GL_POLYGON_BIT);
603  glFrontFace(GL_CW);
604  glEnable(GL_CULL_FACE);
605  glCullFace(GL_BACK);
606     
607  this->interpolate(verticesList);
608  this->material->select();
609
610  /* draw the triangles */
611  /* \todo: take int i out of while loop */
612  while( int i = *(pCommands++)) /* strange looking while loop for maximum performance */
613    {
614      if( i < 0)
615        {
616          glBegin(GL_TRIANGLE_FAN);
617          i = -i;
618        }
619      else
620        {
621          glBegin(GL_TRIANGLE_STRIP);
622        }
623
624      for(; i > 0; --i, pCommands += 3) /* down counting for loop, next 3 gl commands */
625        {
626          /* for quake2 lighting */
627          //float l = shadedots[this->pLightNormals[pCommands[2]]];
628          //glColor3f(l * lcolor[0], l * lcolor[1], l * lcolor[2]);
629
630          glTexCoord2f( ((float *)pCommands)[0], ((float *)pCommands)[1] );
631          //glNormal3fv(anorms[this->pLightNormals[2]]);
632          glVertex3fv(verticesList[pCommands[2]]);
633        }
634      glEnd();
635    }
636  glDisable(GL_CULL_FACE);
637  glPopAttrib();
638}
639
Note: See TracBrowser for help on using the repository browser.