Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/branchs/md2_model: startet working on animated md2 models. this version doesn't compile

File size: 13.6 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
19#include <fstream>
20#include <string>
21#include <vector>
22
23
24using namespace std;
25
26/********************************************************************************
27 *   MD2MODEL                                                                   *
28 ********************************************************************************/
29
30/**
31   \brief standard constructor
32   
33   creates a new model
34*/
35MD2Model::MD2Model () 
36{
37  this->setClassName ("MD2Model");
38}
39
40
41/**
42   \brief standard deconstructor
43
44*/
45MD2Model::~MD2Model () 
46{
47  // delete what has to be deleted here
48}
49
50
51MD2Model::animateModel()
52{
53        if( unlikely(pModel->pObject.size() <= 0)) return;
54        /* get current animation from the list */
55        tAnimationInfo *pAnim = &(pModel->pAnimations[pModel->currentAnim]);
56
57        int nextFrame = (pModel->currentFrame + 1) % pAnim->endFrame;
58        if( unlikely(nextFrame == 0)) 
59                nextFrame =  pAnim->startFrame;
60
61        t3DObject *pFrame = &pModel->pObject[pModel->currentFrame];
62        t3DObject *pNextFrame = &pModel->pObject[nextFrame];
63
64        /* we have stored the texture and face information only in the first frame */
65        t3DObject *pFirstFrame = &pModel->pObject[0];
66
67        /* get the current time as a value in the domain [0..1] :)) */
68        float t = ReturnCurrentTime(pModel, nextFrame);
69
70        glBegin(g_ViewMode);
71                for(int j = 0; j < pFrame->numOfFaces; j++)
72                {
73                        for(int whichVertex = 0; whichVertex < 3; whichVertex++)
74                        {
75                                int vertIndex = pFirstFrame->pFaces[j].vertIndex[whichVertex];
76                                int texIndex  = pFirstFrame->pFaces[j].coordIndex[whichVertex];
77                                               
78                                if( likely(pFirstFrame->pTexVerts != NULL)) 
79                                {
80                                        glTexCoord2f(pFirstFrame->pTexVerts[ texIndex ].x, 
81                                                                 pFirstFrame->pTexVerts[ texIndex ].y);
82                                }
83                       
84                                /* here comes the interpolation part */
85                                CVector3 vPoint1 = pFrame->pVerts[vertIndex];
86                                CVector3 vPoint2 = pNextFrame->pVerts[vertIndex];
87                                glVertex3f(vPoint1.x + t * (vPoint2.x - vPoint1.x), 
88                                                   vPoint1.y + t * (vPoint2.y - vPoint1.y),
89                                                   vPoint1.z + t * (vPoint2.z - vPoint1.z));
90                        }
91                }
92        glEnd();
93}
94
95
96float MD2Model::returnCurrentTime(t3DModel *pModel, int nextFrame)
97{
98        static float elapsedTime   = 0.0f;
99        static float lastTime     = 0.0f;
100
101        /* this is the same like tick(float time) */
102        //float time = GetTickCount();
103        //elapsedTime = time - lastTime;
104       
105        /* stretch the time with animation speed (and make seconds out of it) */
106        float t = elapsedTime / (1000.0f / kAnimationSpeed);
107       
108        if (elapsedTime >= (1000.0f / kAnimationSpeed) )
109        {
110                pModel->currentFrame = nextFrame;
111                lastTime = time;
112        }
113        return t;
114}
115
116/**
117   \brief draw function
118 
119   these function will take NO argument in the final version, just for testing
120*/
121void MD2Model::draw(t3DModel *pModel)
122{
123  if( pModel->objectList.size() <= 0) return;
124
125  t3DObject *pObject = &pModel->objectList[0];
126  glBegin(GL_TRIANGLES);
127  for(int j = 0; j < pObject->numOfFaces; j++)
128    {
129      for(int whichVertex = 0; whichVertex < 3; whichVertex++)
130        {
131          int index = pObject->pFaces[j].vertIndex[whichVertex];
132          int index2 = pObject->pFaces[j].coordIndex[whichVertex];
133          /* we invert the normals since the md2 file format uses different style */
134          /* FIX FIX FIX: ther are actualy no reasons to compute the normals every frame: change this later*/
135          glNormal3f(-pObject->pNormals[index].x, -pObject->pNormals[index].y, -pObject->pNormals[index].z);
136
137          if( likely(pObject->pTexVerts != NULL)) 
138            {
139              glTexCoord2f(pObject->pTexVerts[index2].x, pObject->pTexVerts[index2].y);
140            }
141          glVertex3f(pObject->pVerts[index].x, pObject->pVerts[index].y, pObject->pVerts[index].z);
142        }
143    }
144  glEnd();
145}
146
147/********************************************************************************
148 *   MD2LOADER                                                                  *
149 ********************************************************************************/
150
151/**
152   \brief standard deconstructor
153   creates a new model loader
154*/
155MD2Loader::MD2Loader()
156{
157  this->setClassName ("MD2Loader");
158  /* initialize all data to initial state */
159  memset(&this->header, 0, sizeof(tMd2Header));
160  this->pSkins = NULL;
161  this->pTexCoords = NULL;
162  this->pTriangles = NULL;
163  this->pFrames = NULL;
164}
165
166/**
167   \brief standard deconstructor
168*/
169MD2Loader::~MD2Loader()
170{}
171 
172
173/**
174   \brief this is called by the client to open the .Md2 file, read it, then clean up
175   \param model to load in
176   \param file name to load
177   \param texture name to load
178*/
179bool MD2Loader::importMD2(t3DModel *pModel, char *fileName, char *textureName)
180{
181  this->pFile = fopen(fileName, "rb");
182  if( unlikely(!pFile)) 
183    {
184      PRINTF(1)("Couldn't open the MD2 File for loading. Exiting.\n");
185      return false;
186    }
187  fread(&this->header, 1, sizeof(tMd2Header), pFile);
188  /* check for the header version: make sure its a md2 file :) */
189  if( likely(this->header.version != 8))
190    {
191      PRINTF(1)("Couldn't load file %s: invalid file format: stop loading\n", fileName);
192      return false;
193    }
194       
195  this->readMD2Data();
196  this->convertDataStructures(pModel);
197  this->computeNormals(pModel);
198
199  if( likely((int)textureName))
200    {
201      tMaterialInfo textureInfo;
202      strcpy(textureInfo.strFile, textureName);
203      /* since there is only one texture for a .Md2 file, the ID is always 0 */
204      textureInfo.texureId = 0;
205      textureInfo.uTile = 1;
206      /* we only have 1 material for a model */
207      pModel->numOfMaterials = 1;
208      pModel->materialList.push_back(textureInfo);
209    }
210       
211  this->cleanUp();
212  return true;
213}
214
215
216/**
217   \brief This function reads in all of the model's data, except the animation frames
218*/
219void MD2Loader::readMD2Data()
220{
221  unsigned char buffer[MD2_MAX_FRAMESIZE];
222  this->pSkins     = new tMd2Skin[this->header.numSkins];
223  this->pTexCoords = new tMd2TexCoord[this->header.numTexCoords];
224  this->pTriangles = new tMd2Face[this->header.numTriangles];
225  this->pFrames    = new tMd2Frame[this->header.numFrames];
226
227  /* we read the skins */
228  fseek(this->pFile, this->header.offsetSkins, SEEK_SET);
229  fread(this->pSkins, sizeof(tMd2Skin), this->header.numSkins, this->pFile);
230  /* read all vertex data */
231  fseek(this->pFile, this->header.offsetTexCoords, SEEK_SET);
232  fread(this->pTexCoords, sizeof(tMd2TexCoord), this->header.numTexCoords, this->pFile);
233  /* read face data for each triangle (normals) */
234  fseek(this->pFile, this->header.offsetTriangles, SEEK_SET);
235  fread(this->pTriangles, sizeof(tMd2Face), this->header.numTriangles, this->pFile);
236  /* reading all frame data */
237  fseek(this->pFile, this->header.offsetFrames, SEEK_SET);
238  for( int i = 0; i < this->header.numFrames; i++)
239    {
240      tMd2AliasFrame *pFrame = (tMd2AliasFrame *) buffer;
241      this->pFrames[i].pVertices = new tMd2Triangle [this->header.numVertices];
242
243      /* read the frame animation data */
244      fread(pFrame, 1, this->header.frameSize, this->pFile);
245      strcpy(this->pFrames[i].strName, pFrame->name);
246      tMd2Triangle *pVertices = this->pFrames[i].pVertices;
247      /*
248         scale translations, store vertices: since id used a non-opengl xyz notation, we have to swap y and z
249         and negate z axis
250      */
251      for( int j = 0; j < this->header.numVertices; j++)
252        {
253          pVertices[j].vertex[0] = pFrame->aliasVertices[j].vertex[0] * pFrame->scale[0] + pFrame->translate[0];
254          pVertices[j].vertex[2] = -1 * (pFrame->aliasVertices[j].vertex[1] * pFrame->scale[1] + pFrame->translate[1]);
255          pVertices[j].vertex[1] = pFrame->aliasVertices[j].vertex[2] * pFrame->scale[2] + pFrame->translate[2];
256        }
257    }
258}
259
260
261/**
262   \brief this function fills in the animation list for each animation by name and frame
263   \param model
264*/
265void MD2Loader::parseAnimations(t3DModel *pModel)
266{
267  tAnimationInfo animationInfo;
268  string strLastName = "";
269
270  /* the animation parse process looks a little bit wired: this is because there are no
271     fix bounds for the animation lengths, so the frames are destingushed using their names
272     which is normaly composed of <animationname><number>
273  */
274
275  for(int i = 0; i < pModel->numOfObjects; i++)
276    {
277      string strName  = this->pFrames[i].strName;
278      int frameNum = 0;
279       
280      /* erease the frame number from the frame-name */
281      for(unsigned int j = 0; j < strName.length(); j++)
282        {
283          if( isdigit(strName[j]) && j >= strName.length() - 2)
284            {
285              frameNum = atoi(&strName[j]);
286              strName.erase(j, strName.length() - j);
287              break;
288            }
289        }
290
291      printf("current: %s, last: %s\n", strName.c_str(), strLastName.c_str());
292
293      /* animations are sorted through their names: this is how its been done: */
294      if( strName != strLastName || i == pModel->numOfObjects - 1)
295        {
296          if( strLastName != "")
297            {
298              strcpy(animationInfo.strName, strLastName.c_str());
299              animationInfo.endFrame = i;
300              pModel->animationList.push_back(animationInfo);
301              memset(&animationInfo, 0, sizeof(tAnimationInfo));
302              pModel->numOfAnimations++;
303            }
304          animationInfo.startFrame = frameNum - 1 + i;
305        }
306      strLastName = strName;
307    }
308}
309
310
311/**
312   \brief this function converts the .md2 structures to our own model and object structures: decompress
313   \param model
314*/
315void MD2Loader::convertDataStructures(t3DModel *pModel)
316{
317  int j = 0, i = 0;
318       
319  memset(pModel, 0, sizeof(t3DModel));
320  pModel->numOfObjects = this->header.numFrames;
321
322  this->parseAnimations(pModel);
323
324  for (i = 0; i < pModel->numOfObjects; i++)
325    {
326      t3DObject currentFrame;
327
328      currentFrame.numOfVerts = this->header.numVertices;
329      currentFrame.numTexVertex = this->header.numTexCoords;
330      currentFrame.numOfFaces = this->header.numTriangles;
331
332      currentFrame.pVerts = new CVector3[currentFrame.numOfVerts];
333
334      for (j = 0; j < currentFrame.numOfVerts; j++)
335        {
336          currentFrame.pVerts[j].x = this->pFrames[i].pVertices[j].vertex[0];
337          currentFrame.pVerts[j].y = this->pFrames[i].pVertices[j].vertex[1];
338          currentFrame.pVerts[j].z = this->pFrames[i].pVertices[j].vertex[2];
339        }
340
341      delete this->pFrames[i].pVertices;
342
343      if( likely(i > 0))
344        {
345          pModel->objectList.push_back(currentFrame);
346          continue;
347        }
348                       
349      currentFrame.pTexVerts = new CVector2[currentFrame.numTexVertex];
350      currentFrame.pFaces = new tFace[currentFrame.numOfFaces];
351
352      for(j = 0; j < currentFrame.numTexVertex; j++)
353        {
354          currentFrame.pTexVerts[j].x = this->pTexCoords[j].u / float(this->header.skinWidth);
355          currentFrame.pTexVerts[j].y = 1 - this->pTexCoords[j].v / float(this->header.skinHeight);
356        }
357
358      for(j = 0; j < currentFrame.numOfFaces; j++)
359        {
360          currentFrame.pFaces[j].vertIndex[0] = this->pTriangles[j].vertexIndices[0];
361          currentFrame.pFaces[j].vertIndex[1] = this->pTriangles[j].vertexIndices[1];
362          currentFrame.pFaces[j].vertIndex[2] = this->pTriangles[j].vertexIndices[2];
363
364          currentFrame.pFaces[j].coordIndex[0] = this->pTriangles[j].textureIndices[0];
365          currentFrame.pFaces[j].coordIndex[1] = this->pTriangles[j].textureIndices[1];
366          currentFrame.pFaces[j].coordIndex[2] = this->pTriangles[j].textureIndices[2];
367        }
368      pModel->objectList.push_back(currentFrame);
369    }
370}
371
372
373/**
374   \brief this function conputes the normals of the model
375   \param model
376*/
377void MD2Loader::computeNormals(t3DModel *pModel)
378{
379  CVector3 vVector1, vVector2, vNormal, vPoly[3];
380
381  if( unlikely(pModel->numOfObjects <= 0))
382    return;
383  /* now computing face normals: this means just averaging the vertex normals of a face */
384  /* so for every object: */
385  for(int index = 0; index < pModel->numOfObjects; index++)
386    {
387      t3DObject *pObject = &(pModel->objectList[index]);
388
389      /* allocate all the memory we need to calculate the normals */
390      CVector3 *pNormals = new CVector3 [pObject->numOfFaces];
391      CVector3 *pTempNormals = new CVector3 [pObject->numOfFaces];
392      pObject->pNormals = new CVector3 [pObject->numOfVerts];
393
394      for(int i=0; i < pObject->numOfFaces; i++)
395        {
396          /* cache the points to make coding easier :) */
397          vPoly[0] = pObject->pVerts[pObject->pFaces[i].vertIndex[0]];
398          vPoly[1] = pObject->pVerts[pObject->pFaces[i].vertIndex[1]];
399          vPoly[2] = pObject->pVerts[pObject->pFaces[i].vertIndex[2]];
400
401          vVector1 = MathHelp::VectorDiff(vPoly[0], vPoly[2]);         
402          vVector2 = MathHelp::VectorDiff(vPoly[2], vPoly[1]);         
403                       
404          vNormal  = MathHelp::CrossProduct(vVector1, vVector2);               
405          pTempNormals[i] = vNormal;                                   
406          vNormal  = MathHelp::NormalizeVector(vNormal);                               
407
408          pNormals[i] = vNormal;
409        }
410
411      /* now calculating vertex normals */
412      CVector3 vSum = {0.0, 0.0, 0.0};
413      CVector3 vZero = vSum;
414      int shared=0;
415
416      for (int i = 0; i < pObject->numOfVerts; i++)                     
417        {
418          for (int j = 0; j < pObject->numOfFaces; j++) 
419            {                                                                                           
420              if (pObject->pFaces[j].vertIndex[0] == i || 
421                  pObject->pFaces[j].vertIndex[1] == i || 
422                  pObject->pFaces[j].vertIndex[2] == i)
423                {
424                  vSum = MathHelp::AddVector(vSum, pTempNormals[j]);
425                  shared++;                                                                                             }
426            }     
427          pObject->pNormals[i] = MathHelp::DivideVectorByScaler(vSum, float(-shared));
428          pObject->pNormals[i] = MathHelp::NormalizeVector(pObject->pNormals[i]);       
429
430          vSum = vZero;                                                                 
431          shared = 0;                                                                           
432        }
433      delete [] pTempNormals;
434      delete [] pNormals;
435    }
436}
437
438
439/**
440   \brief This function cleans up our allocated memory and closes the file
441*/
442void MD2Loader::cleanUp()
443{
444  fclose(this->pFile);                 
445       
446  if( this->pSkins) delete [] this->pSkins;             
447  if( this->pTexCoords) delete this->pTexCoords;
448  if( this->pTriangles) delete this->pTriangles;
449  if( this->pFrames) delete this->pFrames;
450}
Note: See TracBrowser for help on using the repository browser.