Md3Player.cpp

Go to the documentation of this file.
00001 /* -*- c++ -*- */
00002 /////////////////////////////////////////////////////////////////////////////
00003 //
00004 // Md3Player.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 Player 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 <cctype>
00027 #include <sstream>
00028 #include <sys/types.h>
00029 
00030 using std::cout;
00031 using std::cerr;
00032 using std::endl;
00033 
00034 #include "Md3Player.h"
00035 #include "TextureManager.h"
00036 
00037 #include "util/file.h"          // for platform-independent dirent
00038 
00039 #ifdef _WIN32
00040 const char kSeparator = '\\';
00041 #else
00042 const char kSeparator = '/';
00043 #endif
00044 
00045 
00046 /////////////////////////////////////////////////////////////////////////////
00047 //
00048 // class Md3PlayerSkin implementation.
00049 //
00050 /////////////////////////////////////////////////////////////////////////////
00051 
00052 // --------------------------------------------------------------------------
00053 // Md3PlayerSkin::Md3PlayerSkin
00054 //
00055 // Constructor.  Load a skin given a path and its name.
00056 // For each portion of the player, load the adequate .skin file.
00057 // --------------------------------------------------------------------------
00058 
00059 Md3PlayerSkin::Md3PlayerSkin (const string &path, const string &name)
00060   : _path (path), _name (name)
00061 {
00062   // Load lower part's textures
00063   loadSkinFile (path + "lower_" + name + ".skin", _lowerTextures);
00064 
00065   // Load upper part's textures
00066   loadSkinFile (path + "upper_" + name + ".skin", _upperTextures);
00067 
00068   // Load head's textures
00069   loadSkinFile (path + "head_" + name + ".skin", _headTextures);
00070 }
00071 
00072 
00073 // --------------------------------------------------------------------------
00074 // Md3PlayerSkin::~Md3PlayerSkin
00075 //
00076 // Destructor.  Free allocated memory for the skin.
00077 // boost:shared_ptr should do it for us.
00078 // --------------------------------------------------------------------------
00079 
00080 Md3PlayerSkin::~Md3PlayerSkin ()
00081 {
00082 }
00083 
00084 
00085 // --------------------------------------------------------------------------
00086 // Md3PlayerSkin::loadSkinFile
00087 //
00088 // Constructor.  Load a skin file and initialize a TexMap object given
00089 // by reference.  The TexMap will contain a texture associated to each
00090 // mesh found in the skin file.
00091 // --------------------------------------------------------------------------
00092 
00093 void
00094 Md3PlayerSkin::loadSkinFile (const string &filename, TexMap &tmap)
00095 {
00096   // Open the skin file
00097   std::ifstream ifs (filename.c_str(), std::ios::in | std::ios::binary);
00098 
00099   if (ifs.fail ()) {
00100     fprintf(stderr, "Bad file: %s\n", filename.c_str());
00101     throw Md3Exception ("Couldn't open skin file", filename);
00102   }
00103 
00104   // Get texture manager
00105   Texture2DManager *texMgr = Texture2DManager::getInstance ();
00106 
00107   // Read the file
00108   while (!ifs.eof ())
00109     {
00110       string meshname, texname, buffer;
00111 
00112       // Read mesh name and texture name
00113       std::getline (ifs, meshname, ',');
00114       ifs >> texname;
00115 
00116       // If this is a valid mesh name, load the texture
00117       if (!meshname.empty () && !texname.empty ()
00118           && meshname.compare (0, 4, "tag_") != 0)
00119         {
00120           // Replace the path from the .skin file with the path
00121           // where the player's .skin file is
00122           long start = texname.find_last_of ('/') + 1;
00123           long end = texname.length () - start;
00124           texname.assign (texname, start, end);
00125           texname = _path + texname;
00126 
00127           // Load the texture
00128           Texture2D *tex = texMgr->load (texname);
00129 
00130           tmap.insert (TexMap::value_type (meshname, tex));
00131         }
00132 
00133       // Eat up rest of the line
00134       std::getline (ifs, buffer);
00135     }
00136 
00137   ifs.close ();
00138 }
00139 
00140 
00141 // --------------------------------------------------------------------------
00142 // Md3PlayerSkin::setModelTextures
00143 //
00144 // Setup textures for the specified model from the given Texture Map.
00145 // --------------------------------------------------------------------------
00146 
00147 void
00148 Md3PlayerSkin::setModelTextures (Md3Model *model, const TexMap &tmap) const
00149 {
00150   for (TexMap::const_iterator itor = tmap.begin ();
00151        itor != tmap.end (); ++itor)
00152     model->setTexture (itor->first, itor->second);
00153 }
00154 
00155 
00156 /////////////////////////////////////////////////////////////////////////////
00157 //
00158 // class Md3Weapon implementation.
00159 //
00160 /////////////////////////////////////////////////////////////////////////////
00161 
00162 // --------------------------------------------------------------------------
00163 // Md3Weapon::Md3Weapon
00164 //
00165 // Constructor.  Load a weapon given a path and the level of details.
00166 // --------------------------------------------------------------------------
00167 
00168 Md3Weapon::Md3Weapon (const string &path, Md3PlayerLOD lod)
00169   : _path (path), _scale (1.0f), _lod (lod)
00170 {
00171   string suffix, modelpath;
00172 
00173   // Add trailing slash to path name if not present
00174   if (_path.find_last_of (kSeparator) < _path.length () - 1)
00175     _path += kSeparator;
00176 
00177   // Extract name from the path
00178   _name.assign (_path, 0, _path.find_last_of (kSeparator));
00179   _name.assign (_name, _name.find_last_of (kSeparator) + 1, _name.length ());
00180 
00181   // Get model file suffix from LOD
00182   switch (lod)
00183     {
00184     case kLodLow:
00185       suffix = "_2";
00186       break;
00187 
00188     case kLodMedium:
00189       suffix = "_1";
00190       break;
00191 
00192     case kLodHigh:
00193       break;
00194     }
00195 
00196   // Load models
00197   modelpath = _path + _name + suffix + ".md3";
00198   _weapon = Md3ModelPtr (new Md3Model (modelpath));
00199   _weapon->loadShaders ();
00200 
00201   modelpath = _path + _name + suffix + "_barrel.md3";
00202   std::ifstream ftest (modelpath.c_str (), std::ios::in);
00203   if (!ftest.fail ())
00204     {
00205       // The barrel model exists, load it
00206       ftest.close ();
00207 
00208       _barrel = Md3ModelPtr (new Md3Model (modelpath));
00209       _barrel->loadShaders ();
00210 
00211       // Create links between weapon and barrel
00212       _weapon->link ("tag_barrel", _barrel);
00213     }
00214 }
00215 
00216 
00217 // --------------------------------------------------------------------------
00218 // Md3Weapon::~Md3Weapon
00219 //
00220 // Destructor.
00221 // --------------------------------------------------------------------------
00222 
00223 Md3Weapon::~Md3Weapon ()
00224 {
00225 }
00226 
00227 
00228 // --------------------------------------------------------------------------
00229 // Md3Weapon::draw
00230 //
00231 // Draw the weapon model.  Don't call this function if you want to
00232 // draw the weapon attached to a player: the player will draw it itself.
00233 // --------------------------------------------------------------------------
00234 
00235 void
00236 Md3Weapon::draw () const
00237 {
00238   // Set scale parameter
00239   scaleModels ();
00240 
00241   // Draw the models
00242   glPushMatrix ();
00243     glRotatef (-90.0, 1.0, 0.0, 0.0);
00244     glRotatef (-90.0, 0.0, 0.0, 1.0);
00245 
00246     _weapon->draw ();
00247   glPopMatrix ();
00248 }
00249 
00250 
00251 // --------------------------------------------------------------------------
00252 // Md3Weapon::scaleModels
00253 //
00254 // Set the current scale factor to weapon's models (call this before
00255 // rendering).
00256 // --------------------------------------------------------------------------
00257 
00258 void
00259 Md3Weapon::scaleModels () const
00260 {
00261   // ??? See this a lot with this code: non-const methods called from
00262   // const...  I think boost::shared_ptr<> has a bug to allow this...
00263   // Sadly, the smart_ptr<T> class is somewhat strict about const-ness,
00264   //    so we have to cast around these cases in this code
00265   Md3Weapon * pThis = (Md3Weapon *) this;
00266 
00267   pThis->_weapon->setScale (_scale);
00268 
00269   if (_barrel)
00270     pThis->_barrel->setScale (_scale);
00271 }
00272 
00273 
00274 // --------------------------------------------------------------------------
00275 // Md3Weapon::linkToModel
00276 //
00277 // Link weapon model to the given model at "tag_weapon".  The target
00278 // model should be player's upper model.
00279 // --------------------------------------------------------------------------
00280 
00281 void
00282 Md3Weapon::linkToModel (Md3Model *model)
00283 {
00284   if (model)
00285     model->link ("tag_weapon", _weapon);
00286 }
00287 
00288 
00289 /////////////////////////////////////////////////////////////////////////////
00290 //
00291 // struct Md3Player::Md3AnimState implementation.
00292 //
00293 /////////////////////////////////////////////////////////////////////////////
00294 
00295 // --------------------------------------------------------------------------
00296 // Md3Player::Md3AnimState::Md3AnimState
00297 //
00298 // Constructor.
00299 // --------------------------------------------------------------------------
00300 
00301 Md3Player::Md3AnimState::Md3AnimState ()
00302   : anim (NULL), curr_time (0.0f), old_time (0.0f),
00303     curr_frame (0), next_frame (0), interp (0.0f)
00304 {
00305 }
00306 
00307 
00308 // --------------------------------------------------------------------------
00309 // Md3Player::Md3AnimState::setup
00310 //
00311 // Initialize member variables given a player animation.
00312 // --------------------------------------------------------------------------
00313 
00314 void
00315 Md3Player::Md3AnimState::setup (Md3PlayerAnim_t *a)
00316 {
00317   // short-circuit: do nothing if we're already using this animation
00318   if (anim == a)
00319           return;
00320 
00321   // okay, animation is changing: reset
00322   anim = a;
00323   curr_frame = a->first;
00324   next_frame = a->first;
00325   interp = 0.0f;
00326 }
00327 
00328 
00329 // --------------------------------------------------------------------------
00330 // Md3Player::Md3AnimState::update
00331 //
00332 // Update current frame, next frame and interpolation percent given a
00333 // delta time.
00334 // --------------------------------------------------------------------------
00335 
00336 void
00337 Md3Player::Md3AnimState::update (float dt)
00338 {
00339   curr_time += dt;
00340 
00341   if ((curr_time - old_time) > (1.0 / anim->fps))
00342     {
00343       curr_frame = next_frame;
00344       next_frame++;
00345 
00346       if (next_frame > (anim->first + anim->num - 1))
00347         next_frame = anim->first;
00348 
00349       old_time = curr_time;
00350     }
00351 
00352   interp = anim->fps * (curr_time - old_time);
00353 }
00354 
00355 
00356 /////////////////////////////////////////////////////////////////////////////
00357 //
00358 // class Md3Player implementation.
00359 //
00360 /////////////////////////////////////////////////////////////////////////////
00361 
00362 // --------------------------------------------------------------------------
00363 // Md3Player::Md3Player
00364 //
00365 // Constructor.  Load a player given a path.  Load player's models,
00366 // animations and skins.
00367 // --------------------------------------------------------------------------
00368 
00369 Md3Player::Md3Player (const string &path, Md3PlayerLOD lod)
00370   : _weapon (NULL), _path (path), _scale (1.0f), _lod (lod)
00371 {
00372   // Add trailing slash to path name if not present
00373   if (_path.find_last_of (kSeparator) < _path.length () - 1)
00374     _path += kSeparator;
00375 
00376   // Extract name from the path
00377   _name.assign (_path, 0, _path.find_last_of (kSeparator));
00378   _name.assign (_name, _name.find_last_of (kSeparator) + 1, _name.length ());
00379 
00380   // Load models
00381   loadModels (_path);
00382 
00383   // Load animations
00384   loadAnimations (_path);
00385 
00386   // Load skins
00387   loadSkins (_path);
00388 }
00389 
00390 
00391 // --------------------------------------------------------------------------
00392 // Md3Player::~Md3Player
00393 //
00394 // Destructor.  Free allocated memory for the MD3 player.
00395 // --------------------------------------------------------------------------
00396 
00397 Md3Player::~Md3Player ()
00398 {
00399 }
00400 
00401 
00402 // --------------------------------------------------------------------------
00403 // Md3Player::draw
00404 //
00405 // Draw player's animated models.
00406 // --------------------------------------------------------------------------
00407 
00408 void
00409 Md3Player::draw () const
00410 {
00411   // sigh...  somehow original code was able to call non-const methods from
00412   //    const methods.  probably a bug in boost::shared_ptr<T>
00413   // we cast to avoid problems, which is ugly...  draw() shouldn't be const,
00414   //    but that is too intrusive to change now
00415   Md3Player * pThis = (Md3Player *) this;
00416 
00417   // Set scale parameter
00418   pThis->_lower->setScale (_scale);
00419   pThis->_upper->setScale (_scale);
00420   pThis->_head->setScale (_scale);
00421 
00422   if (_weapon)
00423     pThis->_weapon->scaleModels ();
00424 
00425   // Set current skin's textures
00426   if (_currentSkin)
00427     {
00428       pThis->_currentSkin->setLowerTextures (pThis->_lower);
00429       pThis->_currentSkin->setUpperTextures (pThis->_upper);
00430       pThis->_currentSkin->setHeadTextures (pThis->_head);
00431     }
00432 
00433   // Set animation parameters
00434   const Md3AnimState &low = _lowerAnim;
00435   const Md3AnimState &upp = _upperAnim;
00436 
00437   pThis->_lower->setupAnimation (low.curr_frame, low.next_frame, low.interp);
00438   pThis->_upper->setupAnimation (upp.curr_frame, upp.next_frame, upp.interp);
00439 
00440   // Draw the models
00441   glPushMatrix ();
00442     glRotatef (-90.0, 1.0, 0.0, 0.0);
00443     glRotatef (-90.0, 0.0, 0.0, 1.0);
00444 
00445     _lower->draw ();
00446   glPopMatrix ();
00447 }
00448 
00449 
00450 // --------------------------------------------------------------------------
00451 // Md3Player::renderFrame
00452 //
00453 // Draw player's models at a given frame.
00454 // --------------------------------------------------------------------------
00455 
00456 void
00457 Md3Player::renderFrame (int upperFrame, int lowerFrame) const
00458 {
00459   // again, cast to avoid const problems...  these methods should not be const
00460   Md3Player * pThis = (Md3Player *) this;
00461 
00462   // Set scale parameter
00463   pThis->_lower->setScale (_scale);
00464   pThis->_upper->setScale (_scale);
00465   pThis->_head->setScale (_scale);
00466 
00467   if (_weapon)
00468     pThis->_weapon->scaleModels ();
00469 
00470   // Set current skin's textures
00471   if (_currentSkin)
00472     {
00473       pThis->_currentSkin->setLowerTextures (pThis->_lower);
00474       pThis->_currentSkin->setUpperTextures (pThis->_upper);
00475       pThis->_currentSkin->setHeadTextures (pThis->_head);
00476     }
00477 
00478   // Set animation parameters
00479   pThis->_lower->setupAnimation (lowerFrame, lowerFrame, 0.0f);
00480   pThis->_upper->setupAnimation (upperFrame, upperFrame, 0.0f);
00481 
00482   // Draw the models
00483   glPushMatrix ();
00484     glRotatef (-90.0, 1.0, 0.0, 0.0);
00485     glRotatef (-90.0, 0.0, 0.0, 1.0);
00486 
00487     _lower->draw ();
00488   glPopMatrix ();
00489 }
00490 
00491 
00492 // --------------------------------------------------------------------------
00493 // Md3Player::animate
00494 //
00495 // Animate player's models.
00496 // --------------------------------------------------------------------------
00497 
00498 void
00499 Md3Player::animate (float dt)
00500 {
00501   _lowerAnim.update (dt);
00502   _upperAnim.update (dt);
00503 }
00504 
00505 
00506 // --------------------------------------------------------------------------
00507 // Md3Player::setAnimation
00508 //
00509 // Set player's current animation.
00510 // --------------------------------------------------------------------------
00511 
00512 void
00513 Md3Player::setAnimation (Md3PlayerAnimType type)
00514 {
00515   if ((type >= kBothDeath1) && (type <= kBothDead3))
00516     {
00517       _lowerAnim.setup (&_anims[type]);
00518       _upperAnim.setup (&_anims[type]);
00519     }
00520   else if ((type >= kTorsoGesture) && (type <= kTorsoStand2))
00521     {
00522       _upperAnim.setup (&_anims[type]);
00523     }
00524   else if ((type >= kLegsWalkCr) && (type <= kLegsTurn))
00525     {
00526       _lowerAnim.setup (&_anims[type]);
00527     }
00528 }
00529 
00530 
00531 // --------------------------------------------------------------------------
00532 // Md3Player::setSkin
00533 //
00534 // Set player's current skin.  If the skin does not exist, current
00535 // skin is set to NULL.
00536 // --------------------------------------------------------------------------
00537 
00538 void
00539 Md3Player::setSkin (const string &name)
00540 {
00541   SkinMap::iterator itor = _skins.find (name);
00542   if (itor != _skins.end ())
00543     {
00544       _currentSkin = itor->second;
00545       _currentSkinName = itor->first;
00546     }
00547   else
00548     {
00549       _currentSkin = NULL;
00550     }
00551 }
00552 
00553 
00554 // --------------------------------------------------------------------------
00555 // Md3Player::linkWeapon
00556 //
00557 // Set weapon model to the player, and link the weapon to player's models.
00558 // --------------------------------------------------------------------------
00559 
00560 void
00561 Md3Player::linkWeapon (Md3Weapon *weapon)
00562 {
00563   _weapon = weapon;
00564 
00565   if (_weapon)
00566     _weapon->linkToModel (_upper);
00567 }
00568 
00569 
00570 // --------------------------------------------------------------------------
00571 // Md3Player::unlinkWeapon
00572 //
00573 // Unset player's weapon.
00574 // --------------------------------------------------------------------------
00575 
00576 void
00577 Md3Player::unlinkWeapon ()
00578 {
00579   if (_weapon)
00580     {
00581       _upper->unlink ("tag_weapon");
00582       _weapon = NULL;
00583     }
00584 }
00585 
00586 
00587 
00588 
00589 // --------------------------------------------------------------------------
00590 // Md3Player::getAnimationState
00591 //
00592 // Retrieve the animation state of the given area (upper/lower)
00593 // --------------------------------------------------------------------------
00594 
00595 void
00596 Md3Player::getAnimationState
00597 (
00598 eAnimationArea area,
00599 Md3AnimState_t& state
00600 )
00601 {
00602         if (eAnimationArea_Upper == area) {
00603                 setState(_upperAnim, state);
00604         } else if (eAnimationArea_Lower == area) {
00605                 setState(_lowerAnim, state);
00606         }
00607 }
00608 
00609 
00610 
00611 void
00612 Md3Player::setState
00613 (
00614 const Md3AnimState& anim,
00615 Md3AnimState_t& state
00616 )
00617 {
00618         state.animationIndex = anim.anim->index;
00619         state.time = anim.curr_time;
00620 }
00621 
00622 
00623 
00624 // --------------------------------------------------------------------------
00625 // Md3Player::setAnimationState
00626 //
00627 // sets the given animation state
00628 // --------------------------------------------------------------------------
00629 
00630 void
00631 Md3Player::setAnimationState
00632 (
00633 eAnimationArea area,
00634 const Md3AnimState_t& state
00635 )
00636 {
00637         Md3PlayerAnim_t * anim = &_anims[state.animationIndex];
00638         if (eAnimationArea_Upper == area) {
00639                 updateAnim(_upperAnim, state, anim);
00640         } else if (eAnimationArea_Lower == area) {
00641                 updateAnim(_lowerAnim, state, anim);
00642         }
00643 }
00644 
00645 
00646 
00647 void
00648 Md3Player::updateAnim
00649 (
00650 Md3AnimState& anim,
00651 const Md3AnimState_t& state,
00652 Md3PlayerAnim_t * a
00653 )
00654 {
00655         anim.anim = a;
00656         anim.curr_time = state.time;
00657         anim.old_time = 0;
00658 }
00659 
00660 
00661 
00662 // --------------------------------------------------------------------------
00663 // Md3Player::loadModels
00664 //
00665 // Load player's models from the path directory.
00666 // --------------------------------------------------------------------------
00667 
00668 void
00669 Md3Player::loadModels (const string &path)
00670 {
00671   string suffix, modelpath;
00672 
00673   // Get model file suffix from LOD
00674   switch (_lod)
00675     {
00676     case kLodLow:
00677       suffix = "_2.md3";
00678       break;
00679 
00680     case kLodMedium:
00681       suffix = "_1.md3";
00682       break;
00683 
00684     case kLodHigh:
00685       suffix = ".md3";
00686       break;
00687     }
00688 
00689   // Load models
00690   modelpath = _path + "lower" + suffix;
00691   _lower = Md3ModelPtr (new Md3Model (modelpath));
00692 
00693   modelpath = _path + "upper" + suffix;
00694   _upper = Md3ModelPtr (new Md3Model (modelpath));
00695 
00696   modelpath = _path + "head" + suffix;
00697   _head = Md3ModelPtr (new Md3Model (modelpath));
00698 
00699   // Create links between the models
00700   _lower->link ("tag_torso", _upper);
00701   _upper->link ("tag_head", _head);
00702 }
00703 
00704 
00705 // --------------------------------------------------------------------------
00706 // Md3Player::loadAnimations
00707 //
00708 // Load animations from the animation.cfg file.
00709 // NOTE: Some animations.cfg files may be broken, i.e. they give wrong
00710 // frame indices or wrong frame number for an animation (which is
00711 // greater or equal than the number of frames of the models).
00712 // We don't fix those files.
00713 // --------------------------------------------------------------------------
00714 
00715 void
00716 Md3Player::loadAnimations (const string &path)
00717 {
00718   string filename (path + "animation.cfg");
00719   string token, buffer;
00720   int index = 0;
00721 
00722   // Open the animation file
00723   std::ifstream ifs (filename.c_str(), std::ios::in | std::ios::binary);
00724 
00725   if (ifs.fail ())
00726     throw Md3Exception ("Couldn't open animation file", filename);
00727 
00728   // Read animation lines
00729   while (!ifs.eof ())
00730     {
00731       // Parse the file line by line
00732       std::getline (ifs, buffer);
00733       std::istringstream line (buffer);
00734 
00735       // Get first char of the line
00736       char c = line.peek ();
00737 
00738       // If the first token is a numeric, then this line
00739       // contains animation infos
00740       if (std::isdigit (c))
00741         {
00742           _anims[index].index = index;
00743           line >> _anims[index].first;
00744           line >> _anims[index].num;
00745           line >> _anims[index].looping;
00746           line >> _anims[index].fps;
00747           index++;
00748         }
00749     }
00750 
00751   ifs.close ();
00752 
00753   // Skip "Torso" frames for the "Legs" animations
00754   int skip = _anims[kLegsWalkCr].first - _anims[kTorsoGesture].first;
00755 
00756   for (int i = kLegsWalkCr; i < kMaxAnimations; ++i)
00757     _anims[i].first -= skip;
00758 }
00759 
00760 
00761 // --------------------------------------------------------------------------
00762 // Md3Player::loadSkins
00763 //
00764 // Load player's skins from the path directory and set the default
00765 // skin as player's current skin.
00766 // --------------------------------------------------------------------------
00767 
00768 void
00769 Md3Player::loadSkins (const string &path)
00770 {
00771   // Open the directory
00772   DIR *dd = opendir (path.c_str ());
00773   if (!dd)
00774     throw Md3Exception ("Couldn't open dir", path);
00775 
00776   dirent *dit;
00777 
00778   // Read directory for textures
00779   while ((dit = readdir (dd)) != NULL)
00780     {
00781       const string filename (dit->d_name);
00782       const string fileext (".skin");
00783       const string pattern ("head_");
00784 
00785       // Filter ".skin" files
00786       if (filename.length () - fileext.length ()
00787           == filename.find (fileext))
00788         {
00789           // Now we should have 3 skin files for a player skin:
00790           // one for upper portion, one for lower and one for head.
00791           // We'll just take one of them to extract the skin name.
00792 
00793           // Filter "head_*.skin" files
00794           if (filename.compare (0, pattern.length (), pattern) == 0)
00795             {
00796               // Extract skin name from filename
00797               const string name (filename, pattern.length (),
00798                    filename.find (fileext) - pattern.length ());
00799 
00800               // Load new skin
00801               Md3PlayerSkinPtr skin (new Md3PlayerSkin (path, name));
00802               _skins.insert (SkinMap::value_type (name, skin));
00803             }
00804         }
00805     }
00806 
00807   // Close directory
00808   closedir (dd);
00809 
00810   // Set the default skin as current player's skin
00811   setSkin ("default");
00812 
00813   // If there is no skin named "default", use the first enry in the map
00814   if (_currentSkin == NULL)
00815     {
00816       _currentSkin = _skins.begin ()->second;
00817       _currentSkinName = _skins.begin ()->first;
00818     }
00819 }