Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 6827 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
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,  7, 0 },   //!< DEATH_FALLBACK
63    { 184, 189,  7, 0 },   //!< DEATH_FALLFORWARD
64    { 190, 197,  7, 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)
78{
79  /* this creates the data container via ressource manager */
80  this->data = (MD2Data*)ResourceManager::getInstance()->load(modelFileName, MD2, RP_GAME, skinFileName);
81  if( unlikely(this->data == NULL))
82    PRINTF(0)("The model was not found, MD2Model Loader finished abnormaly. Update the data-repos\n");
83
84  this->scaleFactor = this->data->scaleFactor;
85
86  shadeDots = MD2Model::anormsDots[0];
87  /* set the animation stat mannualy */
88  this->animationState.type = STAND;
89  this->animationState.numPlays = 1;
90  this->setAnim(STAND);
91
92  this->debug();
93}
94
95/**
96  \brief simple destructor, dereferencing all variables
97
98  this is where the ressource manager is cleaning the stuff
99*/
100MD2Model::~MD2Model()
101{
102  ResourceManager::getInstance()->unload(this->data);
103}
104
105
106/**
107 *  initializes an array of vert with the current frame scaled vertices
108 * @param this->verticesList: the list of vertices to interpolate between
109
110   we won't use the pVertices array directly, since its much easier and we need
111   saving of data anyway
112*/
113void MD2Model::interpolate(/*sVec3D* this->verticesList*/)
114{
115  sVec3D* currVec;
116  sVec3D* nextVec;
117
118  currVec = &this->data->pVertices[this->data->numVertices * this->animationState.currentFrame];
119  nextVec = &this->data->pVertices[this->data->numVertices * this->animationState.nextFrame];
120
121  for( int i = 0; i < this->data->numVertices; ++i)
122    {
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]);
126    }
127}
128
129
130/**
131  \brief sets the animation type
132* @param type: animation type
133
134  the animation types can be looked up in the animationType table
135*/
136void MD2Model::setAnim(int type)
137{
138  if( (type < 0) || (type > MAX_ANIMATIONS) )
139    type = STAND;
140
141  if( MD2Model::animationList[this->animationState.type].bStoppable == 0)
142  {
143    if( this->animationState.numPlays == 0 )
144      return;
145  }
146
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;
152  this->animationState.numPlays = 0;
153
154  this->animationState.interpolationState = 0.0f;
155  this->animationState.localTime = 0.0f;
156  this->animationState.lastTime = 0.0f;
157  this->animationState.currentFrame = animationList[type].firstFrame;
158}
159
160
161/**
162  \brief sets the time in seconds passed since the last tick
163* @param time: in sec
164*/
165void MD2Model::tick(float time)
166{
167  this->animate(time);
168  this->processLighting();
169  this->interpolate(/*this->verticesList*/);
170}
171
172
173/**
174 * @brief draws the model: interface for all other classes out in the world
175 * @todo make it const and virtual
176 * FIXME
177 */
178void MD2Model::draw() const
179{
180  glPushMatrix();
181  this->renderFrame();
182  // renderFrameTriangles();
183  glPopMatrix();
184}
185
186
187/**
188  \brief this is an internal function to render this special frame selected by animate()
189*/
190void MD2Model::renderFrame() const
191{
192  int* pCommands = this->data->pGLCommands;
193
194  /* some face culling stuff */
195  glPushAttrib(GL_POLYGON_BIT);
196  glFrontFace(GL_CW);
197  glEnable(GL_CULL_FACE);
198  glCullFace(GL_BACK);
199
200  this->data->material->select();
201
202  /* draw the triangles */
203  while( int i = *(pCommands++)) /* strange looking while loop for maximum performance */
204    {
205      if( i < 0)
206        {
207          glBegin(GL_TRIANGLE_FAN);
208          i = -i;
209        }
210      else
211        {
212          glBegin(GL_TRIANGLE_STRIP);
213        }
214
215      for(; i > 0; i--, pCommands += 3) /* down counting for loop, next 3 gl commands */
216        {
217          glTexCoord2f( ((float *)pCommands)[0], ((float *)pCommands)[1] );
218          glNormal3fv(anorms[this->data->pLightNormals[pCommands[2]]]);
219          glVertex3fv(this->verticesList[pCommands[2]]);
220        }
221      glEnd();
222
223    }
224  glDisable(GL_CULL_FACE);
225  glPopAttrib();
226}
227
228
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
272/**
273  \brief animates the current model
274
275  depending on the time passed (tick function), the player will select another model
276*/
277void MD2Model::animate(float time)
278{
279  this->animationState.localTime += time;
280
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++;
285
286      if( this->animationState.nextFrame > this->animationState.endFrame)
287      {
288        this->animationState.nextFrame = this->animationState.startFrame;
289        this->animationState.numPlays++;
290      }
291      this->animationState.lastTime = this->animationState.localTime;
292    }
293
294  if( this->animationState.currentFrame > (this->data->numFrames - 1) )
295    this->animationState.currentFrame = 0;
296  if( this->animationState.nextFrame > (this->data->numFrames - 1) )
297    this->animationState.nextFrame = 0;
298
299  this->animationState.interpolationState = this->animationState.fps *
300    (this->animationState.localTime - this->animationState.lastTime);
301}
302
303
304/**
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*/
309void MD2Model::processLighting()
310{
311  shadeDots = anormsDots[((int)(md2Angle*(SHADEDOT_QUANT / 360.0)))&(SHADEDOT_QUANT - 1)];
312}
313
314
315/**
316  \brief prints out debug informations
317*/
318void MD2Model::debug()
319{
320  PRINT(0)("\n==========================| MD2Model::debug() |===\n");
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);
326  PRINT(0)("=  Height, Width:\t%i, %i\n", this->data->header->skinHeight, this->data->header->skinWidth);
327  PRINT(0)("=  Pointer to the data object: %p\n", this->data);
328  PRINT(0)("===================================================\n\n");
329}
330
331
332/********************************************************************************
333 *   MD2Data                                                                    *
334 ********************************************************************************/
335
336/**
337  \brief simple constructor
338*/
339MD2Data::MD2Data(const char* modelFileName, const char* skinFileName)
340{
341  this->pVertices = NULL;
342  this->pGLCommands = NULL;
343  this->pLightNormals = NULL;
344  this->pTexCoor = NULL;
345
346  this->numFrames = 0;
347  this->numVertices = 0;
348  this->numGLCommands = 0;
349  this->numTexCoor = 0;
350
351//   this->scaleFactor = 1.0f;
352  this->scaleFactor = 0.1f;
353
354  this->fileName = NULL;
355  this->skinFileName = NULL;
356  this->loadModel(modelFileName);
357  this->loadSkin(skinFileName);
358}
359
360
361/**
362  \brief simple destructor
363
364  this will clean out all the necessary data for a specific md2model
365*/
366MD2Data::~MD2Data()
367{
368  delete [] this->fileName;
369  delete [] this->skinFileName;
370  delete this->header;
371
372  delete [] this->pVertices;
373  delete [] this->pGLCommands;
374  delete [] this->pLightNormals;
375  delete [] this->pTexCoor;
376
377  delete this->material;
378}
379
380
381
382/**
383  \brief this will load the whole model data (vertices, opengl command list, ...)
384* @param fileName: the name of the model file
385  \return true if success
386*/
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
395  //! @todo this chek should include deleting a loaded model (eventually)
396  if (fileName == NULL)
397    return false;
398
399  pFile = fopen(fileName, "rb");
400  if( unlikely(!pFile))
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;
421  this->numTexCoor = this->header->numTexCoords;
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];
426  this->pTriangles = new sTriangle[this->numTriangles];
427  this->pTexCoor = new sTexCoor[this->numTexCoor];
428  buffer = new char[this->numFrames * this->header->frameSize];
429
430
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);
437  /* triangle list */
438  fseek(pFile, this->header->offsetTriangles, SEEK_SET);
439  fread(this->pTriangles, sizeof(sTriangle), this->numTriangles, pFile);
440  /*  read in texture coordinates */
441  fseek(pFile, this->header->offsetTexCoords, SEEK_SET);
442  fread(this->pTexCoor, sizeof(sTexCoor), this->numTexCoor, pFile);
443
444
445  for(int i = 0; i < this->numFrames; ++i)
446    {
447      frame = (sFrame*)(buffer + this->header->frameSize * i);
448      pVertex = this->pVertices + this->numVertices  * i;
449      pNormals = this->pLightNormals + this->numVertices * i;
450
451      for(int j = 0; j < this->numVertices; ++j)
452        {
453          /* SPEEDUP: *(pVerts + i + 0) = (*(frame->pVertices + i + 0)...  */
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;
457
458          //printf("vertex %i/%i: (%f, %f, %f)\n", j, this->numVertices, pVertex[j][0], pVertex[j][1], pVertex[j][2]);
459
460          pNormals[j] = frame->pVertices[j].lightNormalIndex;
461        }
462    }
463    PRINTF(4)("Finished loading the md2 file\n");
464
465  delete [] buffer;
466  fclose(pFile);
467}
468
469
470/**
471  \brief loads the skin/material stuff
472* @param fileName: name of the skin file
473  \return true if success
474*/
475bool MD2Data::loadSkin(const char* fileName)
476{
477  if( fileName == NULL)
478    {
479      this->skinFileName = NULL;
480      return false;
481    }
482
483  this->skinFileName = new char[strlen(fileName)+1];
484  strcpy(this->skinFileName, fileName);
485
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.