Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 4281 was 4281, checked in by patrick, 19 years ago

orxonox/trunk: seperated the data from the model: now MD2Data represents the vertex/skin data of a model and can be shared between multiple MD2Models.

File size: 12.6 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 "resource_manager.h"
21
22#include <fstream>
23
24
25using namespace std;
26
27
28sVec3D MD2Model::anorms[NUM_VERTEX_NORMALS] = {
29 #include "anorms.h"
30};
31
32float MD2Model::anormsDots[SHADEDOT_QUANT][256] = {
33  #include "anormtab.h"
34};
35
36static float *shadeDots = MD2Model::anormsDots[0];
37
38float md2Angle = 0.0f;
39
40
41sAnim MD2Model::animationList[21] =
42  {
43 // begin, end, fps
44    {   0,  39,  9 },   // STAND
45    {  40,  45, 10 },   // RUN
46    {  46,  53, 10 },   // ATTACK
47    {  54,  57,  7 },   // PAIN_A
48    {  58,  61,  7 },   // PAIN_B
49    {  62,  65,  7 },   // PAIN_C
50    {  66,  71,  7 },   // JUMP
51    {  72,  83,  7 },   // FLIP
52    {  84,  94,  7 },   // SALUTE
53    {  95, 111, 10 },   // FALLBACK
54    { 112, 122,  7 },   // WAVE
55    { 123, 134,  6 },   // POINTT
56    { 135, 153, 10 },   // CROUCH_STAND
57    { 154, 159,  7 },   // CROUCH_WALK
58    { 160, 168, 10 },   // CROUCH_ATTACK
59    { 196, 172,  7 },   // CROUCH_PAIN
60    { 173, 177,  5 },   // CROUCH_DEATH
61    { 178, 183,  7 },   // DEATH_FALLBACK
62    { 184, 189,  7 },   // DEATH_FALLFORWARD
63    { 190, 197,  7 },   // DEATH_FALLBACKSLOW
64    { 198, 198,  5 },   // BOOM
65  };
66
67
68
69/********************************************************************************
70 *   MD2Model2                                                                  *
71 ********************************************************************************/
72
73MD2Model::MD2Model()
74{
75  /*
76  this->pVertices = NULL;
77  this->pGLCommands = NULL;
78  this->pLightNormals = NULL;
79
80  this->numFrames = 0;
81  this->numVertices = 0;
82  this->numGLCommands = 0;
83 
84  this->scaleFactor = 1.0f;
85  */
86
87  /* this creates the data container via ressource manager */
88  this->data = new MD2Data();
89
90  this->setAnim(BOOM);
91}
92
93
94MD2Model::~MD2Model()
95{
96  /*
97  delete [] this->pVertices;
98  delete [] this->pGLCommands;
99  delete [] this->pLightNormals;
100  */
101}
102
103
104
105bool MD2Model::loadModel(const char* fileName)
106{
107  return this->data->loadModel(fileName);
108 
109
110  FILE *pFile;                            //file stream
111  char* buffer;                           //buffer for frame data
112  sFrame* frame;                          //temp frame
113  sVec3D *pVertex;
114  int* pNormals;
115
116  pFile = fopen(fileName, "rb");
117  if( unlikely(!pFile)) 
118    {
119      PRINTF(1)("Couldn't open the MD2 File for loading. Exiting.\n");
120      return false;
121    }
122  this->header = new MD2Header;
123  fread(this->header, 1, sizeof(MD2Header), pFile);
124  /* check for the header version: make sure its a md2 file :) */
125  if( unlikely(this->header->version != MD2_VERSION) && unlikely(this->header->ident != MD2_IDENT))
126    {
127      PRINTF(1)("Couldn't load file %s: invalid file format: stop loading\n", fileName);
128      return false;
129    }
130
131  this->fileName = new char[strlen(fileName)+1];
132  strcpy(this->fileName, fileName);
133  /* got the data: map it to locals */
134  this->numFrames = this->header->numFrames;
135  this->numVertices = this->header->numVertices;
136  this->numTriangles = this->header->numTriangles;
137  this->numGLCommands = this->header->numGlCommands;
138  /* allocate memory for the data storage */
139  this->pVertices = new sVec3D[this->numVertices * this->numFrames];
140  this->pGLCommands = new int[this->numGLCommands];
141  this->pLightNormals = new int[this->numVertices * this->numFrames];
142  buffer = new char[this->numFrames * this->header->frameSize];
143
144  /* read frame data from the file to a temp buffer */
145  fseek(pFile, this->header->offsetFrames, SEEK_SET);
146  fread(buffer, this->header->frameSize, this->numFrames, pFile);
147  /* read opengl commands */
148  fseek(pFile, this->header->offsetGlCommands, SEEK_SET);
149  fread(this->pGLCommands, sizeof(int), this->numGLCommands, pFile);
150
151  for(int i = 0; i < this->numFrames; ++i)
152    {
153      frame = (sFrame*)(buffer + this->header->frameSize * i); 
154      pVertex = this->pVertices + this->numVertices  * i;
155      pNormals = this->pLightNormals + this->numVertices * i;
156
157      for(int j = 0; j < this->numVertices; ++j)
158        {
159          /* SPEEDUP: *(pVerts + i + 0) = (*(frame->pVertices + i + 0)...  */
160          pVertex[j][0] = (frame->pVertices[j].v[0] * frame->scale[0]) + frame->translate[0];
161          pVertex[j][1] = (frame->pVertices[j].v[2] * frame->scale[2]) + frame->translate[2];
162          pVertex[j][2] = -1.0 * (frame->pVertices[j].v[1] * frame->scale[1] + frame->translate[1]);
163         
164          pNormals[j] = frame->pVertices[j].lightNormalIndex;
165        }
166    }
167
168  delete [] buffer;
169  fclose(pFile);
170}
171
172
173bool MD2Model::loadSkin(const char* fileName)
174{
175  return this->data->loadSkin(fileName);
176
177  this->skinFileName = new char[strlen(fileName)+1];
178  strcpy(this->skinFileName, fileName);
179  this->material = new Material("md2ModelTest");
180  this->material->setDiffuseMap(fileName);
181  this->material->setIllum(3);
182  this->material->setAmbient(1.0, 1.0, 1.0);
183}
184
185
186/**
187   \brief initializes an array of vert with the current frame scaled vertices
188
189   we won't use the pVertices array directly, since its much easier and we need
190   saving of data anyway
191*/
192void MD2Model::interpolate(sVec3D* verticesList)
193{
194  sVec3D* currVec;
195  sVec3D* nextVec;
196
197  currVec = &this->data->pVertices[this->data->numVertices * this->animationState.currentFrame];
198  nextVec = &this->data->pVertices[this->data->numVertices * this->animationState.nextFrame];
199
200  for(int i = 0; i < this->data->numFrames; ++i)
201    {
202      verticesList[i][0] = (currVec[i][0] + this->animationState.interpolationState * (nextVec[i][0] - currVec[i][0])) * this->data->scaleFactor;
203      verticesList[i][1] = (currVec[i][1] + this->animationState.interpolationState * (nextVec[i][1] - currVec[i][1])) * this->data->scaleFactor;
204      verticesList[i][2] = (currVec[i][2] + this->animationState.interpolationState * (nextVec[i][2] - currVec[i][2])) * this->data->scaleFactor;
205    }
206}
207
208
209void MD2Model::setAnim(int type)
210{
211  if( (type < 0) || (type > MAX_ANIMATIONS) )
212    type = 0;
213
214  this->animationState.startFrame = animationList[type].firstFrame;
215  this->animationState.endFrame = animationList[type].lastFrame;
216  this->animationState.nextFrame = animationList[type].firstFrame + 1;
217  this->animationState.fps = animationList[type].fps;
218  this->animationState.type = type;
219 
220  this->animationState.interpolationState = 0.0;
221  this->animationState.localTime = 0.0;
222  this->animationState.lastTime = 0.0;
223  this->animationState.currentFrame = animationList[type].firstFrame;
224}
225
226
227void MD2Model::tick(float time)
228{
229  this->animationState.localTime += time;
230}
231
232
233void MD2Model::draw()
234{
235  if( likely(this->animationState.localTime > 0.0))
236    this->animate();
237
238  glPushMatrix();
239
240  this->renderFrame();
241
242  glPopMatrix();
243} 
244
245
246void MD2Model::renderFrame()
247{
248  static sVec3D verticesList[MD2_MAX_VERTICES]; /* performance: created only once in a lifetime */
249  int* pCommands = this->data->pGLCommands;
250
251  /* some face culling stuff */
252  glPushAttrib(GL_POLYGON_BIT);
253  glFrontFace(GL_CW);
254  glEnable(GL_CULL_FACE);
255  glCullFace(GL_BACK);
256     
257  this->processLighting();
258  this->interpolate(verticesList);
259  this->data->material->select();
260
261  /* draw the triangles */
262  while( int i = *(pCommands++)) /* strange looking while loop for maximum performance */
263    {
264      if( i < 0)
265        {
266          glBegin(GL_TRIANGLE_FAN);
267          i = -i;
268        }
269      else
270        {
271          glBegin(GL_TRIANGLE_STRIP);
272        }
273
274      for(; i > 0; i--, pCommands += 3) /* down counting for loop, next 3 gl commands */
275        {
276          glNormal3fv(anorms[this->data->pLightNormals[pCommands[2]]]);
277          glTexCoord2f( ((float *)pCommands)[0], 1.0-((float *)pCommands)[1] );
278          glVertex3fv(verticesList[pCommands[2]]);
279        }
280      glEnd();
281    }
282  glDisable(GL_CULL_FACE);
283  glPopAttrib();
284}
285
286
287void MD2Model::animate()
288{
289  if( this->animationState.localTime - this->animationState.lastTime > (1.0f / this->animationState.fps))
290    {
291      this->animationState.currentFrame = this->animationState.nextFrame;
292      this->animationState.nextFrame++;
293     
294      if( this->animationState.nextFrame > this->animationState.endFrame)
295        this->animationState.nextFrame = this->animationState.startFrame;
296      this->animationState.lastTime = this->animationState.localTime;
297    }
298
299  if( this->animationState.currentFrame > (this->data->numFrames - 1) )
300    this->animationState.currentFrame = 0;
301  if( this->animationState.nextFrame > (this->data->numFrames - 1) )
302    this->animationState.nextFrame = 0;
303
304  this->animationState.interpolationState = this->animationState.fps * 
305    (this->animationState.localTime - this->animationState.lastTime);
306}
307
308
309/* hhmmm... id used a very different way to do lightning... */
310void MD2Model::processLighting()
311{
312  shadeDots = anormsDots[((int)(md2Angle*(SHADEDOT_QUANT / 360.0)))&(SHADEDOT_QUANT - 1)];
313}
314
315
316void MD2Model::debug()
317{
318  PRINT(0)("==========================| MD2Model::debug() |===\n");
319  PRINT(0)("=  Model FileName:\t%s\n", this->data->fileName);
320  PRINT(0)("=  Skin FileName:\t%s\n", this->data->skinFileName);
321  PRINT(0)("=  Size in Memory:\t%i Bytes\n", this->data->header->frameSize * this->data->header->numFrames + 64); // 64bytes is the header size
322  PRINT(0)("=  Number of Vertices:\t%i\n", this->data->header->numVertices);
323  PRINT(0)("=  Number of Frames: \t%i\n", this->data->header->numFrames);
324  PRINT(0)("=  Height, Width\t\t%i, %i\n", this->data->header->skinHeight, this->data->header->skinWidth);
325  PRINT(0)("===================================================\n\n");
326}
327
328
329
330
331
332MD2Data::MD2Data()
333{
334  this->pVertices = NULL;
335  this->pGLCommands = NULL;
336  this->pLightNormals = NULL; 
337
338  this->numFrames = 0;
339  this->numVertices = 0;
340  this->numGLCommands = 0;
341 
342  this->scaleFactor = 1.0f;
343}
344
345
346MD2Data::~MD2Data()
347{
348  delete [] this->pVertices;
349  delete [] this->pGLCommands;
350  delete [] this->pLightNormals;
351}
352
353
354
355bool MD2Data::loadModel(const char* fileName)
356{
357  FILE *pFile;                            //file stream
358  char* buffer;                           //buffer for frame data
359  sFrame* frame;                          //temp frame
360  sVec3D *pVertex;
361  int* pNormals;
362
363  pFile = fopen(fileName, "rb");
364  if( unlikely(!pFile)) 
365    {
366      PRINTF(1)("Couldn't open the MD2 File for loading. Exiting.\n");
367      return false;
368    }
369  this->header = new MD2Header;
370  fread(this->header, 1, sizeof(MD2Header), pFile);
371  /* check for the header version: make sure its a md2 file :) */
372  if( unlikely(this->header->version != MD2_VERSION) && unlikely(this->header->ident != MD2_IDENT))
373    {
374      PRINTF(1)("Couldn't load file %s: invalid file format: stop loading\n", fileName);
375      return false;
376    }
377
378  this->fileName = new char[strlen(fileName)+1];
379  strcpy(this->fileName, fileName);
380  /* got the data: map it to locals */
381  this->numFrames = this->header->numFrames;
382  this->numVertices = this->header->numVertices;
383  this->numTriangles = this->header->numTriangles;
384  this->numGLCommands = this->header->numGlCommands;
385  /* allocate memory for the data storage */
386  this->pVertices = new sVec3D[this->numVertices * this->numFrames];
387  this->pGLCommands = new int[this->numGLCommands];
388  this->pLightNormals = new int[this->numVertices * this->numFrames];
389  buffer = new char[this->numFrames * this->header->frameSize];
390
391  /* read frame data from the file to a temp buffer */
392  fseek(pFile, this->header->offsetFrames, SEEK_SET);
393  fread(buffer, this->header->frameSize, this->numFrames, pFile);
394  /* read opengl commands */
395  fseek(pFile, this->header->offsetGlCommands, SEEK_SET);
396  fread(this->pGLCommands, sizeof(int), this->numGLCommands, pFile);
397
398  for(int i = 0; i < this->numFrames; ++i)
399    {
400      frame = (sFrame*)(buffer + this->header->frameSize * i); 
401      pVertex = this->pVertices + this->numVertices  * i;
402      pNormals = this->pLightNormals + this->numVertices * i;
403
404      for(int j = 0; j < this->numVertices; ++j)
405        {
406          /* SPEEDUP: *(pVerts + i + 0) = (*(frame->pVertices + i + 0)...  */
407          pVertex[j][0] = (frame->pVertices[j].v[0] * frame->scale[0]) + frame->translate[0];
408          pVertex[j][1] = (frame->pVertices[j].v[2] * frame->scale[2]) + frame->translate[2];
409          pVertex[j][2] = -1.0 * (frame->pVertices[j].v[1] * frame->scale[1] + frame->translate[1]);
410         
411          pNormals[j] = frame->pVertices[j].lightNormalIndex;
412        }
413    }
414
415  delete [] buffer;
416  fclose(pFile);
417}
418
419
420bool MD2Data::loadSkin(const char* fileName)
421{
422  this->skinFileName = new char[strlen(fileName)+1];
423  strcpy(this->skinFileName, fileName);
424
425  this->material = new Material("md2ModelTest");
426  this->material->setDiffuseMap(fileName);
427  this->material->setIllum(3);
428  this->material->setAmbient(1.0, 1.0, 1.0);
429}
Note: See TracBrowser for help on using the repository browser.