Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/branches/md2_importer: reimplemented the animation functions, compiles again

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