00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <iostream>
00019 #include <iomanip>
00020 #include <sstream>
00021 #include <cstdarg>
00022 #include <vector>
00023
00024
00025 #define FREEGLUT_STATIC
00026 #define GLUT_STATIC_LIB
00027 #define GLEW_STATIC
00028
00029 #include <GL/glew.h>
00030 #include <GL/glut.h>
00031
00032 #include "md3-model/Md3Player.h"
00033 #include "md3-model/TextureManager.h"
00034
00035 using std::vector;
00036 using std::cout;
00037 using std::cerr;
00038 using std::endl;
00039
00040
00041 struct keyboard_input_t
00042 {
00043 unsigned char keymap[256];
00044 int special[256];
00045 int modifiers;
00046
00047 } keyboard;
00048
00049
00050 struct mouse_input_t
00051 {
00052 int buttons[3];
00053 int x, y;
00054
00055 } mouse;
00056
00057
00058 struct glut_timer_t
00059 {
00060 double current_time;
00061 double last_time;
00062
00063 } timer;
00064
00065
00066 struct Vector_3d
00067 {
00068 float x, y, z;
00069
00070 } rot, eye;
00071
00072 const string animStrings[kMaxAnimations] = {
00073 "Both death 1", "Both dead 1", "Both death 2", "Both dead 2",
00074 "Both death 3", "Both dead 3", "Torso gesture", "Torso attack",
00075 "Torso attack 2", "Torso drop", "Torso raise", "Torso stand",
00076 "Torso stand 2", "Legs walk crouch", "Legs walk", "Legs run",
00077 "Legs back", "Legs swim", "Legs jump", "Legs land", "Legs jump B",
00078 "Legs land B", "Legs idle", "Legs idle crouch", "Legs turn"
00079 };
00080
00081 Md3Player *player = NULL;
00082 Md3Weapon *weapon = NULL;
00083
00084 bool bTextured = true;
00085 bool bLightGL = true;
00086 bool bAnimated = true;
00087 bool bWeapon = false;
00088
00089 int verbose = 2;
00090 int fps = 0;
00091
00092 vector<string> skinList;
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102 static void
00103 animMenu (int item)
00104 {
00105 player->setAnimation (static_cast<Md3PlayerAnimType>(item));
00106
00107 glutPostRedisplay ();
00108 }
00109
00110
00111 static void
00112 skinMenu (int item)
00113 {
00114 player->setSkin (skinList[item]);
00115
00116 glutPostRedisplay ();
00117 }
00118
00119
00120
00121
00122
00123
00124
00125
00126 int
00127 buildSkinMenu (const Md3Player::SkinMap &skinMap)
00128 {
00129 string skinName;
00130 int i = 0;
00131
00132 Md3Player::SkinMap::const_iterator itor;
00133 for (itor = skinMap.begin (); itor != skinMap.end (); ++itor)
00134 skinList.push_back (itor->first);
00135
00136
00137
00138 int menuId = glutCreateMenu (skinMenu);
00139
00140 vector<string>::iterator it;
00141 for (it = skinList.begin (); it != skinList.end (); ++it)
00142 {
00143 skinName.assign (*it, it->find_last_of ('/') + 1, it->length ());
00144 glutAddMenuEntry (skinName.c_str (), i++);
00145 }
00146
00147 return menuId;
00148 }
00149
00150
00151
00152
00153
00154
00155
00156
00157 static int
00158 buildAnimMenu (int start, int end)
00159 {
00160 int menuId = glutCreateMenu (animMenu);
00161
00162 for (int i = start; i < end; ++i)
00163 glutAddMenuEntry (animStrings[i].c_str (), i);
00164
00165 return menuId;
00166 }
00167
00168
00169
00170
00171
00172
00173
00174
00175 static void
00176 shutdownApp ()
00177 {
00178 Texture2DManager::kill ();
00179
00180 delete player;
00181 delete weapon;
00182 }
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192 static void
00193 init (const string &playerpath, const string &weaponpath)
00194 {
00195
00196
00197
00198
00199 GLenum err = glewInit ();
00200 if (GLEW_OK != err)
00201 {
00202
00203 cerr << "Error: " << glewGetErrorString (err) << endl;
00204 shutdownApp ();
00205 }
00206
00207
00208
00209
00210
00211
00212 memset (keyboard.keymap, 0, 256);
00213 memset (keyboard.special, 0, 256);
00214
00215
00216 mouse.buttons[GLUT_LEFT_BUTTON] = GLUT_UP;
00217 mouse.buttons[GLUT_MIDDLE_BUTTON] = GLUT_UP;
00218 mouse.buttons[GLUT_RIGHT_BUTTON] = GLUT_UP;
00219 mouse.x = 0;
00220 mouse.y = 0;
00221
00222
00223 timer.current_time = 0;
00224 timer.last_time = 0;
00225
00226
00227 rot.x = 0.0f; eye.x = 0.0f;
00228 rot.y = 0.0f; eye.y = 0.0f;
00229 rot.z = 0.0f; eye.z = 8.0f;
00230
00231
00232 string playerdir (playerpath);
00233 if (playerdir.find (".md3") == playerdir.length () - 4)
00234 #ifdef _WIN32
00235 playerdir.assign (playerdir, 0, playerdir.find_last_of ('\\'));
00236 #else
00237 playerdir.assign (playerdir, 0, playerdir.find_last_of ('/'));
00238 #endif
00239
00240
00241 try
00242 {
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257 player = new Md3Player (playerdir);
00258 player->setScale (0.1f);
00259 player->setAnimation (kTorsoStand);
00260 player->setAnimation (kLegsIdle);
00261 }
00262 catch (std::runtime_error &err)
00263 {
00264 cerr << "Error: failed to load " << playerdir << endl;
00265 cerr << "Reason: " << err.what () << endl;
00266 exit (-1);
00267 }
00268
00269 try
00270 {
00271
00272 if (!weaponpath.empty ())
00273 {
00274 weapon = new Md3Weapon (weaponpath);
00275 weapon->setScale (0.1f);
00276 player->linkWeapon (weapon);
00277 bWeapon = true;
00278 }
00279 }
00280 catch (std::runtime_error &err)
00281 {
00282 cerr << "Error: failed to load " << weaponpath << endl;
00283 cerr << "Reason: " << err.what () << endl;
00284 }
00285
00286
00287
00288
00289
00290 int deathAnimMenuId = buildAnimMenu (kBothDeath1, kTorsoGesture);
00291 int torsoAnimMenuId = buildAnimMenu (kTorsoGesture, kLegsWalkCr);
00292 int legsAnimMenuId = buildAnimMenu (kLegsWalkCr, kMaxAnimations);
00293 int skinMenuId = buildSkinMenu (player->skins ());
00294
00295 glutCreateMenu (NULL);
00296 glutAddSubMenu ("Death animation", deathAnimMenuId);
00297 glutAddSubMenu ("Torso animation", torsoAnimMenuId);
00298 glutAddSubMenu ("Legs animation", legsAnimMenuId);
00299 glutAddSubMenu ("Skins", skinMenuId);
00300 glutAttachMenu (GLUT_RIGHT_BUTTON);
00301
00302
00303
00304
00305
00306 glClearColor (0.5f, 0.5f, 0.5f, 1.0f);
00307 glShadeModel (GL_SMOOTH);
00308
00309 glEnable (GL_DEPTH_TEST);
00310 glEnable (GL_TEXTURE_2D);
00311 glEnable (GL_CULL_FACE);
00312 glEnable (GL_LIGHTING);
00313 glEnable (GL_LIGHT0);
00314
00315 glCullFace (GL_BACK);
00316 }
00317
00318
00319
00320
00321
00322
00323
00324
00325 static void
00326 reshape (int w, int h)
00327 {
00328 if (h == 0)
00329 h = 1;
00330
00331 glViewport (0, 0, static_cast<GLsizei>(w), static_cast<GLsizei>(h));
00332
00333 glMatrixMode (GL_PROJECTION);
00334 glLoadIdentity ();
00335 gluPerspective (45.0, w / static_cast<GLfloat>(h), 0.1, 1000.0);
00336
00337 glMatrixMode (GL_MODELVIEW);
00338 glLoadIdentity ();
00339
00340 glutPostRedisplay ();
00341 }
00342
00343
00344
00345
00346
00347
00348
00349
00350 static void
00351 updateTimer (struct glut_timer_t *t)
00352 {
00353 t->last_time = t->current_time;
00354 t->current_time = glutGet (GLUT_ELAPSED_TIME) * 0.001f;
00355 }
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365 static void
00366 handleKeyboard (struct keyboard_input_t *k)
00367 {
00368
00369
00370
00371
00372 }
00373
00374
00375
00376
00377
00378
00379
00380
00381 static void
00382 begin2D ()
00383 {
00384 int width = glutGet (GLUT_WINDOW_WIDTH);
00385 int height = glutGet (GLUT_WINDOW_HEIGHT);
00386
00387 glMatrixMode (GL_PROJECTION);
00388 glPushMatrix ();
00389
00390 glLoadIdentity ();
00391 glOrtho (0, width, 0, height, -1.0f, 1.0f);
00392
00393 glMatrixMode (GL_MODELVIEW);
00394 glLoadIdentity ();
00395 }
00396
00397
00398
00399
00400
00401
00402
00403
00404 static void
00405 end2D ()
00406 {
00407 glMatrixMode (GL_PROJECTION);
00408 glPopMatrix ();
00409 glMatrixMode (GL_MODELVIEW);
00410 }
00411
00412
00413
00414
00415
00416
00417
00418
00419 static int
00420 glPrintf (const char *format, ...)
00421 {
00422 char buffer[1024];
00423 std::va_list arg;
00424 int ret;
00425
00426
00427 va_start (arg, format);
00428 ret = vsnprintf (buffer, sizeof (buffer), format, arg);
00429 va_end (arg);
00430
00431
00432 for (unsigned int i = 0; i < strlen (buffer); ++i)
00433 glutBitmapCharacter (GLUT_BITMAP_HELVETICA_12, buffer[i]);
00434
00435 return ret;
00436 }
00437
00438
00439
00440
00441
00442
00443
00444
00445 static void
00446 gameLogic ()
00447 {
00448
00449 static double current_time = 0;
00450 static double last_time = 0;
00451 static int n = 0;
00452
00453 n++;
00454 current_time = timer.current_time;
00455
00456 if ((current_time - last_time) >= 1.0)
00457 {
00458 fps = n;
00459 n = 0;
00460 last_time = current_time;
00461 }
00462
00463
00464 if (bAnimated)
00465 {
00466 double dt = timer.current_time - timer.last_time;
00467 player->animate (dt);
00468 }
00469 }
00470
00471
00472
00473
00474
00475
00476
00477
00478 static void
00479 draw3D ()
00480 {
00481
00482 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00483 glLoadIdentity ();
00484
00485
00486 glTranslated (-eye.x, -eye.y, -eye.z);
00487 glRotated (rot.x, 1.0f, 0.0f, 0.0f);
00488 glRotated (rot.y, 0.0f, 1.0f, 0.0f);
00489 glRotated (rot.z, 0.0f, 0.0f, 1.0f);
00490
00491 glEnable (GL_DEPTH_TEST);
00492
00493 if (bLightGL)
00494 glEnable (GL_LIGHTING);
00495
00496 if (bTextured)
00497 glEnable (GL_TEXTURE_2D);
00498
00499
00500 player->draw ();
00501
00502 glDisable (GL_LIGHTING);
00503 glDisable (GL_TEXTURE_2D);
00504 glDisable (GL_DEPTH_TEST);
00505 }
00506
00507
00508
00509
00510
00511
00512
00513
00514 static void
00515 draw2D ()
00516 {
00517 begin2D ();
00518
00519 glColor3f (1.0f, 1.0f, 1.0f);
00520
00521 if (verbose > 0)
00522 {
00523 glRasterPos2i (10, 10);
00524 glPrintf ("FPS: %i", fps);
00525 }
00526
00527 if (verbose > 1)
00528 {
00529 glRasterPos2i (10, glutGet (GLUT_WINDOW_HEIGHT) - 20);
00530 glPrintf ("Rendering player: \"%s\"", player->name ().c_str ());
00531
00532 glRasterPos2i (10, glutGet (GLUT_WINDOW_HEIGHT) - 35);
00533 glPrintf ("Current skin: \"%s\"", player->skinName ().c_str ());
00534
00535 if (weapon)
00536 {
00537 glRasterPos2i (10, glutGet (GLUT_WINDOW_HEIGHT) - 50);
00538 glPrintf ("Rendering weapon: \"%s\"", weapon->name ().c_str ());
00539
00540 if (!bWeapon)
00541 glPrintf (" (hiden)");
00542 }
00543 }
00544
00545 end2D ();
00546 }
00547
00548
00549
00550
00551
00552
00553
00554
00555 static void
00556 display ()
00557 {
00558 gameLogic ();
00559
00560 draw3D ();
00561
00562 draw2D ();
00563
00564 glutSwapBuffers ();
00565 }
00566
00567
00568
00569
00570
00571
00572
00573
00574 static void
00575 keyPress (unsigned char key, int x, int y)
00576 {
00577
00578 keyboard.keymap[key] = 1;
00579
00580
00581
00582
00583
00584
00585
00586 if (key == 27)
00587 exit (0);
00588
00589 if (key == 'a' || key == 'A')
00590 bAnimated = !bAnimated;
00591
00592 if (key == 'l' || key == 'L')
00593 bLightGL = !bLightGL;
00594
00595 if (key == 'p' || key == 'P')
00596 {
00597 bWeapon = !bWeapon;
00598
00599 if (bWeapon && weapon)
00600 player->linkWeapon (weapon);
00601 else
00602 player->unlinkWeapon ();
00603 }
00604
00605 if (key == 's' || key == 'S')
00606 glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
00607
00608 if (key == 't' || key == 'T')
00609 bTextured = !bTextured;
00610
00611 if (key == 'v' || key == 'V')
00612 verbose = (verbose + 1) % 3;
00613
00614 if (key == 'w' || key == 'W')
00615 glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
00616
00617 glutPostRedisplay ();
00618 }
00619
00620
00621
00622
00623
00624
00625
00626
00627 static void
00628 keyUp (unsigned char key, int x, int y)
00629 {
00630 keyboard.keymap[key] = 0;
00631 }
00632
00633
00634
00635
00636
00637
00638
00639
00640 static void
00641 specialKeyPress (int key, int x, int y)
00642 {
00643 keyboard.special[key] = 1;
00644 }
00645
00646
00647
00648
00649
00650
00651
00652
00653 static void
00654 specialKeyUp (int key, int x, int y)
00655 {
00656 keyboard.special[key] = 0;
00657 }
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667 static void
00668 mouseMotion (int x, int y)
00669 {
00670 if (mouse.buttons[GLUT_MIDDLE_BUTTON] == GLUT_DOWN)
00671 {
00672
00673 eye.z += (x - mouse.x) * 0.1;
00674 }
00675 else if (mouse.buttons[GLUT_LEFT_BUTTON] == GLUT_DOWN)
00676 {
00677 if (keyboard.modifiers & GLUT_ACTIVE_SHIFT)
00678 {
00679
00680 eye.x -= (x - mouse.x) * 0.02;
00681 eye.y += (y - mouse.y) * 0.02;
00682 }
00683 else
00684 {
00685
00686 rot.x += (y - mouse.y);
00687 rot.y += (x - mouse.x);
00688 }
00689 }
00690
00691 mouse.x = x;
00692 mouse.y = y;
00693
00694 glutPostRedisplay ();
00695 }
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705 static void
00706 mouseButton (int button, int state, int x, int y)
00707 {
00708
00709 keyboard.modifiers = glutGetModifiers ();
00710
00711
00712 mouse.buttons[button] = state;
00713 mouse.x = x;
00714 mouse.y = y;
00715 }
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725 static void
00726 idleVisible ()
00727 {
00728
00729 updateTimer (&timer);
00730
00731
00732 handleKeyboard (&keyboard);
00733
00734 if (bAnimated)
00735 glutPostRedisplay ();
00736 }
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746 static void
00747 windowStatus (int state)
00748 {
00749
00750
00751 if ((state != GLUT_HIDDEN) &&
00752 (state != GLUT_FULLY_COVERED))
00753 {
00754 glutIdleFunc (idleVisible);
00755 }
00756 else
00757 {
00758 glutIdleFunc (NULL);
00759 }
00760 }
00761
00762
00763
00764
00765
00766
00767
00768
00769 int
00770 main (int argc, char *argv[])
00771 {
00772
00773 glutInit (&argc, argv);
00774
00775 if (argc < 2)
00776 {
00777 cerr << "usage: " << argv[0] << " <player path> [<weapon path>]" << endl;
00778 return -1;
00779 }
00780
00781
00782 glutInitDisplayMode (GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
00783 glutInitWindowSize (640, 480);
00784 glutCreateWindow ("Quake 3's MD3 Model Viewer");
00785
00786
00787 atexit (shutdownApp);
00788 init (argv[1], (argc > 2) ? argv[2] : string ());
00789
00790
00791 glutReshapeFunc (reshape);
00792 glutDisplayFunc (display);
00793 glutKeyboardFunc (keyPress);
00794 glutKeyboardUpFunc (keyUp);
00795 glutSpecialFunc (specialKeyPress);
00796 glutSpecialUpFunc (specialKeyUp);
00797 glutMotionFunc (mouseMotion);
00798 glutMouseFunc (mouseButton);
00799 glutWindowStatusFunc (windowStatus);
00800 glutIdleFunc (idleVisible);
00801
00802
00803 glutMainLoop ();
00804
00805 return 0;
00806 }