Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/branches/md2_loader/src/lib/graphics/importer/md2Model.cc @ 4187

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

orxonox/branches/md2_model: lightning alg extended, now almost complete.

File size: 19.2 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 <fstream>
21#include <string>
22#include <vector>
23
24
25using namespace std;
26
27
28sVec3D MD2Model2::anorms[NUM_VERTEX_NORMALS] = {
29 #include "anorms.h"
30};
31
32float MD2Model2::anormsDots[SHADEDOT_QUANT][256] = {
33  #include "anormtab.h"
34};
35
36static float *shadedots = MD2Model2::anormsDots[0];
37
38
39/********************************************************************************
40 *   MD2MODEL                                                                   *
41 ********************************************************************************/
42
43/**
44   \brief standard constructor
45   
46   creates a new model
47*/
48MD2Model::MD2Model () 
49{
50  this->setClassName ("MD2Model");
51
52  MD2Loader* md2loader = new MD2Loader();
53  this->model = new t3DModel;
54  md2loader->importMD2(this->model, "../data/models/tris.md2");
55  delete md2loader;
56}
57
58
59/**
60   \brief standard deconstructor
61
62*/
63MD2Model::~MD2Model () 
64{
65  // delete what has to be deleted here
66}
67
68
69void MD2Model::animate()
70{
71  if( unlikely(this->model->objectList.size() <= 0)) return;
72  /* get current animation from the list */
73  tAnimationInfo *pAnim = &(this->model->animationList[this->model->currentAnim]);
74
75  int nextFrame = (this->model->currentFrame + 1) % pAnim->endFrame;
76  if( unlikely(nextFrame == 0)) 
77    nextFrame =  pAnim->startFrame;
78
79  t3DObject *pFrame = &this->model->objectList[this->model->currentFrame];
80  t3DObject *pNextFrame = &this->model->objectList[nextFrame];
81
82  /* we have stored the texture and face information only in the first frame */
83  t3DObject *pFirstFrame = &this->model->objectList[0];
84
85  /* get the current time as a value in the domain [0..1] :)) */
86  float t = this->getCurrentTime(this->model, nextFrame);
87
88  glBegin(GL_TRIANGLES);
89  for(int j = 0; j < pFrame->numOfFaces; j++)
90    {
91      for(int whichVertex = 0; whichVertex < 3; whichVertex++)
92        {
93          int vertIndex = pFirstFrame->pFaces[j].vertIndex[whichVertex];
94          int texIndex  = pFirstFrame->pFaces[j].coordIndex[whichVertex];
95                                               
96          if( likely(pFirstFrame->pTexVerts != NULL)) 
97            {
98              glTexCoord2f(pFirstFrame->pTexVerts[texIndex].x, 
99                           pFirstFrame->pTexVerts[texIndex].y);
100            }
101                       
102          /* here comes the interpolation part */
103          CVector3 vPoint1 = pFrame->pVerts[vertIndex];
104          CVector3 vPoint2 = pNextFrame->pVerts[vertIndex];
105          glVertex3f(vPoint1.x + t * (vPoint2.x - vPoint1.x), 
106                     vPoint1.y + t * (vPoint2.y - vPoint1.y),
107                     vPoint1.z + t * (vPoint2.z - vPoint1.z));
108        }
109    }
110  glEnd();
111}
112
113
114float MD2Model::getCurrentTime(t3DModel *pModel, int nextFrame)
115{
116  /* stretch the time with animation speed (and make seconds out of it) */
117  //float t = this->dtS / kAnimationSpeed;
118       
119  if ( unlikely(this->localTime*1000.0 >=  1000.0/kAnimationSpeed) )
120    {
121      pModel->currentFrame = nextFrame;
122      this->localTime = 0.0f;
123    }
124  return (this->localTime / kAnimationSpeed);
125}
126
127
128void MD2Model::tick(float dtS)
129{
130  this->localTime += dtS;
131}
132
133/**
134   \brief draw function
135 
136   these function will take NO argument in the final version, just for testing
137*/
138void MD2Model::draw()
139{
140  if( this->model->objectList.size() <= 0) return;
141
142  t3DObject *pObject = &this->model->objectList[0];
143  glBegin(GL_TRIANGLES);
144  for(int j = 0; j < pObject->numOfFaces; j++)
145    {
146      for(int whichVertex = 0; whichVertex < 3; whichVertex++)
147        {
148          int index = pObject->pFaces[j].vertIndex[whichVertex];
149          int index2 = pObject->pFaces[j].coordIndex[whichVertex];
150          /* we invert the normals since the md2 file format uses different style */
151          /* FIX FIX FIX: ther are actualy no reasons to compute the normals every frame: change this later*/
152          glNormal3f(-pObject->pNormals[index].x, -pObject->pNormals[index].y, -pObject->pNormals[index].z);
153
154          if( likely(pObject->pTexVerts != NULL)) 
155            {
156              glTexCoord2f(pObject->pTexVerts[index2].x, pObject->pTexVerts[index2].y);
157            }
158          glVertex3f(pObject->pVerts[index].x, pObject->pVerts[index].y, pObject->pVerts[index].z);
159        }
160    }
161  glEnd();
162}
163
164/********************************************************************************
165 *   MD2LOADER                                                                  *
166 ********************************************************************************/
167
168/**
169   \brief standard deconstructor
170   creates a new model loader
171*/
172MD2Loader::MD2Loader()
173{
174  this->setClassName ("MD2Loader");
175  /* initialize all data to initial state */
176  memset(&this->header, 0, sizeof(tMd2Header));
177  this->pSkins = NULL;
178  this->pTexCoords = NULL;
179  this->pTriangles = NULL;
180  this->pFrames = NULL;
181}
182
183/**
184   \brief standard deconstructor
185*/
186MD2Loader::~MD2Loader()
187{}
188 
189
190/**
191   \brief this is called by the client to open the .Md2 file, read it, then clean up
192   \param model to load in
193   \param file name to load
194   \param texture name to load
195*/
196bool MD2Loader::importMD2(t3DModel *pModel, char *fileName, char *textureName)
197{
198  this->pFile = fopen(fileName, "rb");
199  if( unlikely(!pFile)) 
200    {
201      PRINTF(1)("Couldn't open the MD2 File for loading. Exiting.\n");
202      return false;
203    }
204  fread(&this->header, 1, sizeof(tMd2Header), pFile);
205  /* check for the header version: make sure its a md2 file :) */
206  if( likely(this->header.version != 8))
207    {
208      PRINTF(1)("Couldn't load file %s: invalid file format: stop loading\n", fileName);
209      return false;
210    }
211       
212  this->readMD2Data();
213  this->convertDataStructures(pModel);
214  this->computeNormals(pModel);
215
216  if( likely((int)textureName))
217    {
218      tMaterialInfo textureInfo;
219      strcpy(textureInfo.strFile, textureName);
220      /* since there is only one texture for a .Md2 file, the ID is always 0 */
221      textureInfo.texureId = 0;
222      textureInfo.uTile = 1;
223      /* we only have 1 material for a model */
224      pModel->numOfMaterials = 1;
225      pModel->materialList.push_back(textureInfo);
226    }
227       
228  this->cleanUp();
229  return true;
230}
231
232
233/**
234   \brief This function reads in all of the model's data, except the animation frames
235*/
236void MD2Loader::readMD2Data()
237{
238  unsigned char buffer[MD2_MAX_FRAMESIZE];
239  this->pSkins     = new tMd2Skin[this->header.numSkins];
240  this->pTexCoords = new tMd2TexCoord[this->header.numTexCoords];
241  this->pTriangles = new tMd2Face[this->header.numTriangles];
242  this->pFrames    = new tMd2Frame[this->header.numFrames];
243
244  /* we read the skins */
245  fseek(this->pFile, this->header.offsetSkins, SEEK_SET);
246  fread(this->pSkins, sizeof(tMd2Skin), this->header.numSkins, this->pFile);
247  /* read all vertex data */
248  fseek(this->pFile, this->header.offsetTexCoords, SEEK_SET);
249  fread(this->pTexCoords, sizeof(tMd2TexCoord), this->header.numTexCoords, this->pFile);
250  /* read face data for each triangle (normals) */
251  fseek(this->pFile, this->header.offsetTriangles, SEEK_SET);
252  fread(this->pTriangles, sizeof(tMd2Face), this->header.numTriangles, this->pFile);
253  /* reading all frame data */
254  fseek(this->pFile, this->header.offsetFrames, SEEK_SET);
255  for( int i = 0; i < this->header.numFrames; i++)
256    {
257      tMd2AliasFrame *pFrame = (tMd2AliasFrame *) buffer;
258      this->pFrames[i].pVertices = new tMd2Triangle [this->header.numVertices];
259
260      /* read the frame animation data */
261      fread(pFrame, 1, this->header.frameSize, this->pFile);
262      strcpy(this->pFrames[i].strName, pFrame->name);
263      tMd2Triangle *pVertices = this->pFrames[i].pVertices;
264      /*
265         scale translations, store vertices: since id used a non-opengl xyz notation, we have to swap y and z
266         and negate z axis
267      */
268      for( int j = 0; j < this->header.numVertices; j++)
269        {
270          pVertices[j].vertex[0] = pFrame->aliasVertices[j].vertex[0] * pFrame->scale[0] + pFrame->translate[0];
271          pVertices[j].vertex[2] = -1 * (pFrame->aliasVertices[j].vertex[1] * pFrame->scale[1] + pFrame->translate[1]);
272          pVertices[j].vertex[1] = pFrame->aliasVertices[j].vertex[2] * pFrame->scale[2] + pFrame->translate[2];
273        }
274    }
275}
276
277
278/**
279   \brief this function fills in the animation list for each animation by name and frame
280   \param model
281*/
282void MD2Loader::parseAnimations(t3DModel *pModel)
283{
284  tAnimationInfo animationInfo;
285  string strLastName = "";
286
287  /* the animation parse process looks a little bit wired: this is because there are no
288     fix bounds for the animation lengths, so the frames are destingushed using their names
289     which is normaly composed of <animationname><number>
290  */
291
292  for(int i = 0; i < pModel->numOfObjects; i++)
293    {
294      string strName  = this->pFrames[i].strName;
295      int frameNum = 0;
296       
297      /* erease the frame number from the frame-name */
298      for(unsigned int j = 0; j < strName.length(); j++)
299        {
300          if( isdigit(strName[j]) && j >= strName.length() - 2)
301            {
302              frameNum = atoi(&strName[j]);
303              strName.erase(j, strName.length() - j);
304              break;
305            }
306        }
307
308      printf("current: %s, last: %s\n", strName.c_str(), strLastName.c_str());
309
310      /* animations are sorted through their names: this is how its been done: */
311      if( strName != strLastName || i == pModel->numOfObjects - 1)
312        {
313          if( strLastName != "")
314            {
315              strcpy(animationInfo.strName, strLastName.c_str());
316              animationInfo.endFrame = i;
317              pModel->animationList.push_back(animationInfo);
318              memset(&animationInfo, 0, sizeof(tAnimationInfo));
319              pModel->numOfAnimations++;
320            }
321          animationInfo.startFrame = frameNum - 1 + i;
322        }
323      strLastName = strName;
324    }
325}
326
327
328/**
329   \brief this function converts the .md2 structures to our own model and object structures: decompress
330   \param model
331*/
332void MD2Loader::convertDataStructures(t3DModel *pModel)
333{
334  int j = 0, i = 0;
335       
336  memset(pModel, 0, sizeof(t3DModel));
337  pModel->numOfObjects = this->header.numFrames;
338
339  this->parseAnimations(pModel);
340
341  for (i = 0; i < pModel->numOfObjects; i++)
342    {
343      t3DObject currentFrame;
344
345      currentFrame.numOfVerts = this->header.numVertices;
346      currentFrame.numTexVertex = this->header.numTexCoords;
347      currentFrame.numOfFaces = this->header.numTriangles;
348
349      currentFrame.pVerts = new CVector3[currentFrame.numOfVerts];
350
351      for (j = 0; j < currentFrame.numOfVerts; j++)
352        {
353          currentFrame.pVerts[j].x = this->pFrames[i].pVertices[j].vertex[0];
354          currentFrame.pVerts[j].y = this->pFrames[i].pVertices[j].vertex[1];
355          currentFrame.pVerts[j].z = this->pFrames[i].pVertices[j].vertex[2];
356        }
357
358      delete this->pFrames[i].pVertices;
359
360      if( likely(i > 0))
361        {
362          pModel->objectList.push_back(currentFrame);
363          continue;
364        }
365                       
366      currentFrame.pTexVerts = new CVector2[currentFrame.numTexVertex];
367      currentFrame.pFaces = new tFace[currentFrame.numOfFaces];
368
369      for(j = 0; j < currentFrame.numTexVertex; j++)
370        {
371          currentFrame.pTexVerts[j].x = this->pTexCoords[j].u / float(this->header.skinWidth);
372          currentFrame.pTexVerts[j].y = 1 - this->pTexCoords[j].v / float(this->header.skinHeight);
373        }
374
375      for(j = 0; j < currentFrame.numOfFaces; j++)
376        {
377          currentFrame.pFaces[j].vertIndex[0] = this->pTriangles[j].vertexIndices[0];
378          currentFrame.pFaces[j].vertIndex[1] = this->pTriangles[j].vertexIndices[1];
379          currentFrame.pFaces[j].vertIndex[2] = this->pTriangles[j].vertexIndices[2];
380
381          currentFrame.pFaces[j].coordIndex[0] = this->pTriangles[j].textureIndices[0];
382          currentFrame.pFaces[j].coordIndex[1] = this->pTriangles[j].textureIndices[1];
383          currentFrame.pFaces[j].coordIndex[2] = this->pTriangles[j].textureIndices[2];
384        }
385      pModel->objectList.push_back(currentFrame);
386    }
387}
388
389
390/**
391   \brief this function conputes the normals of the model
392   \param model
393*/
394void MD2Loader::computeNormals(t3DModel *pModel)
395{
396  CVector3 vVector1, vVector2, vNormal, vPoly[3];
397
398  if( unlikely(pModel->numOfObjects <= 0))
399    return;
400  /* now computing face normals: this means just averaging the vertex normals of a face */
401  /* so for every object: */
402  for(int index = 0; index < pModel->numOfObjects; index++)
403    {
404      t3DObject *pObject = &(pModel->objectList[index]);
405
406      /* allocate all the memory we need to calculate the normals */
407      CVector3 *pNormals = new CVector3 [pObject->numOfFaces];
408      CVector3 *pTempNormals = new CVector3 [pObject->numOfFaces];
409      pObject->pNormals = new CVector3 [pObject->numOfVerts];
410
411      for(int i=0; i < pObject->numOfFaces; i++)
412        {
413          /* cache the points to make coding easier :) */
414          vPoly[0] = pObject->pVerts[pObject->pFaces[i].vertIndex[0]];
415          vPoly[1] = pObject->pVerts[pObject->pFaces[i].vertIndex[1]];
416          vPoly[2] = pObject->pVerts[pObject->pFaces[i].vertIndex[2]];
417
418          vVector1 = MathHelp::VectorDiff(vPoly[0], vPoly[2]);         
419          vVector2 = MathHelp::VectorDiff(vPoly[2], vPoly[1]);         
420                       
421          vNormal  = MathHelp::CrossProduct(vVector1, vVector2);               
422          pTempNormals[i] = vNormal;                                   
423          vNormal  = MathHelp::NormalizeVector(vNormal);                               
424
425          pNormals[i] = vNormal;
426        }
427
428      /* now calculating vertex normals */
429      CVector3 vSum = {0.0, 0.0, 0.0};
430      CVector3 vZero = vSum;
431      int shared=0;
432
433      for (int i = 0; i < pObject->numOfVerts; i++)                     
434        {
435          for (int j = 0; j < pObject->numOfFaces; j++) 
436            {                                                                                           
437              if (pObject->pFaces[j].vertIndex[0] == i || 
438                  pObject->pFaces[j].vertIndex[1] == i || 
439                  pObject->pFaces[j].vertIndex[2] == i)
440                {
441                  vSum = MathHelp::AddVector(vSum, pTempNormals[j]);
442                  shared++;                                                                                             }
443            }     
444          pObject->pNormals[i] = MathHelp::DivideVectorByScaler(vSum, float(-shared));
445          pObject->pNormals[i] = MathHelp::NormalizeVector(pObject->pNormals[i]);       
446
447          vSum = vZero;                                                                 
448          shared = 0;                                                                           
449        }
450      delete [] pTempNormals;
451      delete [] pNormals;
452    }
453}
454
455
456/**
457   \brief This function cleans up our allocated memory and closes the file
458*/
459void MD2Loader::cleanUp()
460{
461  fclose(this->pFile);                 
462       
463  if( this->pSkins) delete [] this->pSkins;             
464  if( this->pTexCoords) delete this->pTexCoords;
465  if( this->pTriangles) delete this->pTriangles;
466  if( this->pFrames) delete this->pFrames;
467}
468
469
470/********************************************************************************
471 *   MD2LOADER2                                                                 *
472 ********************************************************************************/
473
474MD2Model2::MD2Model2()
475{
476  this->pVertices = NULL;
477  this->pGLCommands = NULL;
478  this->pLightNormals = NULL; 
479
480  this->numFrames = 0;
481  this->numVertices = 0;
482  this->numGLCommands = 0;
483 
484  this->textureID = 0;
485  this->scaleFactor = 1.0f;
486
487  //this->setAnim(0);
488}
489
490
491MD2Model2::~MD2Model2()
492{
493  delete [] this->pVertices;
494  delete [] this->pGLCommands;
495  delete [] this->pLightNormals;
496}
497
498
499
500bool MD2Model2::loadModel(const char *fileName)
501{
502  FILE *pFile;                            //file stream
503  tMd2Header header;
504  char* buffer;                           //buffer for frame data
505  sFrame* frame;                          //temp frame
506  sVec3D *pVertex;
507  int* pNormals;
508
509  pFile = fopen(fileName, "rb");
510  if( unlikely(!pFile)) 
511    {
512      PRINTF(1)("Couldn't open the MD2 File for loading. Exiting.\n");
513      return false;
514    }
515  fread(&header, 1, sizeof(tMd2Header), pFile);
516  /* check for the header version: make sure its a md2 file :) */
517  if( unlikely(header.version != MD2_VERSION) && unlikely(header.ident != MD2_IDENT))
518    {
519      PRINTF(1)("Couldn't load file %s: invalid file format: stop loading\n", fileName);
520      return false;
521    }
522
523  /* got the data: map it to locals */
524  this->numFrames = header.numFrames;
525  this->numVertices = header.numVertices;
526  this->numGLCommands = header.numGlCommands;
527  /* allocate memory for the data storage */
528  this->pVertices = new sVec3D[this->numVertices * this->numFrames];
529  this->pGLCommands = new int[this->numGLCommands];
530  this->pLightNormals = new int[this->numVertices * this->numFrames];
531  buffer = new char[this->numFrames * header.frameSize];
532
533  /* read frame data from the file to a temp buffer */
534  fseek(pFile, header.offsetFrames, SEEK_SET);
535  fread(buffer, header.frameSize, this->numFrames, pFile);
536  /* read opengl commands */
537  fseek(pFile, header.offsetGlCommands, SEEK_SET);
538  fread(this->pGLCommands, sizeof(int), this->numGLCommands, pFile);
539
540  for(int i = 0; i < this->numFrames; ++i)
541    {
542      frame = (sFrame*)(buffer + header.frameSize * i); 
543      pVertex = this->pVertices + this->numVertices  * i;
544      pNormals = this->pLightNormals + this->numVertices * i;
545
546      for(int j = 0; j < this->numVertices; ++j)
547        {
548          /* SPEEDUP: *(pVerts + i + 0) = (*(frame->pVertices + i + 0)...  */
549          pVertex[i][0] = (frame->pVertices[i].v[0] * frame->scale[0]) + frame->translate[0];
550          pVertex[i][1] = (frame->pVertices[i].v[1] * frame->scale[1]) + frame->translate[1];
551          pVertex[i][2] = (frame->pVertices[i].v[2] * frame->scale[2]) + frame->translate[2];     
552
553          pNormals[i] = frame->pVertices[i].lightNormalIndex;
554        }
555    }
556
557  delete [] buffer;
558  fclose(pFile);
559}
560
561
562bool MD2Model2::loadSkin(const char* fileName)
563{
564  this->material = new Material("md2ModelTest");
565  this->material->setDiffuseMap(fileName);
566  this->material->setIllum(3);
567  this->material->setAmbient(1.0, 1.0, 1.0);
568}
569
570
571void MD2Model2::draw()
572{
573  glPushMatrix();
574  /* rotate because id software uses another orientation then the openGL default */
575  /* \todo: rotate the axis already when loading... easy :) */
576  glRotatef(-90.0, 1.0, 0.0, 0.0);
577  glRotatef(-90.0, 0.0, 0.0, 1.0);
578
579  this->renderFrame();
580
581  glPopMatrix();
582}
583
584
585/**
586   \brief initializes an array of vert with the current frame scaled vertices
587
588   we won't use the pVertices array directly, since its much easier and we need
589   saving of data anyway
590*/
591void MD2Model2::interpolate(sVec3D* verticesList)
592{
593  for(int i = 0; i < this->numFrames; ++i)
594    {
595      verticesList[i][0] = this->pVertices[i + (this->numFrames * this->animationState.currentFrame)][0] * this->scaleFactor;
596      verticesList[i][1] = this->pVertices[i + (this->numFrames * this->animationState.currentFrame)][1] * this->scaleFactor;
597      verticesList[i][2] = this->pVertices[i + (this->numFrames * this->animationState.currentFrame)][2] * this->scaleFactor;
598    }
599}
600
601
602/* hhmmm... id used a very different way to do lightning...*/
603void MD2Model2::processLighting()
604{
605}
606
607
608void MD2Model2::renderFrame()
609{
610  static sVec3D verticesList[MD2_MAX_VERTICES]; /* performance: created only once in a lifetime */
611  int* pCommands = this->pGLCommands;
612
613  /* some face culling stuff */
614  glPushAttrib(GL_POLYGON_BIT);
615  glFrontFace(GL_CW);
616  glEnable(GL_CULL_FACE);
617  glCullFace(GL_BACK);
618     
619  this->interpolate(verticesList);
620  this->material->select();
621
622  /* draw the triangles */
623  /* \todo: take int i out of while loop */
624  while( int i = *(pCommands++)) /* strange looking while loop for maximum performance */
625    {
626      if( i < 0)
627        {
628          glBegin(GL_TRIANGLE_FAN);
629          i = -i;
630        }
631      else
632        {
633          glBegin(GL_TRIANGLE_STRIP);
634        }
635
636      for(; i > 0; --i, pCommands += 3) /* down counting for loop, next 3 gl commands */
637        {
638          /* for quake2 lighting */
639          //float l = shadedots[this->pLightNormals[pCommands[2]]];
640          //glColor3f(l * lcolor[0], l * lcolor[1], l * lcolor[2]);
641
642          glTexCoord2f( ((float *)pCommands)[0], ((float *)pCommands)[1] );
643          //glNormal3fv(anorms[this->pLightNormals[2]]);
644          glVertex3fv(verticesList[pCommands[2]]);
645        }
646      glEnd();
647    }
648  glDisable(GL_CULL_FACE);
649  glPopAttrib();
650}
651
Note: See TracBrowser for help on using the repository browser.