Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/branches/md2_loader: now using the home brewed material class for the model - and it works just perfect! orxonox has a very powerfull material class./orxonox :D

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