Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/lib/graphics/importer/md2Model.cc @ 7171

Last change on this file since 7171 was 7123, checked in by bensch, 19 years ago

orxonox/trunk: some cleanup before the new tag

  1. BaseObject isA was wrong… every subclass was detected as any other subclass
  2. Classes get unloaded again as they should
  3. some minor fixes (Material* → Material) and some other cleanups
File size: 16.4 KB
RevLine 
[4682]1/*
[4245]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#include "material.h"
19
[5075]20#include "debug.h"
[4246]21#include "resource_manager.h"
22
[4245]23
24using namespace std;
25
[4682]26//! the model anorms
[4276]27sVec3D MD2Model::anorms[NUM_VERTEX_NORMALS] = {
[4245]28 #include "anorms.h"
29};
30
[4459]31//! anormal dots, no idea of how this shall work, but it does
[4276]32float MD2Model::anormsDots[SHADEDOT_QUANT][256] = {
[4245]33  #include "anormtab.h"
34};
35
36
[4682]37//! the angle under which the model is viewd, used internaly
[4245]38float md2Angle = 0.0f;
39
40
[4459]41//! list of all different animations a std md2model supports
[4276]42sAnim MD2Model::animationList[21] =
[4245]43  {
[6222]44 // begin, end, fps, interruptable
45    {   0,  39,  9, 1 },   //!< STAND
46    {  40,  45, 10, 1 },   //!< RUN
47    {  46,  53, 10, 0 },   //!< ATTACK
48    {  54,  57,  7, 1 },   //!< PAIN_A
49    {  58,  61,  7, 1 },   //!< PAIN_B
50    {  62,  65,  7, 1 },   //!< PAIN_C
51    {  66,  71,  7, 0 },   //!< JUMP
52    {  72,  83,  7, 1 },   //!< FLIP
53    {  84,  94,  7, 1 },   //!< SALUTE
54    {  95, 111, 10, 1 },   //!< FALLBACK
55    { 112, 122,  7, 1 },   //!< WAVE
56    { 123, 134,  6, 1 },   //!< POINTT
57    { 135, 153, 10, 1 },   //!< CROUCH_STAND
58    { 154, 159,  7, 1 },   //!< CROUCH_WALK
59    { 160, 168, 10, 1 },   //!< CROUCH_ATTACK
60    { 196, 172,  7, 1 },   //!< CROUCH_PAIN
61    { 173, 177,  5, 0 },   //!< CROUCH_DEATH
[7114]62    { 178, 183,  10, 0 },   //!< DEATH_FALLBACK
63    { 184, 189,  10, 0 },   //!< DEATH_FALLFORWARD
64    { 190, 197,  10, 0 },   //!< DEATH_FALLBACKSLOW
[6222]65    { 198, 198,  5, 1 },   //!< BOOM
[4245]66  };
67
68
69
70/********************************************************************************
[4459]71 *   MD2Model                                                                   *
72 ********************************************************************************/
[4245]73
[4461]74/**
[4284]75  \brief simple constructor initializing all variables
76*/
[7055]77MD2Model::MD2Model(const char* modelFileName, const char* skinFileName, float scale)
[4245]78{
[7123]79  this->setClassID(CL_MD2_MODEL, "MD2Model");
[4280]80  /* this creates the data container via ressource manager */
[7059]81  this->data = (MD2Data*)ResourceManager::getInstance()->load(modelFileName, MD2, RP_GAME, skinFileName, scale);
[4787]82  if( unlikely(this->data == NULL))
83    PRINTF(0)("The model was not found, MD2Model Loader finished abnormaly. Update the data-repos\n");
[5075]84
[7059]85  this->scaleFactor = scale;
86
[6222]87  shadeDots = MD2Model::anormsDots[0];
88  /* set the animation stat mannualy */
89  this->animationState.type = STAND;
90  this->animationState.numPlays = 1;
[5087]91  this->setAnim(STAND);
[6222]92
93  this->debug();
[7068]94
95    //write the modelinfo information
96  this->pModelInfo.numVertices = this->data->numVertices;
97  this->pModelInfo.numTriangles = this->data->numTriangles;
98  this->pModelInfo.numNormals = 0;
99  this->pModelInfo.numTexCoor = this->data->numTexCoor;
100  this->pModelInfo.pVertices = (float*)this->data->pVertices;
101  this->pModelInfo.pNormals = NULL;
102  this->pModelInfo.pTexCoor = (float*)this->data->pTexCoor;
103
104  // triangle conversion
105  this->pModelInfo.pTriangles = new sTriangleExt[this->data->numTriangles];
106  for( int i = 0; i < this->data->numTriangles; i++)
107  {
108    this->pModelInfo.pTriangles[i].indexToVertices[0] = this->data->pTriangles[i].indexToVertices[0];
109    this->pModelInfo.pTriangles[i].indexToVertices[1] = this->data->pTriangles[i].indexToVertices[1];
110    this->pModelInfo.pTriangles[i].indexToVertices[2] = this->data->pTriangles[i].indexToVertices[2];
111
112    this->pModelInfo.pTriangles[i].indexToTexCoor[0] = this->data->pTriangles[i].indexToTexCoor[0];
113    this->pModelInfo.pTriangles[i].indexToTexCoor[1] = this->data->pTriangles[i].indexToTexCoor[1];
114    this->pModelInfo.pTriangles[i].indexToTexCoor[2] = this->data->pTriangles[i].indexToTexCoor[2];
115  }
[4245]116}
117
[7068]118
[4461]119/**
[4284]120  \brief simple destructor, dereferencing all variables
[4245]121
[4284]122  this is where the ressource manager is cleaning the stuff
123*/
[4276]124MD2Model::~MD2Model()
[4245]125{
[4462]126  ResourceManager::getInstance()->unload(this->data);
[4245]127}
128
129
130/**
[4836]131 *  initializes an array of vert with the current frame scaled vertices
[6222]132 * @param this->verticesList: the list of vertices to interpolate between
[4245]133
134   we won't use the pVertices array directly, since its much easier and we need
135   saving of data anyway
136*/
[6222]137void MD2Model::interpolate(/*sVec3D* this->verticesList*/)
[4245]138{
139  sVec3D* currVec;
140  sVec3D* nextVec;
141
[4281]142  currVec = &this->data->pVertices[this->data->numVertices * this->animationState.currentFrame];
143  nextVec = &this->data->pVertices[this->data->numVertices * this->animationState.nextFrame];
[4245]144
[5086]145  for( int i = 0; i < this->data->numVertices; ++i)
[4245]146    {
[6222]147      this->verticesList[i][0] = currVec[i][0] + this->animationState.interpolationState * (nextVec[i][0] - currVec[i][0]);
148      this->verticesList[i][1] = currVec[i][1] + this->animationState.interpolationState * (nextVec[i][1] - currVec[i][1]);
149      this->verticesList[i][2] = currVec[i][2] + this->animationState.interpolationState * (nextVec[i][2] - currVec[i][2]);
[4245]150    }
151}
152
153
[4461]154/**
[4284]155  \brief sets the animation type
[4836]156* @param type: animation type
[4284]157
158  the animation types can be looked up in the animationType table
159*/
[7071]160void MD2Model::setAnim(int type, int animPlayback)
[4245]161{
162  if( (type < 0) || (type > MAX_ANIMATIONS) )
[5087]163    type = STAND;
[4245]164
[6222]165  if( MD2Model::animationList[this->animationState.type].bStoppable == 0)
166  {
167    if( this->animationState.numPlays == 0 )
168      return;
169  }
170
[4245]171  this->animationState.startFrame = animationList[type].firstFrame;
172  this->animationState.endFrame = animationList[type].lastFrame;
173  this->animationState.nextFrame = animationList[type].firstFrame + 1;
174  this->animationState.fps = animationList[type].fps;
175  this->animationState.type = type;
[6222]176  this->animationState.numPlays = 0;
[7071]177  this->animationState.animPlaybackMode = animPlayback;
[4682]178
[5087]179  this->animationState.interpolationState = 0.0f;
180  this->animationState.localTime = 0.0f;
181  this->animationState.lastTime = 0.0f;
[4245]182  this->animationState.currentFrame = animationList[type].firstFrame;
183}
184
185
[4461]186/**
[4284]187  \brief sets the time in seconds passed since the last tick
[4836]188* @param time: in sec
[4284]189*/
[4276]190void MD2Model::tick(float time)
[4245]191{
[6222]192  this->animate(time);
193  this->processLighting();
194  this->interpolate(/*this->verticesList*/);
[4245]195}
196
197
[4461]198/**
[6022]199 * @brief draws the model: interface for all other classes out in the world
200 * @todo make it const and virtual
201 * FIXME
202 */
[6222]203void MD2Model::draw() const
[4245]204{
205  glPushMatrix();
[5087]206  this->renderFrame();
[6222]207  // renderFrameTriangles();
[4245]208  glPopMatrix();
[4682]209}
[4245]210
211
[4461]212/**
[4284]213  \brief this is an internal function to render this special frame selected by animate()
214*/
[6222]215void MD2Model::renderFrame() const
[4245]216{
[4281]217  int* pCommands = this->data->pGLCommands;
[4245]218
219  /* some face culling stuff */
220  glPushAttrib(GL_POLYGON_BIT);
221  glFrontFace(GL_CW);
222  glEnable(GL_CULL_FACE);
223  glCullFace(GL_BACK);
[4682]224
[7123]225  this->data->material.select();
[4245]226
227  /* draw the triangles */
228  while( int i = *(pCommands++)) /* strange looking while loop for maximum performance */
229    {
230      if( i < 0)
[4682]231        {
232          glBegin(GL_TRIANGLE_FAN);
233          i = -i;
234        }
[4245]235      else
[4682]236        {
237          glBegin(GL_TRIANGLE_STRIP);
238        }
[4245]239
240      for(; i > 0; i--, pCommands += 3) /* down counting for loop, next 3 gl commands */
[4682]241        {
[4717]242          glTexCoord2f( ((float *)pCommands)[0], ((float *)pCommands)[1] );
[4682]243          glNormal3fv(anorms[this->data->pLightNormals[pCommands[2]]]);
[6222]244          glVertex3fv(this->verticesList[pCommands[2]]);
[4682]245        }
[4245]246      glEnd();
[4717]247
[4245]248    }
249  glDisable(GL_CULL_FACE);
250  glPopAttrib();
251}
252
253
[6222]254void MD2Model::renderFrameTriangles() const
255{
256  //static sVec3D this->verticesList[MD2_MAX_VERTICES]; /* performance: created only once in a lifetime */
257  int* pCommands = this->data->pGLCommands;
258  /* some face culling stuff */
259//   glPushAttrib(GL_POLYGON_BIT);
260//   glFrontFace(GL_CW);
261//   glEnable(GL_CULL_FACE);
262//   glCullFace(GL_BACK);
263//
264//   this->processLighting();
265//   this->interpolate(/*this->verticesList*/);
[7123]266  this->data->material.select();
[6222]267
268  /* draw the triangles */
269  glBegin(GL_TRIANGLES);
270
271  for( int i = 0, k = 0; i < this->data->numTriangles; ++i, k += 3)
272  {
273    float* v = this->data->pVertices[this->data->pTriangles[i].indexToVertices[0]];
274
275    printf("triangle: %i\n", i);
276    printf("     v0: (%f, %f, %f)\n", v[0], v[1], v[2]);
277    v = this->data->pVertices[this->data->pTriangles[i].indexToVertices[1]];
278    printf("     v1: (%f, %f, %f)\n", v[0], v[1], v[2]);
279    v = this->data->pVertices[this->data->pTriangles[i].indexToVertices[2]];
280    printf("     v2: (%f, %f, %f)\n", v[0], v[1], v[2]);
281
282
283    glNormal3f(anorms[i][0], anorms[i][1], anorms[i][2]);
284    glVertex3fv(this->data->pVertices[this->data->pTriangles[i].indexToVertices[0]]);
285
286    glNormal3f(anorms[i][0], anorms[i][1], anorms[i][2]);
287    glVertex3fv(this->data->pVertices[this->data->pTriangles[i].indexToVertices[1]]);
288
289    glNormal3f(anorms[i][0], anorms[i][1], anorms[i][2]);
290    glVertex3fv(this->data->pVertices[this->data->pTriangles[i].indexToVertices[2]]);
291  }
292
293  glEnd();
294}
295
296
[4461]297/**
[4284]298  \brief animates the current model
299
300  depending on the time passed (tick function), the player will select another model
301*/
[6222]302void MD2Model::animate(float time)
[4280]303{
[6222]304  this->animationState.localTime += time;
305
[4280]306  if( this->animationState.localTime - this->animationState.lastTime > (1.0f / this->animationState.fps))
307    {
308      this->animationState.currentFrame = this->animationState.nextFrame;
309      this->animationState.nextFrame++;
[4682]310
[7075]311      if( this->animationState.nextFrame > this->animationState.endFrame )
[6222]312      {
[7075]313        if( this->animationState.animPlaybackMode == MD2_ANIM_LOOP)
314        {
315          this->animationState.nextFrame = this->animationState.startFrame;
316          this->animationState.numPlays++;
317        }
318        else
319        {
320          this->animationState.nextFrame = this->animationState.endFrame;
321        }
[6222]322      }
[4280]323      this->animationState.lastTime = this->animationState.localTime;
324    }
325
[7075]326//     if( this->animationState.currentFrame > (this->data->numFrames - 1) )
327//       this->animationState.currentFrame = 0;
[4280]328
[7075]329//     if( (this->animationState.nextFrame > (this->data->numFrames - 1)) && this->animationState.animPlaybackMode == MD2_ANIM_LOOP)
330//     this->animationState.nextFrame = 0;
331
[4682]332  this->animationState.interpolationState = this->animationState.fps *
[4280]333    (this->animationState.localTime - this->animationState.lastTime);
334}
335
336
[4461]337/**
[4284]338  \brief this is how id is precessing their lightning
339
340  the details of how the whole lighting process is beeing handled - i have no idea... :)
341*/
[4280]342void MD2Model::processLighting()
343{
344  shadeDots = anormsDots[((int)(md2Angle*(SHADEDOT_QUANT / 360.0)))&(SHADEDOT_QUANT - 1)];
345}
346
[4461]347
348/**
[4284]349  \brief prints out debug informations
350*/
[4276]351void MD2Model::debug()
[4245]352{
[4282]353  PRINT(0)("\n==========================| MD2Model::debug() |===\n");
[4281]354  PRINT(0)("=  Model FileName:\t%s\n", this->data->fileName);
355  PRINT(0)("=  Skin FileName:\t%s\n", this->data->skinFileName);
356  PRINT(0)("=  Size in Memory:\t%i Bytes\n", this->data->header->frameSize * this->data->header->numFrames + 64); // 64bytes is the header size
357  PRINT(0)("=  Number of Vertices:\t%i\n", this->data->header->numVertices);
358  PRINT(0)("=  Number of Frames: \t%i\n", this->data->header->numFrames);
[4282]359  PRINT(0)("=  Height, Width:\t%i, %i\n", this->data->header->skinHeight, this->data->header->skinWidth);
[4488]360  PRINT(0)("=  Pointer to the data object: %p\n", this->data);
[4245]361  PRINT(0)("===================================================\n\n");
362}
[4280]363
364
[4282]365/********************************************************************************
366 *   MD2Data                                                                    *
367 ********************************************************************************/
[4280]368
[4461]369/**
[4284]370  \brief simple constructor
371*/
[7059]372MD2Data::MD2Data(const char* modelFileName, const char* skinFileName, float scale)
[4280]373{
[7059]374  scale *= 0.1f;
375
[4280]376  this->pVertices = NULL;
377  this->pGLCommands = NULL;
[4682]378  this->pLightNormals = NULL;
[5085]379  this->pTexCoor = NULL;
[4280]380
381  this->numFrames = 0;
382  this->numVertices = 0;
383  this->numGLCommands = 0;
[5085]384  this->numTexCoor = 0;
[4459]385
[6222]386//   this->scaleFactor = 1.0f;
[7059]387  this->scaleFactor = scale;
[4682]388
[5284]389  this->fileName = NULL;
390  this->skinFileName = NULL;
[4459]391  this->loadModel(modelFileName);
392  this->loadSkin(skinFileName);
[4280]393}
394
395
[4461]396/**
[4284]397  \brief simple destructor
398
399  this will clean out all the necessary data for a specific md2model
400*/
[4280]401MD2Data::~MD2Data()
402{
[5235]403  delete [] this->fileName;
404  delete [] this->skinFileName;
405  delete this->header;
[4460]406
[4280]407  delete [] this->pVertices;
408  delete [] this->pGLCommands;
409  delete [] this->pLightNormals;
[5085]410  delete [] this->pTexCoor;
[4460]411
[4280]412}
413
414
415
[4461]416/**
[4284]417  \brief this will load the whole model data (vertices, opengl command list, ...)
[4836]418* @param fileName: the name of the model file
[4284]419  \return true if success
420*/
[4280]421bool MD2Data::loadModel(const char* fileName)
422{
423  FILE *pFile;                            //file stream
424  char* buffer;                           //buffer for frame data
425  sFrame* frame;                          //temp frame
426  sVec3D *pVertex;
427  int* pNormals;
428
[5284]429  //! @todo this chek should include deleting a loaded model (eventually)
430  if (fileName == NULL)
431    return false;
432
[4280]433  pFile = fopen(fileName, "rb");
[4682]434  if( unlikely(!pFile))
[4280]435    {
436      PRINTF(1)("Couldn't open the MD2 File for loading. Exiting.\n");
437      return false;
438    }
439  this->header = new MD2Header;
440  fread(this->header, 1, sizeof(MD2Header), pFile);
441  /* check for the header version: make sure its a md2 file :) */
442  if( unlikely(this->header->version != MD2_VERSION) && unlikely(this->header->ident != MD2_IDENT))
443    {
444      PRINTF(1)("Couldn't load file %s: invalid file format: stop loading\n", fileName);
445      return false;
446    }
447
448  this->fileName = new char[strlen(fileName)+1];
449  strcpy(this->fileName, fileName);
450  /* got the data: map it to locals */
451  this->numFrames = this->header->numFrames;
452  this->numVertices = this->header->numVertices;
453  this->numTriangles = this->header->numTriangles;
454  this->numGLCommands = this->header->numGlCommands;
[5085]455  this->numTexCoor = this->header->numTexCoords;
[4280]456  /* allocate memory for the data storage */
457  this->pVertices = new sVec3D[this->numVertices * this->numFrames];
458  this->pGLCommands = new int[this->numGLCommands];
459  this->pLightNormals = new int[this->numVertices * this->numFrames];
[4787]460  this->pTriangles = new sTriangle[this->numTriangles];
[5085]461  this->pTexCoor = new sTexCoor[this->numTexCoor];
[4280]462  buffer = new char[this->numFrames * this->header->frameSize];
463
[4787]464
[4280]465  /* read frame data from the file to a temp buffer */
466  fseek(pFile, this->header->offsetFrames, SEEK_SET);
467  fread(buffer, this->header->frameSize, this->numFrames, pFile);
468  /* read opengl commands */
469  fseek(pFile, this->header->offsetGlCommands, SEEK_SET);
470  fread(this->pGLCommands, sizeof(int), this->numGLCommands, pFile);
[4787]471  /* triangle list */
472  fseek(pFile, this->header->offsetTriangles, SEEK_SET);
473  fread(this->pTriangles, sizeof(sTriangle), this->numTriangles, pFile);
[5085]474  /*  read in texture coordinates */
475  fseek(pFile, this->header->offsetTexCoords, SEEK_SET);
476  fread(this->pTexCoor, sizeof(sTexCoor), this->numTexCoor, pFile);
[4280]477
[5087]478
[4280]479  for(int i = 0; i < this->numFrames; ++i)
480    {
[4682]481      frame = (sFrame*)(buffer + this->header->frameSize * i);
[4280]482      pVertex = this->pVertices + this->numVertices  * i;
483      pNormals = this->pLightNormals + this->numVertices * i;
484
485      for(int j = 0; j < this->numVertices; ++j)
[4682]486        {
487          /* SPEEDUP: *(pVerts + i + 0) = (*(frame->pVertices + i + 0)...  */
[6222]488           pVertex[j][0] = ((frame->pVertices[j].v[0] * frame->scale[0] ) + frame->translate[0] )* this->scaleFactor;
489           pVertex[j][1] = ((frame->pVertices[j].v[2] * frame->scale[2]) + frame->translate[2]) * this->scaleFactor;
490           pVertex[j][2] = (-1.0 * (frame->pVertices[j].v[1] * frame->scale[1] + frame->translate[1])) * this->scaleFactor;
[4682]491
[6222]492          //printf("vertex %i/%i: (%f, %f, %f)\n", j, this->numVertices, pVertex[j][0], pVertex[j][1], pVertex[j][2]);
493
[4682]494          pNormals[j] = frame->pVertices[j].lightNormalIndex;
495        }
[4280]496    }
[6222]497    PRINTF(4)("Finished loading the md2 file\n");
[4280]498
499  delete [] buffer;
500  fclose(pFile);
501}
502
503
[4461]504/**
[4284]505  \brief loads the skin/material stuff
[4836]506* @param fileName: name of the skin file
[4284]507  \return true if success
508*/
[4280]509bool MD2Data::loadSkin(const char* fileName)
510{
[4459]511  if( fileName == NULL)
512    {
513      this->skinFileName = NULL;
514      return false;
515    }
516
[4280]517  this->skinFileName = new char[strlen(fileName)+1];
518  strcpy(this->skinFileName, fileName);
[4281]519
[7123]520  this->material.setName("md2ModelMaterial");
521  this->material.setDiffuseMap(fileName);
522  this->material.setIllum(3);
523  this->material.setAmbient(1.0, 1.0, 1.0);
[4280]524}
Note: See TracBrowser for help on using the repository browser.