Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/branches/md2_model: yea! animation now works :), orxonox now supports md2 loading and md2 animation playing. There is still a lot of work to do: cleaning up code and tie it closer to the orxonox framework

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