Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 4434 was 4357, checked in by bensch, 19 years ago

orxonox/trunk: now Textures are maped as they should
before this textures where switched upside-down, now this is done in the corresponding model's textureCoordinate

File size: 11.3 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 *   MD2Model                                                                   * ********************************************************************************/
71
72/*
73  \brief simple constructor initializing all variables
74*/
75MD2Model::MD2Model()
76{
77  /* this creates the data container via ressource manager */
78  this->data = new MD2Data();
79  this->scaleFactor = this->data->scaleFactor;
80
81  this->setAnim(BOOM);
82}
83
84/*
85  \brief simple destructor, dereferencing all variables
86
87  this is where the ressource manager is cleaning the stuff
88*/
89MD2Model::~MD2Model()
90{
91
92}
93
94/*
95  \brief load model
96  \param name of the model file
97  \return true if everything worked out smoothly
98*/
99bool MD2Model::loadModel(const char* fileName)
100{
101  return this->data->loadModel(fileName);
102}
103
104
105/*
106  \brief load the skin as a material
107  \param name of the texture file
108  \return true if ok
109*/
110bool MD2Model::loadSkin(const char* fileName)
111{
112  return this->data->loadSkin(fileName);
113}
114
115
116/**
117   \brief initializes an array of vert with the current frame scaled vertices
118
119   we won't use the pVertices array directly, since its much easier and we need
120   saving of data anyway
121*/
122void MD2Model::interpolate(sVec3D* verticesList)
123{
124  sVec3D* currVec;
125  sVec3D* nextVec;
126
127  currVec = &this->data->pVertices[this->data->numVertices * this->animationState.currentFrame];
128  nextVec = &this->data->pVertices[this->data->numVertices * this->animationState.nextFrame];
129
130  for(int i = 0; i < this->data->numFrames; ++i)
131    {
132      verticesList[i][0] = (currVec[i][0] + this->animationState.interpolationState * (nextVec[i][0] - currVec[i][0])) * this->scaleFactor;
133      verticesList[i][1] = (currVec[i][1] + this->animationState.interpolationState * (nextVec[i][1] - currVec[i][1])) * this->scaleFactor;
134      verticesList[i][2] = (currVec[i][2] + this->animationState.interpolationState * (nextVec[i][2] - currVec[i][2])) * this->scaleFactor;
135    }
136}
137
138
139/*
140  \brief sets the animation type
141  \param animation type
142
143  the animation types can be looked up in the animationType table
144*/
145void MD2Model::setAnim(int type)
146{
147  if( (type < 0) || (type > MAX_ANIMATIONS) )
148    type = 0;
149
150  this->animationState.startFrame = animationList[type].firstFrame;
151  this->animationState.endFrame = animationList[type].lastFrame;
152  this->animationState.nextFrame = animationList[type].firstFrame + 1;
153  this->animationState.fps = animationList[type].fps;
154  this->animationState.type = type;
155 
156  this->animationState.interpolationState = 0.0;
157  this->animationState.localTime = 0.0;
158  this->animationState.lastTime = 0.0;
159  this->animationState.currentFrame = animationList[type].firstFrame;
160}
161
162
163/*
164  \brief sets the time in seconds passed since the last tick
165  \param time in sec
166*/
167void MD2Model::tick(float time)
168{
169  this->animationState.localTime += time;
170}
171
172
173/*
174  \brief draws the model: interface for all other classes out in the world
175*/
176void MD2Model::draw()
177{
178  if( likely(this->animationState.localTime > 0.0))
179    this->animate();
180
181  glPushMatrix();
182
183  this->renderFrame();
184
185  glPopMatrix();
186} 
187
188
189/*
190  \brief this is an internal function to render this special frame selected by animate()
191*/
192void MD2Model::renderFrame()
193{
194  static sVec3D verticesList[MD2_MAX_VERTICES]; /* performance: created only once in a lifetime */
195  int* pCommands = this->data->pGLCommands;
196
197  /* some face culling stuff */
198  glPushAttrib(GL_POLYGON_BIT);
199  glFrontFace(GL_CW);
200  glEnable(GL_CULL_FACE);
201  glCullFace(GL_BACK);
202     
203  this->processLighting();
204  this->interpolate(verticesList);
205  this->data->material->select();
206
207  /* draw the triangles */
208  while( int i = *(pCommands++)) /* strange looking while loop for maximum performance */
209    {
210      if( i < 0)
211        {
212          glBegin(GL_TRIANGLE_FAN);
213          i = -i;
214        }
215      else
216        {
217          glBegin(GL_TRIANGLE_STRIP);
218        }
219
220      for(; i > 0; i--, pCommands += 3) /* down counting for loop, next 3 gl commands */
221        {
222          glNormal3fv(anorms[this->data->pLightNormals[pCommands[2]]]);
223          glTexCoord2f( ((float *)pCommands)[0], ((float *)pCommands)[1] );
224          glVertex3fv(verticesList[pCommands[2]]);
225        }
226      glEnd();
227    }
228  glDisable(GL_CULL_FACE);
229  glPopAttrib();
230}
231
232
233/*
234  \brief animates the current model
235
236  depending on the time passed (tick function), the player will select another model
237*/
238void MD2Model::animate()
239{
240  if( this->animationState.localTime - this->animationState.lastTime > (1.0f / this->animationState.fps))
241    {
242      this->animationState.currentFrame = this->animationState.nextFrame;
243      this->animationState.nextFrame++;
244     
245      if( this->animationState.nextFrame > this->animationState.endFrame)
246        this->animationState.nextFrame = this->animationState.startFrame;
247      this->animationState.lastTime = this->animationState.localTime;
248    }
249
250  if( this->animationState.currentFrame > (this->data->numFrames - 1) )
251    this->animationState.currentFrame = 0;
252  if( this->animationState.nextFrame > (this->data->numFrames - 1) )
253    this->animationState.nextFrame = 0;
254
255  this->animationState.interpolationState = this->animationState.fps * 
256    (this->animationState.localTime - this->animationState.lastTime);
257}
258
259
260/*
261  \brief this is how id is precessing their lightning
262
263  the details of how the whole lighting process is beeing handled - i have no idea... :)
264*/
265void MD2Model::processLighting()
266{
267  shadeDots = anormsDots[((int)(md2Angle*(SHADEDOT_QUANT / 360.0)))&(SHADEDOT_QUANT - 1)];
268}
269
270/*
271  \brief prints out debug informations
272*/
273void MD2Model::debug()
274{
275  PRINT(0)("\n==========================| MD2Model::debug() |===\n");
276  PRINT(0)("=  Model FileName:\t%s\n", this->data->fileName);
277  PRINT(0)("=  Skin FileName:\t%s\n", this->data->skinFileName);
278  PRINT(0)("=  Size in Memory:\t%i Bytes\n", this->data->header->frameSize * this->data->header->numFrames + 64); // 64bytes is the header size
279  PRINT(0)("=  Number of Vertices:\t%i\n", this->data->header->numVertices);
280  PRINT(0)("=  Number of Frames: \t%i\n", this->data->header->numFrames);
281  PRINT(0)("=  Height, Width:\t%i, %i\n", this->data->header->skinHeight, this->data->header->skinWidth);
282  PRINT(0)("===================================================\n\n");
283}
284
285
286/********************************************************************************
287 *   MD2Data                                                                    *
288 ********************************************************************************/
289
290/*
291  \brief simple constructor
292*/
293MD2Data::MD2Data()
294{
295  this->pVertices = NULL;
296  this->pGLCommands = NULL;
297  this->pLightNormals = NULL; 
298
299  this->numFrames = 0;
300  this->numVertices = 0;
301  this->numGLCommands = 0;
302 
303  this->scaleFactor = 1.0f;
304}
305
306
307/*
308  \brief simple destructor
309
310  this will clean out all the necessary data for a specific md2model
311*/
312MD2Data::~MD2Data()
313{
314  delete [] this->pVertices;
315  delete [] this->pGLCommands;
316  delete [] this->pLightNormals;
317}
318
319
320
321/*
322  \brief this will load the whole model data (vertices, opengl command list, ...)
323  \param name to the model file
324  \return true if success
325*/
326bool MD2Data::loadModel(const char* fileName)
327{
328  FILE *pFile;                            //file stream
329  char* buffer;                           //buffer for frame data
330  sFrame* frame;                          //temp frame
331  sVec3D *pVertex;
332  int* pNormals;
333
334  pFile = fopen(fileName, "rb");
335  if( unlikely(!pFile)) 
336    {
337      PRINTF(1)("Couldn't open the MD2 File for loading. Exiting.\n");
338      return false;
339    }
340  this->header = new MD2Header;
341  fread(this->header, 1, sizeof(MD2Header), pFile);
342  /* check for the header version: make sure its a md2 file :) */
343  if( unlikely(this->header->version != MD2_VERSION) && unlikely(this->header->ident != MD2_IDENT))
344    {
345      PRINTF(1)("Couldn't load file %s: invalid file format: stop loading\n", fileName);
346      return false;
347    }
348
349  this->fileName = new char[strlen(fileName)+1];
350  strcpy(this->fileName, fileName);
351  /* got the data: map it to locals */
352  this->numFrames = this->header->numFrames;
353  this->numVertices = this->header->numVertices;
354  this->numTriangles = this->header->numTriangles;
355  this->numGLCommands = this->header->numGlCommands;
356  /* allocate memory for the data storage */
357  this->pVertices = new sVec3D[this->numVertices * this->numFrames];
358  this->pGLCommands = new int[this->numGLCommands];
359  this->pLightNormals = new int[this->numVertices * this->numFrames];
360  buffer = new char[this->numFrames * this->header->frameSize];
361
362  /* read frame data from the file to a temp buffer */
363  fseek(pFile, this->header->offsetFrames, SEEK_SET);
364  fread(buffer, this->header->frameSize, this->numFrames, pFile);
365  /* read opengl commands */
366  fseek(pFile, this->header->offsetGlCommands, SEEK_SET);
367  fread(this->pGLCommands, sizeof(int), this->numGLCommands, pFile);
368
369  for(int i = 0; i < this->numFrames; ++i)
370    {
371      frame = (sFrame*)(buffer + this->header->frameSize * i); 
372      pVertex = this->pVertices + this->numVertices  * i;
373      pNormals = this->pLightNormals + this->numVertices * i;
374
375      for(int j = 0; j < this->numVertices; ++j)
376        {
377          /* SPEEDUP: *(pVerts + i + 0) = (*(frame->pVertices + i + 0)...  */
378          pVertex[j][0] = (frame->pVertices[j].v[0] * frame->scale[0]) + frame->translate[0];
379          pVertex[j][1] = (frame->pVertices[j].v[2] * frame->scale[2]) + frame->translate[2];
380          pVertex[j][2] = -1.0 * (frame->pVertices[j].v[1] * frame->scale[1] + frame->translate[1]);
381         
382          pNormals[j] = frame->pVertices[j].lightNormalIndex;
383        }
384    }
385
386  delete [] buffer;
387  fclose(pFile);
388}
389
390
391/*
392  \brief loads the skin/material stuff
393  \param name of the skin file
394  \return true if success
395*/
396bool MD2Data::loadSkin(const char* fileName)
397{
398  this->skinFileName = new char[strlen(fileName)+1];
399  strcpy(this->skinFileName, fileName);
400
401  this->material = new Material("md2ModelTest");
402  this->material->setDiffuseMap(fileName);
403  this->material->setIllum(3);
404  this->material->setAmbient(1.0, 1.0, 1.0);
405}
Note: See TracBrowser for help on using the repository browser.