Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/branches/md2_loader: modified the texture loader to use the sdl-image libraries, this will use material/texture classes from orxonox later

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