Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

center in the middle

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