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