00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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"
00038
00039 #ifdef _WIN32
00040 const char kSeparator = '\\';
00041 #else
00042 const char kSeparator = '/';
00043 #endif
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059 Md3PlayerSkin::Md3PlayerSkin (const string &path, const string &name)
00060 : _path (path), _name (name)
00061 {
00062
00063 loadSkinFile (path + "lower_" + name + ".skin", _lowerTextures);
00064
00065
00066 loadSkinFile (path + "upper_" + name + ".skin", _upperTextures);
00067
00068
00069 loadSkinFile (path + "head_" + name + ".skin", _headTextures);
00070 }
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080 Md3PlayerSkin::~Md3PlayerSkin ()
00081 {
00082 }
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093 void
00094 Md3PlayerSkin::loadSkinFile (const string &filename, TexMap &tmap)
00095 {
00096
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
00105 Texture2DManager *texMgr = Texture2DManager::getInstance ();
00106
00107
00108 while (!ifs.eof ())
00109 {
00110 string meshname, texname, buffer;
00111
00112
00113 std::getline (ifs, meshname, ',');
00114 ifs >> texname;
00115
00116
00117 if (!meshname.empty () && !texname.empty ()
00118 && meshname.compare (0, 4, "tag_") != 0)
00119 {
00120
00121
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
00128 Texture2D *tex = texMgr->load (texname);
00129
00130 tmap.insert (TexMap::value_type (meshname, tex));
00131 }
00132
00133
00134 std::getline (ifs, buffer);
00135 }
00136
00137 ifs.close ();
00138 }
00139
00140
00141
00142
00143
00144
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
00159
00160
00161
00162
00163
00164
00165
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
00174 if (_path.find_last_of (kSeparator) < _path.length () - 1)
00175 _path += kSeparator;
00176
00177
00178 _name.assign (_path, 0, _path.find_last_of (kSeparator));
00179 _name.assign (_name, _name.find_last_of (kSeparator) + 1, _name.length ());
00180
00181
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
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
00206 ftest.close ();
00207
00208 _barrel = Md3ModelPtr (new Md3Model (modelpath));
00209 _barrel->loadShaders ();
00210
00211
00212 _weapon->link ("tag_barrel", _barrel);
00213 }
00214 }
00215
00216
00217
00218
00219
00220
00221
00222
00223 Md3Weapon::~Md3Weapon ()
00224 {
00225 }
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235 void
00236 Md3Weapon::draw () const
00237 {
00238
00239 scaleModels ();
00240
00241
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
00253
00254
00255
00256
00257
00258 void
00259 Md3Weapon::scaleModels () const
00260 {
00261
00262
00263
00264
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
00276
00277
00278
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
00292
00293
00294
00295
00296
00297
00298
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
00310
00311
00312
00313
00314 void
00315 Md3Player::Md3AnimState::setup (Md3PlayerAnim_t *a)
00316 {
00317
00318 if (anim == a)
00319 return;
00320
00321
00322 anim = a;
00323 curr_frame = a->first;
00324 next_frame = a->first;
00325 interp = 0.0f;
00326 }
00327
00328
00329
00330
00331
00332
00333
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
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369 Md3Player::Md3Player (const string &path, Md3PlayerLOD lod)
00370 : _weapon (NULL), _path (path), _scale (1.0f), _lod (lod)
00371 {
00372
00373 if (_path.find_last_of (kSeparator) < _path.length () - 1)
00374 _path += kSeparator;
00375
00376
00377 _name.assign (_path, 0, _path.find_last_of (kSeparator));
00378 _name.assign (_name, _name.find_last_of (kSeparator) + 1, _name.length ());
00379
00380
00381 loadModels (_path);
00382
00383
00384 loadAnimations (_path);
00385
00386
00387 loadSkins (_path);
00388 }
00389
00390
00391
00392
00393
00394
00395
00396
00397 Md3Player::~Md3Player ()
00398 {
00399 }
00400
00401
00402
00403
00404
00405
00406
00407
00408 void
00409 Md3Player::draw () const
00410 {
00411
00412
00413
00414
00415 Md3Player * pThis = (Md3Player *) this;
00416
00417
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
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
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
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
00452
00453
00454
00455
00456 void
00457 Md3Player::renderFrame (int upperFrame, int lowerFrame) const
00458 {
00459
00460 Md3Player * pThis = (Md3Player *) this;
00461
00462
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
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
00479 pThis->_lower->setupAnimation (lowerFrame, lowerFrame, 0.0f);
00480 pThis->_upper->setupAnimation (upperFrame, upperFrame, 0.0f);
00481
00482
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
00494
00495
00496
00497
00498 void
00499 Md3Player::animate (float dt)
00500 {
00501 _lowerAnim.update (dt);
00502 _upperAnim.update (dt);
00503 }
00504
00505
00506
00507
00508
00509
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
00533
00534
00535
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
00556
00557
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
00572
00573
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
00591
00592
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
00626
00627
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
00664
00665
00666
00667
00668 void
00669 Md3Player::loadModels (const string &path)
00670 {
00671 string suffix, modelpath;
00672
00673
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
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
00700 _lower->link ("tag_torso", _upper);
00701 _upper->link ("tag_head", _head);
00702 }
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
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
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
00729 while (!ifs.eof ())
00730 {
00731
00732 std::getline (ifs, buffer);
00733 std::istringstream line (buffer);
00734
00735
00736 char c = line.peek ();
00737
00738
00739
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
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
00763
00764
00765
00766
00767
00768 void
00769 Md3Player::loadSkins (const string &path)
00770 {
00771
00772 DIR *dd = opendir (path.c_str ());
00773 if (!dd)
00774 throw Md3Exception ("Couldn't open dir", path);
00775
00776 dirent *dit;
00777
00778
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
00786 if (filename.length () - fileext.length ()
00787 == filename.find (fileext))
00788 {
00789
00790
00791
00792
00793
00794 if (filename.compare (0, pattern.length (), pattern) == 0)
00795 {
00796
00797 const string name (filename, pattern.length (),
00798 filename.find (fileext) - pattern.length ());
00799
00800
00801 Md3PlayerSkinPtr skin (new Md3PlayerSkin (path, name));
00802 _skins.insert (SkinMap::value_type (name, skin));
00803 }
00804 }
00805 }
00806
00807
00808 closedir (dd);
00809
00810
00811 setSkin ("default");
00812
00813
00814 if (_currentSkin == NULL)
00815 {
00816 _currentSkin = _skins.begin ()->second;
00817 _currentSkinName = _skins.begin ()->first;
00818 }
00819 }