Md3Model.cpp

Go to the documentation of this file.
00001 /* -*- c++ -*- */
00002 /////////////////////////////////////////////////////////////////////////////
00003 //
00004 // Md3Model.cpp -- Copyright (c) 2006-2007 David Henry
00005 // last modification: may. 7, 2007
00006 //
00007 // This code is licenced under the MIT license.
00008 //
00009 // This software is provided "as is" without express or implied
00010 // warranties. You may freely copy and compile this source into
00011 // applications you distribute provided that the copyright text
00012 // below is included in the resulting source code.
00013 //
00014 // Implementation of MD3 Model Classes.
00015 //
00016 /////////////////////////////////////////////////////////////////////////////
00017 
00018 #ifdef _WIN32
00019 #define WIN32_LEAN_AND_MEAN
00020 #include <windows.h>
00021 #endif
00022 
00023 #include <GL/gl.h>
00024 #include <GL/glu.h>
00025 #include <iostream>
00026 #include <cmath>
00027 
00028 using std::cout;
00029 using std::cerr;
00030 using std::endl;
00031 
00032 #include "Md3Model.h"
00033 #include "TextureManager.h"
00034 
00035 
00036 /////////////////////////////////////////////////////////////////////////////
00037 //
00038 // struct Md3Model::Md3QuaternionTag implementation.
00039 //
00040 /////////////////////////////////////////////////////////////////////////////
00041 
00042 // --------------------------------------------------------------------------
00043 // Md3Model::Md3QuaternionTag::Md3QuaternionTag
00044 //
00045 // Constructor.  Initialize the quaternion tag from the original tag
00046 // with 3x3 rotation matrix.
00047 // --------------------------------------------------------------------------
00048 
00049 Md3Model::Md3QuaternionTag::Md3QuaternionTag (const Md3Tag_t &tag)
00050   : name (tag.name)
00051 {
00052   // Copy the origin vector
00053   origin._x = tag.origin[0];
00054   origin._y = tag.origin[1];
00055   origin._z = tag.origin[2];
00056 
00057   // Create a 4x4 matrix from the 3x3 rotation matrix
00058   Matrix4x4f m;
00059   m._m11 = tag.axis[0][0]; m._m12 = tag.axis[0][1]; m._m13 = tag.axis[0][2];
00060   m._m21 = tag.axis[1][0]; m._m22 = tag.axis[1][1]; m._m23 = tag.axis[1][2];
00061   m._m31 = tag.axis[2][0]; m._m32 = tag.axis[2][1]; m._m33 = tag.axis[2][2];
00062 
00063   // Convert the matrix to quaternion
00064   orient.fromMatrix (m);
00065   orient.normalize ();
00066 }
00067 
00068 
00069 /////////////////////////////////////////////////////////////////////////////
00070 //
00071 // class NormalLookupTable implementation.
00072 //
00073 /////////////////////////////////////////////////////////////////////////////
00074 
00075 // --------------------------------------------------------------------------
00076 // NormalLookupTable::NormalLookupTable
00077 //
00078 // Constructor.  Build the normal lookup table.
00079 // --------------------------------------------------------------------------
00080 
00081 NormalLookupTable::NormalLookupTable ()
00082 {
00083   for (int i = 0; i < 256; ++i)
00084     {
00085       for (int j = 0; j < 256; ++j)
00086         {
00087           float lng = i * 2.0f * kPi / 255.0f;
00088           float lat = j * 2.0f * kPi / 255.0f;
00089 
00090           _normal[i][j][0] = std::cos (lat) * std::sin (lng);
00091           _normal[i][j][1] = std::sin (lat) * std::sin (lng);
00092           _normal[i][j][2] = std::cos (lng);
00093         }
00094     }
00095 }
00096 
00097 
00098 /////////////////////////////////////////////////////////////////////////////
00099 //
00100 // class Md3Mesh implementation.
00101 //
00102 /////////////////////////////////////////////////////////////////////////////
00103 
00104 // Precomputed normal vector array
00105 const NormalLookupTable Md3Mesh::_kAnorms;
00106 
00107 // Magic number (should be 860898377)
00108 const int Md3Mesh::_kMd3Ident = 'I' + ('D'<<8) + ('P'<<16) + ('3'<<24);
00109 
00110 // Vertex arrays
00111 vec3_t Md3Mesh::_kVertexArray[kMd3MaxTriangles * 3];
00112 vec3_t Md3Mesh::_kNormalArray[kMd3MaxTriangles * 3];
00113 
00114 
00115 // --------------------------------------------------------------------------
00116 // Md3Mesh::Md3Mesh
00117 //
00118 // Constructor.  Read a mesh from an ifstream.
00119 // --------------------------------------------------------------------------
00120 
00121 Md3Mesh::Md3Mesh (std::ifstream &ifs)
00122   : _tex (NULL)
00123 {
00124   // File must be successfully opened
00125   if (!ifs.is_open ())
00126     throw Md3Exception ("Stream not opened");
00127 
00128   // Get the current position in the stream
00129   long pos = ifs.tellg ();
00130 
00131   // Read header
00132   ifs.read (reinterpret_cast<char *>(&_header),
00133             sizeof (Md3MeshHeader_t));
00134 
00135   // Check if ident is valid
00136   if (_header.ident != _kMd3Ident)
00137     throw Md3Exception ("Bad mesh ident");
00138 
00139   // Memory allocation for model data
00140   _shaders.reserve (_header.num_shaders);
00141   _triangles.reserve (_header.num_triangles);
00142   _texCoords.reserve (_header.num_verts);
00143   _vertices.reserve (_header.num_verts * _header.num_frames);
00144   _indices.reserve (_header.num_triangles * 3);
00145 
00146   // Read shaders
00147   Md3Shader_t shader;
00148   ifs.seekg (pos + _header.offset_shaders, std::ios::beg);
00149   for (int i = 0; i < _header.num_shaders; ++i)
00150     {
00151       ifs.read (reinterpret_cast<char *>(&shader), sizeof (Md3Shader_t));
00152       _shaders.push_back (Md3ShaderPtr (new Md3Shader_t (shader)));
00153     }
00154 
00155   // Read triangles
00156   Md3Triangle_t tri;
00157   ifs.seekg (pos + _header.offset_triangles, std::ios::beg);
00158   for (int i = 0; i < _header.num_triangles; ++i)
00159     {
00160       ifs.read (reinterpret_cast<char *>(&tri), sizeof (Md3Triangle_t));
00161       _triangles.push_back (Md3TrianglePtr (new Md3Triangle_t (tri)));
00162     }
00163 
00164   // Read texture coords.
00165   Md3TexCoord_t st;
00166   ifs.seekg (pos + _header.offset_st, std::ios::beg);
00167   for (int i = 0; i < _header.num_verts; ++i)
00168     {
00169       ifs.read (reinterpret_cast<char *>(&st), sizeof (Md3TexCoord_t));
00170       _texCoords.push_back (st);
00171     }
00172 
00173   // Read vertices
00174   // Read texture coords.
00175   Md3Vertex_t vert;
00176   ifs.seekg (pos + _header.offset_xyznormal, std::ios::beg);
00177   for (int i = 0; i < _header.num_verts * _header.num_frames; ++i)
00178     {
00179       ifs.read (reinterpret_cast<char *>(&vert), sizeof (Md3Vertex_t));
00180       _vertices.push_back (Md3VertexPtr (new Md3Vertex_t (vert)));
00181     }
00182 
00183   // Jump to end of mesh into the stream
00184   ifs.seekg (pos + _header.offset_end, std::ios::beg);
00185 
00186   // Initialize vertex index array
00187   for (int i = 0; i < _header.num_triangles; ++i)
00188     {
00189       // Triangles are stored in clockwise order, reverse them
00190       // so that front faces are in CCW (OpenGL default)
00191       for (int j = 2; j >= 0; --j)
00192         _indices.push_back (_triangles[i]->index[j]);
00193     }
00194 }
00195 
00196 
00197 // --------------------------------------------------------------------------
00198 // Md3Mesh::~Md3Mesh
00199 //
00200 // Destructor.  Free allocated memory for the mesh.
00201 // --------------------------------------------------------------------------
00202 
00203 Md3Mesh::~Md3Mesh ()
00204 {
00205 }
00206 
00207 
00208 // --------------------------------------------------------------------------
00209 // Md3Mesh::loadShaders
00210 //
00211 // Load mesh's texture from shader #index.
00212 // --------------------------------------------------------------------------
00213 
00214 void
00215 Md3Mesh::loadShader (int index)
00216 {
00217   if (index < 0 || index >= _header.num_shaders)
00218     return;
00219 
00220   const string filename (_shaders[index]->name);
00221   if (!filename.empty ())
00222     {
00223       // Get texture manager
00224       Texture2DManager *texMgr = Texture2DManager::getInstance ();
00225 
00226       // Load the texture
00227       setTexture (texMgr->load (filename));
00228     }
00229 }
00230 
00231 
00232 // --------------------------------------------------------------------------
00233 // Md3Mesh::bindTexture
00234 //
00235 // Bind the active texture unit to mesh's current texture.
00236 // --------------------------------------------------------------------------
00237 
00238 void
00239 Md3Mesh::bindTexture () const
00240 {
00241   if (!_tex)
00242     {
00243       // Disable texture and return
00244       glBindTexture (GL_TEXTURE_2D, 0);
00245       return;
00246     }
00247 
00248   _tex->bind ();
00249 
00250   // Quake doesn't use the OpenGL standard coordinate system
00251   // for images, i.e. image data "starts" at the upper-left
00252   // corner instead of the lower-left corner.
00253 
00254   // We must reverse the t component if the texture
00255   // has been built with OpenGL's coord. system
00256   if (_tex->stdCoordSystem ())
00257     {
00258       glMatrixMode (GL_TEXTURE);
00259       glLoadIdentity ();
00260       glScalef (1.0f, -1.0f, 1.0f);
00261       glTranslatef (0.0f, -1.0f, 0.0f);
00262       glMatrixMode (GL_MODELVIEW);
00263     }
00264 }
00265 
00266 
00267 // --------------------------------------------------------------------------
00268 // Md3Mesh::setupVertexArrays
00269 //
00270 // Compute final mesh's vertices from frames frameA and frameB with
00271 // linear interpolation.  The resultant vertices are stored in the
00272 // vertex array.
00273 // NOTE: there is no test if frameA and frameB are valid!
00274 // --------------------------------------------------------------------------
00275 
00276 void
00277 Md3Mesh::setupVertexArrays (int frameA, int frameB, float interp, float scale)
00278 {
00279   int frameOffsetA = frameA * _header.num_verts;
00280   int frameOffsetB = frameB * _header.num_verts;
00281 
00282   float s = scale * kMd3XYZScale;
00283 
00284   for (int i = 0; i < _header.num_verts; ++i)
00285     {
00286       const Md3Vertex_t *pVertA = _vertices[frameOffsetA + i];
00287       const Md3Vertex_t *pVertB = _vertices[frameOffsetB + i];
00288 
00289       // Compute interpolated normal vector
00290       const int &uA = pVertA->normal[0];
00291       const int &vA = pVertA->normal[1];
00292 
00293       const int &uB = pVertB->normal[0];
00294       const int &vB = pVertB->normal[1];
00295 
00296       const float *normA = _kAnorms[uA][vA];
00297       const float *normB = _kAnorms[uB][vB];
00298 
00299       _kNormalArray[i][0] = normA[0] + interp * (normB[0] - normA[0]);
00300       _kNormalArray[i][1] = normA[1] + interp * (normB[1] - normA[1]);
00301       _kNormalArray[i][2] = normA[2] + interp * (normB[2] - normA[2]);
00302 
00303       // Compute interpolated vertex position
00304       const short *vertA = pVertA->v;
00305       const short *vertB = pVertB->v;
00306 
00307       _kVertexArray[i][0] = (vertA[0] + interp * (vertB[0] - vertA[0])) * s;
00308       _kVertexArray[i][1] = (vertA[1] + interp * (vertB[1] - vertA[1])) * s;
00309       _kVertexArray[i][2] = (vertA[2] + interp * (vertB[2] - vertA[2])) * s;
00310     }
00311 }
00312 
00313 
00314 // --------------------------------------------------------------------------
00315 // Md3Mesh::renderFrameImmediate
00316 //
00317 // Draw the mesh at a specified frame, using immediate mode.
00318 // NOTE: we don't check here if frame is a valid index!
00319 // --------------------------------------------------------------------------
00320 
00321 void
00322 Md3Mesh::renderFrameImmediate (int frame, float scale) const
00323 {
00324   int frameOffset = frame * _header.num_verts;
00325 
00326   // Scale and uncompress vertex in one pass
00327   float scale_and_uncompress = scale * kMd3XYZScale;
00328 
00329   glPushAttrib (GL_POLYGON_BIT);
00330   glFrontFace (GL_CW);
00331 
00332   // Bind to mesh's texture
00333   bindTexture ();
00334 
00335   glBegin (GL_TRIANGLES);
00336     // Draw each triangle
00337     for (int i = 0; i < _header.num_triangles; ++i)
00338       {
00339         // Draw each vertex of this triangle
00340         for (int j = 0; j < 3; ++j)
00341           {
00342             const int &vertIndex = _triangles[i]->index[j];
00343             const Md3Vertex_t *pVert = _vertices[frameOffset + vertIndex];
00344             const Md3TexCoord_t *pTexCoords = &_texCoords[vertIndex];
00345 
00346             // Send texture coords. to OpenGL
00347             glTexCoord2f (pTexCoords->s, pTexCoords->t);
00348 
00349             // Send normal vector to OpenGL
00350             const unsigned char &un = pVert->normal[0];
00351             const unsigned char &vn = pVert->normal[1];
00352 
00353             glNormal3fv (_kAnorms[un][vn]);
00354 
00355             // Uncompress vertex position and scale it
00356             vec3_t v;
00357 
00358             v[0] = pVert->v[0] * scale_and_uncompress;
00359             v[1] = pVert->v[1] * scale_and_uncompress;
00360             v[2] = pVert->v[2] * scale_and_uncompress;
00361 
00362             glVertex3fv (v);
00363           }
00364       }
00365   glEnd ();
00366 
00367   // GL_POLYGON_BIT
00368   glPopAttrib ();
00369 }
00370 
00371 
00372 // --------------------------------------------------------------------------
00373 // Md3Mesh::renderWithVertexArrays
00374 //
00375 // Draw the mesh using vertex arrays.  Vertex arrays must be previously
00376 // computed by a call to setupVertexArrays().
00377 // --------------------------------------------------------------------------
00378 
00379 void
00380 Md3Mesh::renderWithVertexArrays () const
00381 {
00382   glEnableClientState (GL_VERTEX_ARRAY);
00383   glEnableClientState (GL_NORMAL_ARRAY);
00384   glEnableClientState (GL_TEXTURE_COORD_ARRAY);
00385 
00386   // Send arrays to OpenGL
00387   glVertexPointer (3, GL_FLOAT, 0, _kVertexArray);
00388   glNormalPointer (GL_FLOAT, 0, _kNormalArray);
00389   glTexCoordPointer (2, GL_FLOAT, 0, &_texCoords.front ());
00390 
00391   // Bind to mesh's texture
00392   bindTexture ();
00393 
00394   // Draw triangles
00395   glDrawElements (GL_TRIANGLES, _header.num_triangles * 3,
00396                   GL_UNSIGNED_INT, &_indices.front ());
00397 
00398   glDisableClientState (GL_VERTEX_ARRAY);
00399   glDisableClientState (GL_NORMAL_ARRAY);
00400   glDisableClientState (GL_TEXTURE_COORD_ARRAY);
00401 }
00402 
00403 
00404 /////////////////////////////////////////////////////////////////////////////
00405 //
00406 // class Md3Model implementation.
00407 //
00408 /////////////////////////////////////////////////////////////////////////////
00409 
00410 // Magic number (should be 860898377)
00411 const int Md3Model::_kMd3Ident = 'I' + ('D'<<8) + ('P'<<16) + ('3'<<24);
00412 
00413 // MD3 format version
00414 const int Md3Model::_kMd3Version = 15;
00415 
00416 
00417 // --------------------------------------------------------------------------
00418 // Md3Model::Md3Model
00419 //
00420 // Constructor.  Load a model from file.
00421 // --------------------------------------------------------------------------
00422 
00423 Md3Model::Md3Model (const string &filename)
00424   : _currFrame (0), _nextFrame (0), _interp (0.0f),
00425     _scale (1.0f), _name (filename)
00426 {
00427   // Open the file
00428   std::ifstream ifs (filename.c_str(), std::ios::in | std::ios::binary);
00429 
00430   if (ifs.fail ())
00431     throw Md3Exception ("Couldn't open file", filename);
00432 
00433   // Read header
00434   ifs.read (reinterpret_cast<char *>(&_header),
00435             sizeof (Md3Header_t));
00436 
00437   // Check if ident and version are valid
00438   if (_header.ident != _kMd3Ident)
00439     throw Md3Exception ("Bad file ident", filename);
00440 
00441   if (_header.version != _kMd3Version)
00442     throw Md3Exception ("Bad file version", filename);
00443 
00444   // Memory allocation for model data
00445   _meshes.reserve (_header.num_meshes);
00446   _qtags.reserve (_header.num_tags * _header.num_frames);
00447   _links.reserve (_header.num_tags);
00448 
00449   // Read frames.
00450   Md3Frame_t frame;
00451   ifs.seekg (_header.offset_frames, std::ios::beg);
00452   for (int i = 0; i < _header.num_frames; ++i)
00453     {
00454       ifs.read (reinterpret_cast<char *>(&frame), sizeof (Md3Frame_t));
00455       _frames.push_back (Md3FramePtr (new Md3Frame_t (frame)));
00456     }
00457 
00458   // Read tags
00459   Md3Tag_t tag;
00460   ifs.seekg (_header.offset_tag, std::ios::beg);
00461   for (int i = 0; i < _header.num_tags * _header.num_frames; ++i)
00462     {
00463       ifs.read (reinterpret_cast<char *>(&tag), sizeof (Md3Tag_t));
00464       _qtags.push_back (Md3TagPtr (new Md3QuaternionTag (tag)));
00465     }
00466 
00467   // Read meshes
00468   ifs.seekg (_header.offset_meshes, std::ios::beg);
00469   for (int i = 0; i < _header.num_meshes; ++i)
00470     _meshes.push_back (Md3MeshPtr (new Md3Mesh (ifs)));
00471 
00472   // We finished reading, close file
00473   ifs.close();
00474 
00475   // Initialize links to NULL pointers
00476   for (int i = 0; i < _header.num_tags; ++i)
00477     _links.push_back (NULL);
00478 }
00479 
00480 
00481 // --------------------------------------------------------------------------
00482 // Md3Model::~Md3Model
00483 //
00484 // Destructor.  Free allocated memory for the model.  Thanks to
00485 // boost::shared_ptr, we have nothing to do ;)
00486 // --------------------------------------------------------------------------
00487 
00488 Md3Model::~Md3Model ()
00489 {
00490 }
00491 
00492 
00493 // --------------------------------------------------------------------------
00494 // Md3Model::loadShaders
00495 //
00496 // Load textures for each mesh using meshes' shader string number #0.
00497 // --------------------------------------------------------------------------
00498 
00499 void
00500 Md3Model::loadShaders ()
00501 {
00502   for (int i = 0; i < _header.num_meshes; ++i)
00503     _meshes[i]->loadShader (0);
00504 }
00505 
00506 
00507 // --------------------------------------------------------------------------
00508 // Md3Model::draw
00509 //
00510 // Draw the model and linked models with frame interpolation between
00511 // current and next frames.
00512 // --------------------------------------------------------------------------
00513 
00514 void
00515 Md3Model::draw () const
00516 {
00517   Matrix4x4f m;
00518 
00519   // Draw the model
00520   renderFrameItpWithVertexArrays (_currFrame, _nextFrame, _interp);
00521 
00522   // Draw models linked to this one
00523   for (int i = 0; i < _header.num_tags; ++i)
00524     {
00525       if (!_links[i])
00526         continue;
00527 
00528       const Quaternionf &qA = _qtags[_currFrame * _header.num_tags + i]->orient;
00529       const Quaternionf &qB = _qtags[_nextFrame * _header.num_tags + i]->orient;
00530 
00531       m.fromQuaternion (Slerp (qA, qB, _interp));
00532 
00533       const Vector3f &currPos = _qtags[_currFrame * _header.num_tags + i]->origin;
00534       const Vector3f &nextPos = _qtags[_nextFrame * _header.num_tags + i]->origin;
00535 
00536       m.setTranslation ((currPos + _interp * (nextPos - currPos)) * _scale);
00537 
00538       glPushMatrix ();
00539         glMultMatrixf (m);
00540         _links[i]->draw ();
00541       glPopMatrix ();
00542     }
00543 }
00544 
00545 
00546 // --------------------------------------------------------------------------
00547 // Md3Model::renderFrameImmediate
00548 //
00549 // Draw each mesh of the model at a specified frame, using immediate mode.
00550 // --------------------------------------------------------------------------
00551 
00552 void
00553 Md3Model::renderFrameImmediate (int frame) const
00554 {
00555   // Check if the frame index is valid
00556   if ((frame < 0) || (frame >= _header.num_frames))
00557     return;
00558 
00559   for (int i = 0; i < _header.num_meshes; ++i)
00560     _meshes[i]->renderFrameImmediate (frame, _scale);
00561 }
00562 
00563 
00564 // --------------------------------------------------------------------------
00565 // Md3Model::renderFrameImmediate
00566 //
00567 // Draw each mesh of the model with linear interpolation between
00568 // frameA and frameB, using vertex arrays.
00569 // --------------------------------------------------------------------------
00570 
00571 void
00572 Md3Model::renderFrameItpWithVertexArrays (int frameA, int frameB,
00573                                           float interp) const
00574 {
00575   int maxFrame = _header.num_frames - 1;
00576 
00577   // Check if frames are valid
00578   if ((frameA < 0) || (frameB < 0))
00579     return;
00580 
00581   if ((frameA > maxFrame) || (frameB > maxFrame))
00582     return;
00583 
00584   for (int i = 0; i < _header.num_meshes; ++i)
00585     {
00586       // weird issue: original code called non-const fn from const
00587       // we cast to avoid
00588       const Md3Mesh * cmesh = _meshes[i];
00589       Md3Mesh * mesh = (Md3Mesh *) cmesh;
00590       mesh->setupVertexArrays (frameA, frameB, interp, _scale);
00591       mesh->renderWithVertexArrays ();
00592     }
00593 }
00594 
00595 
00596 // --------------------------------------------------------------------------
00597 // Md3Model::link
00598 //
00599 // Link a model to a tag.
00600 // --------------------------------------------------------------------------
00601 
00602 bool
00603 Md3Model::link (const string &name, const Md3Model *model)
00604 {
00605   for (int i = 0; i < _header.num_tags; ++i)
00606     {
00607       if (name == _qtags[i]->name)
00608         {
00609           _links[i] = model;
00610           return true;
00611         }
00612     }
00613 
00614   return false;
00615 }
00616 
00617 
00618 // --------------------------------------------------------------------------
00619 // Md3Model::unlink
00620 //
00621 // Unlink a model given the tag to which it is associated.
00622 // --------------------------------------------------------------------------
00623 
00624 bool
00625 Md3Model::unlink (const string &name)
00626 {
00627   for (int i = 0; i < _header.num_tags; ++i)
00628     {
00629       if (name == _qtags[i]->name)
00630         {
00631           _links[i] = NULL;
00632           return true;
00633         }
00634     }
00635 
00636   return false;
00637 }
00638 
00639 // --------------------------------------------------------------------------
00640 // Md3Model::setTexture
00641 //
00642 // Set the texture to the specified mesh.
00643 // --------------------------------------------------------------------------
00644 
00645 void
00646 Md3Model::setTexture (const string &mesh, const Texture2D *tex)
00647 {
00648   for (int i = 0; i < _header.num_meshes; ++i)
00649     {
00650       if (_meshes[i]->name () == mesh)
00651         _meshes[i]->setTexture (tex);
00652     }
00653 }
00654 
00655 
00656 // --------------------------------------------------------------------------
00657 // Md3Model::setupAnimation
00658 //
00659 // Set the current frame, next frame and interpolation percent for
00660 // the next "animated" rendering of the model.
00661 // --------------------------------------------------------------------------
00662 
00663 void
00664 Md3Model::setupAnimation (int currFrame, int nextFrame, float interp)
00665 {
00666   _currFrame = currFrame;
00667   _nextFrame = nextFrame;
00668   _interp = interp;
00669 
00670   // Ensure that current frame and next frame aren't out of bounds
00671   if (_currFrame >= _header.num_frames)
00672     _currFrame = _header.num_frames - 1;
00673 
00674   if (_nextFrame >= _header.num_frames)
00675     _nextFrame = _header.num_frames - 1;
00676 }