Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/new_class_id/src/lib/graphics/importer/md2/md2Model.cc @ 9824

Last change on this file since 9824 was 9824, checked in by bensch, 18 years ago

first try to make the MD2-model a Resource… it looks quite funny… seems like everything gets loaded, but totally wrong :)

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