Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 7123 was 7123, checked in by bensch, 18 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
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#include "material.h"
19
20#include "debug.h"
21#include "resource_manager.h"
22
23
24using namespace std;
25
26//! the model anorms
27sVec3D MD2Model::anorms[NUM_VERTEX_NORMALS] = {
28 #include "anorms.h"
29};
30
31//! anormal dots, no idea of how this shall work, but it does
32float MD2Model::anormsDots[SHADEDOT_QUANT][256] = {
33  #include "anormtab.h"
34};
35
36
37//! the angle under which the model is viewd, used internaly
38float md2Angle = 0.0f;
39
40
41//! list of all different animations a std md2model supports
42sAnim MD2Model::animationList[21] =
43  {
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,  10, 0 },   //!< DEATH_FALLBACK
63    { 184, 189,  10, 0 },   //!< DEATH_FALLFORWARD
64    { 190, 197,  10, 0 },   //!< DEATH_FALLBACKSLOW
65    { 198, 198,  5, 1 },   //!< BOOM
66  };
67
68
69
70/********************************************************************************
71 *   MD2Model                                                                   *
72 ********************************************************************************/
73
74/**
75  \brief simple constructor initializing all variables
76*/
77MD2Model::MD2Model(const char* modelFileName, const char* skinFileName, float scale)
78{
79  this->setClassID(CL_MD2_MODEL, "MD2Model");
80  /* this creates the data container via ressource manager */
81  this->data = (MD2Data*)ResourceManager::getInstance()->load(modelFileName, MD2, RP_GAME, skinFileName, scale);
82  if( unlikely(this->data == NULL))
83    PRINTF(0)("The model was not found, MD2Model Loader finished abnormaly. Update the data-repos\n");
84
85  this->scaleFactor = scale;
86
87  shadeDots = MD2Model::anormsDots[0];
88  /* set the animation stat mannualy */
89  this->animationState.type = STAND;
90  this->animationState.numPlays = 1;
91  this->setAnim(STAND);
92
93  this->debug();
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  }
116}
117
118
119/**
120  \brief simple destructor, dereferencing all variables
121
122  this is where the ressource manager is cleaning the stuff
123*/
124MD2Model::~MD2Model()
125{
126  ResourceManager::getInstance()->unload(this->data);
127}
128
129
130/**
131 *  initializes an array of vert with the current frame scaled vertices
132 * @param this->verticesList: the list of vertices to interpolate between
133
134   we won't use the pVertices array directly, since its much easier and we need
135   saving of data anyway
136*/
137void MD2Model::interpolate(/*sVec3D* this->verticesList*/)
138{
139  sVec3D* currVec;
140  sVec3D* nextVec;
141
142  currVec = &this->data->pVertices[this->data->numVertices * this->animationState.currentFrame];
143  nextVec = &this->data->pVertices[this->data->numVertices * this->animationState.nextFrame];
144
145  for( int i = 0; i < this->data->numVertices; ++i)
146    {
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]);
150    }
151}
152
153
154/**
155  \brief sets the animation type
156* @param type: animation type
157
158  the animation types can be looked up in the animationType table
159*/
160void MD2Model::setAnim(int type, int animPlayback)
161{
162  if( (type < 0) || (type > MAX_ANIMATIONS) )
163    type = STAND;
164
165  if( MD2Model::animationList[this->animationState.type].bStoppable == 0)
166  {
167    if( this->animationState.numPlays == 0 )
168      return;
169  }
170
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;
176  this->animationState.numPlays = 0;
177  this->animationState.animPlaybackMode = animPlayback;
178
179  this->animationState.interpolationState = 0.0f;
180  this->animationState.localTime = 0.0f;
181  this->animationState.lastTime = 0.0f;
182  this->animationState.currentFrame = animationList[type].firstFrame;
183}
184
185
186/**
187  \brief sets the time in seconds passed since the last tick
188* @param time: in sec
189*/
190void MD2Model::tick(float time)
191{
192  this->animate(time);
193  this->processLighting();
194  this->interpolate(/*this->verticesList*/);
195}
196
197
198/**
199 * @brief draws the model: interface for all other classes out in the world
200 * @todo make it const and virtual
201 * FIXME
202 */
203void MD2Model::draw() const
204{
205  glPushMatrix();
206  this->renderFrame();
207  // renderFrameTriangles();
208  glPopMatrix();
209}
210
211
212/**
213  \brief this is an internal function to render this special frame selected by animate()
214*/
215void MD2Model::renderFrame() const
216{
217  int* pCommands = this->data->pGLCommands;
218
219  /* some face culling stuff */
220  glPushAttrib(GL_POLYGON_BIT);
221  glFrontFace(GL_CW);
222  glEnable(GL_CULL_FACE);
223  glCullFace(GL_BACK);
224
225  this->data->material.select();
226
227  /* draw the triangles */
228  while( int i = *(pCommands++)) /* strange looking while loop for maximum performance */
229    {
230      if( i < 0)
231        {
232          glBegin(GL_TRIANGLE_FAN);
233          i = -i;
234        }
235      else
236        {
237          glBegin(GL_TRIANGLE_STRIP);
238        }
239
240      for(; i > 0; i--, pCommands += 3) /* down counting for loop, next 3 gl commands */
241        {
242          glTexCoord2f( ((float *)pCommands)[0], ((float *)pCommands)[1] );
243          glNormal3fv(anorms[this->data->pLightNormals[pCommands[2]]]);
244          glVertex3fv(this->verticesList[pCommands[2]]);
245        }
246      glEnd();
247
248    }
249  glDisable(GL_CULL_FACE);
250  glPopAttrib();
251}
252
253
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*/);
266  this->data->material.select();
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
297/**
298  \brief animates the current model
299
300  depending on the time passed (tick function), the player will select another model
301*/
302void MD2Model::animate(float time)
303{
304  this->animationState.localTime += time;
305
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++;
310
311      if( this->animationState.nextFrame > this->animationState.endFrame )
312      {
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        }
322      }
323      this->animationState.lastTime = this->animationState.localTime;
324    }
325
326//     if( this->animationState.currentFrame > (this->data->numFrames - 1) )
327//       this->animationState.currentFrame = 0;
328
329//     if( (this->animationState.nextFrame > (this->data->numFrames - 1)) && this->animationState.animPlaybackMode == MD2_ANIM_LOOP)
330//     this->animationState.nextFrame = 0;
331
332  this->animationState.interpolationState = this->animationState.fps *
333    (this->animationState.localTime - this->animationState.lastTime);
334}
335
336
337/**
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*/
342void MD2Model::processLighting()
343{
344  shadeDots = anormsDots[((int)(md2Angle*(SHADEDOT_QUANT / 360.0)))&(SHADEDOT_QUANT - 1)];
345}
346
347
348/**
349  \brief prints out debug informations
350*/
351void MD2Model::debug()
352{
353  PRINT(0)("\n==========================| MD2Model::debug() |===\n");
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);
359  PRINT(0)("=  Height, Width:\t%i, %i\n", this->data->header->skinHeight, this->data->header->skinWidth);
360  PRINT(0)("=  Pointer to the data object: %p\n", this->data);
361  PRINT(0)("===================================================\n\n");
362}
363
364
365/********************************************************************************
366 *   MD2Data                                                                    *
367 ********************************************************************************/
368
369/**
370  \brief simple constructor
371*/
372MD2Data::MD2Data(const char* modelFileName, const char* skinFileName, float scale)
373{
374  scale *= 0.1f;
375
376  this->pVertices = NULL;
377  this->pGLCommands = NULL;
378  this->pLightNormals = NULL;
379  this->pTexCoor = NULL;
380
381  this->numFrames = 0;
382  this->numVertices = 0;
383  this->numGLCommands = 0;
384  this->numTexCoor = 0;
385
386//   this->scaleFactor = 1.0f;
387  this->scaleFactor = scale;
388
389  this->fileName = NULL;
390  this->skinFileName = NULL;
391  this->loadModel(modelFileName);
392  this->loadSkin(skinFileName);
393}
394
395
396/**
397  \brief simple destructor
398
399  this will clean out all the necessary data for a specific md2model
400*/
401MD2Data::~MD2Data()
402{
403  delete [] this->fileName;
404  delete [] this->skinFileName;
405  delete this->header;
406
407  delete [] this->pVertices;
408  delete [] this->pGLCommands;
409  delete [] this->pLightNormals;
410  delete [] this->pTexCoor;
411
412}
413
414
415
416/**
417  \brief this will load the whole model data (vertices, opengl command list, ...)
418* @param fileName: the name of the model file
419  \return true if success
420*/
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
429  //! @todo this chek should include deleting a loaded model (eventually)
430  if (fileName == NULL)
431    return false;
432
433  pFile = fopen(fileName, "rb");
434  if( unlikely(!pFile))
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;
455  this->numTexCoor = this->header->numTexCoords;
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];
460  this->pTriangles = new sTriangle[this->numTriangles];
461  this->pTexCoor = new sTexCoor[this->numTexCoor];
462  buffer = new char[this->numFrames * this->header->frameSize];
463
464
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);
471  /* triangle list */
472  fseek(pFile, this->header->offsetTriangles, SEEK_SET);
473  fread(this->pTriangles, sizeof(sTriangle), this->numTriangles, pFile);
474  /*  read in texture coordinates */
475  fseek(pFile, this->header->offsetTexCoords, SEEK_SET);
476  fread(this->pTexCoor, sizeof(sTexCoor), this->numTexCoor, pFile);
477
478
479  for(int i = 0; i < this->numFrames; ++i)
480    {
481      frame = (sFrame*)(buffer + this->header->frameSize * i);
482      pVertex = this->pVertices + this->numVertices  * i;
483      pNormals = this->pLightNormals + this->numVertices * i;
484
485      for(int j = 0; j < this->numVertices; ++j)
486        {
487          /* SPEEDUP: *(pVerts + i + 0) = (*(frame->pVertices + i + 0)...  */
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;
491
492          //printf("vertex %i/%i: (%f, %f, %f)\n", j, this->numVertices, pVertex[j][0], pVertex[j][1], pVertex[j][2]);
493
494          pNormals[j] = frame->pVertices[j].lightNormalIndex;
495        }
496    }
497    PRINTF(4)("Finished loading the md2 file\n");
498
499  delete [] buffer;
500  fclose(pFile);
501}
502
503
504/**
505  \brief loads the skin/material stuff
506* @param fileName: name of the skin file
507  \return true if success
508*/
509bool MD2Data::loadSkin(const char* fileName)
510{
511  if( fileName == NULL)
512    {
513      this->skinFileName = NULL;
514      return false;
515    }
516
517  this->skinFileName = new char[strlen(fileName)+1];
518  strcpy(this->skinFileName, fileName);
519
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);
524}
Note: See TracBrowser for help on using the repository browser.