Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/branches/md2_loader: md2 model now gets loaded: all animations and frames are parsed and referenced

File size: 9.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/**
51   \brief draw function
52 
53   these function will take NO argument in the final version, just for testing
54*/
55void MD2Model::draw(t3DModel *pModel)
56{
57  if( pModel->objectList.size() <= 0) return;
58
59  t3DObject *pObject = &pModel->objectList[0];
60  glBegin(GL_TRIANGLES);
61  for(int j = 0; j < pObject->numOfFaces; j++)
62    {
63      for(int whichVertex = 0; whichVertex < 3; whichVertex++)
64        {
65          int index = pObject->pFaces[j].vertIndex[whichVertex];
66          int index2 = pObject->pFaces[j].coordIndex[whichVertex];
67          /* we invert the normals since the md2 file format uses different style */
68          glNormal3f(-pObject->pNormals[ index ].x, -pObject->pNormals[ index ].y, -pObject->pNormals[ index ].z);
69          if(pObject->pTexVerts) 
70            {
71              glTexCoord2f(pObject->pTexVerts[ index2 ].x, pObject->pTexVerts[ index2 ].y);
72            }
73          glVertex3f(pObject->pVerts[ index ].x, pObject->pVerts[ index ].y, pObject->pVerts[ index ].z);
74        }
75    }
76  glEnd();
77}
78
79/********************************************************************************
80 *   MD2LOADER                                                                  *
81 ********************************************************************************/
82
83/**
84   \brief standard deconstructor
85   creates a new model loader
86*/
87MD2Loader::MD2Loader()
88{
89  this->setClassName ("MD2Loader");
90  /* initialize all data to initial state */
91  memset(&this->header, 0, sizeof(tMd2Header));
92  this->pSkins = NULL;
93  this->pTexCoords = NULL;
94  this->pTriangles = NULL;
95  this->pFrames = NULL;
96}
97
98/**
99   \brief standard deconstructor
100*/
101MD2Loader::~MD2Loader()
102{}
103 
104
105/**
106   \brief this is called by the client to open the .Md2 file, read it, then clean up
107   \param model to load in
108   \param file name to load
109   \param texture name to load
110*/
111bool MD2Loader::importMD2(t3DModel *pModel, char *fileName, char *textureName)
112{
113  this->pFile = fopen(fileName, "rb");
114  if( unlikely(!pFile)) 
115    {
116      PRINTF(1)("Couldn't open the MD2 File for loading. Exiting.\n");
117      return false;
118    }
119  fread(&this->header, 1, sizeof(tMd2Header), pFile);
120  /* check for the header version: make sure its a md2 file :) */
121  if( likely(this->header.version != 8))
122    {
123      PRINTF(1)("Couldn't load file %s: invalid file format: stop loading\n", fileName);
124      return false;
125    }
126       
127  this->readMD2Data();
128  this->convertDataStructures(pModel);
129
130  if( likely((int)textureName))
131    {
132      tMaterialInfo textureInfo;
133      strcpy(textureInfo.strFile, textureName);
134      /* since there is only one texture for a .Md2 file, the ID is always 0 */
135      textureInfo.texureId = 0;
136      textureInfo.uTile = 1;
137      /* we only have 1 material for a model */
138      pModel->numOfMaterials = 1;
139      pModel->materialList.push_back(textureInfo);
140    }
141       
142  this->cleanUp();
143  return true;
144}
145
146/**
147   \brief This function reads in all of the model's data, except the animation frames
148*/
149void MD2Loader::readMD2Data()
150{
151  unsigned char buffer[MD2_MAX_FRAMESIZE];
152  this->pSkins     = new tMd2Skin[this->header.numSkins];
153  this->pTexCoords = new tMd2TexCoord[this->header.numTexCoords];
154  this->pTriangles = new tMd2Face[this->header.numTriangles];
155  this->pFrames    = new tMd2Frame[this->header.numFrames];
156
157  /* we read the skins */
158  fseek(this->pFile, this->header.offsetSkins, SEEK_SET);
159  fread(this->pSkins, sizeof(tMd2Skin), this->header.numSkins, this->pFile);
160  /* read all vertex data */
161  fseek(this->pFile, this->header.offsetTexCoords, SEEK_SET);
162  fread(this->pTexCoords, sizeof(tMd2TexCoord), this->header.numTexCoords, this->pFile);
163  /* read face data for each triangle (normals) */
164  fseek(this->pFile, this->header.offsetTriangles, SEEK_SET);
165  fread(this->pTriangles, sizeof(tMd2Face), this->header.numTriangles, this->pFile);
166  /* reading all frame data */
167  fseek(this->pFile, this->header.offsetFrames, SEEK_SET);
168  for(int i = 0; i < this->header.numFrames; i++)
169    {
170      tMd2AliasFrame *pFrame = (tMd2AliasFrame *) buffer;
171      this->pFrames[i].pVertices = new tMd2Triangle [this->header.numVertices];
172
173      /* read the frame animation data */
174      fread(pFrame, 1, this->header.frameSize, this->pFile);
175      strcpy(this->pFrames[i].strName, pFrame->name);
176      tMd2Triangle *pVertices = this->pFrames[i].pVertices;
177      /*
178         scale translations, store vertices: since id used a non-opengl xyz notation, we have to swap y and z
179         and negate z axis
180      */
181      for(int j = 0; j < this->header.numVertices; j++)
182        {
183          pVertices[j].vertex[0] = pFrame->aliasVertices[j].vertex[0] * pFrame->scale[0] + pFrame->translate[0];
184          pVertices[j].vertex[2] = -1 * (pFrame->aliasVertices[j].vertex[1] * pFrame->scale[1] + pFrame->translate[1]);
185          pVertices[j].vertex[1] = pFrame->aliasVertices[j].vertex[2] * pFrame->scale[2] + pFrame->translate[2];
186        }
187    }
188}
189
190/**
191   \brief this function fills in the animation list for each animation by name and frame
192   \param model
193*/
194void MD2Loader::parseAnimations(t3DModel *pModel)
195{
196  tAnimationInfo animationInfo;
197  string strLastName = "";
198
199  /* the animation parse process looks a little bit wired: this is because there are no
200     fix bounds for the animation lengths, so the frames are destingushed using their names
201     which is normaly composed of <animationname><number>
202  */
203
204  for(int i = 0; i < pModel->numOfObjects; i++)
205    {
206      string strName  = this->pFrames[i].strName;
207      int frameNum = 0;
208       
209      /* erease the frame number from the frame-name */
210      for(unsigned int j = 0; j < strName.length(); j++)
211        {
212          if( isdigit(strName[j]) && j >= strName.length() - 2)
213            {
214              frameNum = atoi(&strName[j]);
215              strName.erase(j, strName.length() - j);
216              break;
217            }
218        }
219
220      printf("current: %s, last: %s\n", strName.c_str(), strLastName.c_str());
221
222      /* animations are sorted through their names: this is how its been done: */
223      if( strName != strLastName || i == pModel->numOfObjects - 1)
224        {
225          if( strLastName != "")
226            {
227              strcpy(animationInfo.strName, strLastName.c_str());
228              animationInfo.endFrame = i;
229              pModel->animationList.push_back(animationInfo);
230              memset(&animationInfo, 0, sizeof(tAnimationInfo));
231              pModel->numOfAnimations++;
232            }
233          animationInfo.startFrame = frameNum - 1 + i;
234        }
235      strLastName = strName;
236    }
237}
238
239/**
240   \brief this function converts the .md2 structures to our own model and object structures: decompress
241   \param model
242*/
243void MD2Loader::convertDataStructures(t3DModel *pModel)
244{
245  int j = 0, i = 0;
246       
247  memset(pModel, 0, sizeof(t3DModel));
248  pModel->numOfObjects = this->header.numFrames;
249
250  this->parseAnimations(pModel);
251
252  for (i = 0; i < pModel->numOfObjects; i++)
253    {
254      t3DObject currentFrame;
255
256      currentFrame.numOfVerts = this->header.numVertices;
257      currentFrame.numTexVertex = this->header.numTexCoords;
258      currentFrame.numOfFaces = this->header.numTriangles;
259
260      currentFrame.pVerts = new CVector3[currentFrame.numOfVerts];
261
262      for (j = 0; j < currentFrame.numOfVerts; j++)
263        {
264          currentFrame.pVerts[j].x = this->pFrames[i].pVertices[j].vertex[0];
265          currentFrame.pVerts[j].y = this->pFrames[i].pVertices[j].vertex[1];
266          currentFrame.pVerts[j].z = this->pFrames[i].pVertices[j].vertex[2];
267        }
268
269      delete this->pFrames[i].pVertices;
270
271      if( likely(i > 0))
272        {
273          pModel->objectList.push_back(currentFrame);
274          continue;
275        }
276                       
277      currentFrame.pTexVerts = new CVector2[currentFrame.numTexVertex];
278      currentFrame.pFaces = new tFace[currentFrame.numOfFaces];
279
280      for(j = 0; j < currentFrame.numTexVertex; j++)
281        {
282          currentFrame.pTexVerts[j].x = this->pTexCoords[j].u / float(this->header.skinWidth);
283          currentFrame.pTexVerts[j].y = 1 - this->pTexCoords[j].v / float(this->header.skinHeight);
284        }
285
286      for(j = 0; j < currentFrame.numOfFaces; j++)
287        {
288          currentFrame.pFaces[j].vertIndex[0] = this->pTriangles[j].vertexIndices[0];
289          currentFrame.pFaces[j].vertIndex[1] = this->pTriangles[j].vertexIndices[1];
290          currentFrame.pFaces[j].vertIndex[2] = this->pTriangles[j].vertexIndices[2];
291
292          currentFrame.pFaces[j].coordIndex[0] = this->pTriangles[j].textureIndices[0];
293          currentFrame.pFaces[j].coordIndex[1] = this->pTriangles[j].textureIndices[1];
294          currentFrame.pFaces[j].coordIndex[2] = this->pTriangles[j].textureIndices[2];
295        }
296      pModel->objectList.push_back(currentFrame);
297    }
298}
299
300
301/**
302   \brief this function conputes the normals of the model
303   \param model
304*/
305void MD2Loader::computeNormals(t3DModel *pModel)
306{}
307
308
309/**
310   \brief This function cleans up our allocated memory and closes the file
311*/
312void MD2Loader::cleanUp()
313{
314  fclose(this->pFile);                 
315       
316  if( this->pSkins) delete [] this->pSkins;             
317  if( this->pTexCoords) delete this->pTexCoords;
318  if( this->pTriangles) delete this->pTriangles;
319  if( this->pFrames) delete this->pFrames;
320}
Note: See TracBrowser for help on using the repository browser.