Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 6785 was 6645, checked in by bensch, 19 years ago

orxonox/trunk: totally remastered the ResourceManager.
Now it takes MultiTypes instead of (void*) as parameters

  1. This is TypeSafe
  2. This is easier to use
  3. This makes much more sense, and is objectOriented

also made some minor adjustments to the MultiType, some comparisons

also fixed the loading in all the Other classes like material md2 and so on

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