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 }