Main.cpp

Go to the documentation of this file.
00001 /* -*- c++ -*- */
00002 /////////////////////////////////////////////////////////////////////////////
00003 //
00004 // Main.cpp -- Copyright (c) 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 // Main file of the MD3 Player loader.
00015 //
00016 /////////////////////////////////////////////////////////////////////////////
00017 
00018 #include <iostream>
00019 #include <iomanip>
00020 #include <sstream>
00021 #include <cstdarg>
00022 #include <vector>
00023 
00024 // force static linking
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 // Keyboard
00041 struct keyboard_input_t
00042 {
00043   unsigned char keymap[256];
00044   int special[256];
00045   int modifiers;
00046 
00047 } keyboard;
00048 
00049 // Mouse
00050 struct mouse_input_t
00051 {
00052   int buttons[3];
00053   int x, y;
00054 
00055 } mouse;
00056 
00057 // Timer
00058 struct glut_timer_t
00059 {
00060   double current_time;
00061   double last_time;
00062 
00063 } timer;
00064 
00065 // Camera
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 // animMenu & skinMenu
00097 //
00098 // GLUT menu callback functions. Handle the menus. Select the skin
00099 // to use and the animation to play.
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 // buildSkinMenu
00122 //
00123 // Create GLUT menu for skin selection.
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   //std::sort (skinList.begin (), skinList.end ());
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 // buildAnimMenu
00153 //
00154 // Create GLUT menu for animation selection.
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 // shutdownApp
00171 //
00172 // Application termination.
00173 // -------------------------------------------------------------------------
00174 
00175 static void
00176 shutdownApp ()
00177 {
00178   Texture2DManager::kill ();
00179 
00180   delete player;
00181   delete weapon;
00182 }
00183 
00184 
00185 // -------------------------------------------------------------------------
00186 // init
00187 //
00188 // Application initialization.  Setup keyboard input, mouse input,
00189 // timer, camera and OpenGL.
00190 // -------------------------------------------------------------------------
00191 
00192 static void
00193 init (const string &playerpath, const string &weaponpath)
00194 {
00195   //
00196   // GLEW Initialization
00197   //
00198 
00199   GLenum err = glewInit ();
00200   if (GLEW_OK != err)
00201     {
00202       // Problem: glewInit failed, something is seriously wrong.
00203       cerr << "Error: " << glewGetErrorString (err) << endl;
00204       shutdownApp ();
00205     }
00206 
00207   //
00208   // Application initialization
00209   //
00210 
00211   // Initialize keyboard
00212   memset (keyboard.keymap, 0, 256);
00213   memset (keyboard.special, 0, 256);
00214 
00215   // Inititialize mouse
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   // Initialize timer
00223   timer.current_time = 0;
00224   timer.last_time = 0;
00225 
00226   // Initialize camera input
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   // Get base dir for player if a *.md3 file is given
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   // Initialize MD3 player
00241   try
00242     {
00243       /*
00244       lower = new Md3Model ("models/players/harley/lower.md3");
00245       upper = new Md3Model ("models/players/harley/upper.md3");
00246       head = new Md3Model ("models/players/harley/head.md3");
00247 
00248       lower->link ("tag_torso", upper);
00249       upper->link ("tag_head", head);
00250 
00251       lower->setScale (0.1f);
00252       upper->setScale (0.1f);
00253       head->setScale (0.1f);
00254       */
00255 
00256       // Load MD3 player
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       // Load weapon if a path is given
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   // Create GLUT menus
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   // Initialize OpenGL
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 // reshape
00321 //
00322 // OpenGL window resizing.  Update the viewport and the projection matrix.
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 // updateTimer
00346 //
00347 // Update the timer.
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 // handleKeyboard
00360 //
00361 // Keyboard input handling.  Handle here continuous actions when a key
00362 // is pressed (like moving the camera).
00363 // -------------------------------------------------------------------------
00364 
00365 static void
00366 handleKeyboard (struct keyboard_input_t *k)
00367 {
00368   /*
00369   if (k->keymap['yourkey'])
00370     do_something ();
00371   */
00372 }
00373 
00374 
00375 // -------------------------------------------------------------------------
00376 // begin2D
00377 //
00378 // Enter into 2D mode.
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 // end2D
00400 //
00401 // Return from 2D mode.
00402 // -------------------------------------------------------------------------
00403 
00404 static void
00405 end2D ()
00406 {
00407   glMatrixMode (GL_PROJECTION);
00408   glPopMatrix ();
00409   glMatrixMode (GL_MODELVIEW);
00410 }
00411 
00412 
00413 // -------------------------------------------------------------------------
00414 // glPrintf
00415 //
00416 // printf-like function for OpenGL.
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   // Format the text
00427   va_start (arg, format);
00428     ret = vsnprintf (buffer, sizeof (buffer), format, arg);
00429   va_end (arg);
00430 
00431   // Print it
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 // gameLogic
00441 //
00442 // Perform application logic.
00443 // -------------------------------------------------------------------------
00444 
00445 static void
00446 gameLogic ()
00447 {
00448   // Calculate frame per seconds
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   // Animate player
00464   if (bAnimated)
00465     {
00466       double dt = timer.current_time - timer.last_time;
00467       player->animate (dt);
00468     }
00469 }
00470 
00471 
00472 // -------------------------------------------------------------------------
00473 // draw3D
00474 //
00475 // Render the 3D part of the scene.
00476 // -------------------------------------------------------------------------
00477 
00478 static void
00479 draw3D ()
00480 {
00481   // Clear window
00482   glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00483   glLoadIdentity ();
00484 
00485   // Perform camera transformations
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   // Draw objects
00500   player->draw ();
00501 
00502   glDisable (GL_LIGHTING);
00503   glDisable (GL_TEXTURE_2D);
00504   glDisable (GL_DEPTH_TEST);
00505 }
00506 
00507 
00508 // -------------------------------------------------------------------------
00509 // draw2D
00510 //
00511 // Render the 2D part of the scene.
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 // display
00551 //
00552 // Render the main scene to the screen.
00553 // -------------------------------------------------------------------------
00554 
00555 static void
00556 display ()
00557 {
00558   gameLogic ();
00559 
00560   draw3D ();
00561 
00562   draw2D ();
00563 
00564   glutSwapBuffers ();
00565 }
00566 
00567 
00568 // -------------------------------------------------------------------------
00569 // keyPress
00570 //
00571 // Key press glut callback function.  Called when user press a key.
00572 // -------------------------------------------------------------------------
00573 
00574 static void
00575 keyPress (unsigned char key, int x, int y)
00576 {
00577   // Update key state
00578   keyboard.keymap[key] = 1;
00579 
00580   //
00581   // Handle here ponctual actions when
00582   // a key is pressed (like toggle ligthing)
00583   //
00584 
00585   // Escape
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 // keyUp
00623 //
00624 // Key up glut callback function.  Called when user release a key.
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 // specialKeyPress
00636 //
00637 // Key press glut callback function.  Called when user press a special key.
00638 // -------------------------------------------------------------------------
00639 
00640 static void
00641 specialKeyPress (int key, int x, int y)
00642 {
00643   keyboard.special[key] = 1;
00644 }
00645 
00646 
00647 // -------------------------------------------------------------------------
00648 // specialKeyUp
00649 //
00650 // Key up glut callback function.  Called when user release a special key.
00651 // -------------------------------------------------------------------------
00652 
00653 static void
00654 specialKeyUp (int key, int x, int y)
00655 {
00656   keyboard.special[key] = 0;
00657 }
00658 
00659 
00660 // -------------------------------------------------------------------------
00661 // mouseMotion
00662 //
00663 // Mouse motion glut callback function.  Called when the user move the
00664 // mouse. Update the camera.
00665 // -------------------------------------------------------------------------
00666 
00667 static void
00668 mouseMotion (int x, int y)
00669 {
00670   if (mouse.buttons[GLUT_MIDDLE_BUTTON] == GLUT_DOWN)
00671     {
00672       // Zoom
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           // Translation
00680           eye.x -= (x - mouse.x) * 0.02;
00681           eye.y += (y - mouse.y) * 0.02;
00682         }
00683       else
00684         {
00685           // Rotation
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 // mouseButton
00700 //
00701 // Mouse button press glut callback function.  Called when the user
00702 // press a mouse button. Update mouse state and keyboard modifiers.
00703 // -------------------------------------------------------------------------
00704 
00705 static void
00706 mouseButton (int button, int state, int x, int y)
00707 {
00708   // Update key modifiers
00709   keyboard.modifiers = glutGetModifiers ();
00710 
00711   // Update mouse state
00712   mouse.buttons[button] = state;
00713   mouse.x = x;
00714   mouse.y = y;
00715 }
00716 
00717 
00718 // -------------------------------------------------------------------------
00719 // idleVisible
00720 //
00721 // Idle glut callback function.  Continuously called. Perform background
00722 // processing tasks.
00723 // -------------------------------------------------------------------------
00724 
00725 static void
00726 idleVisible ()
00727 {
00728   // Update the timer
00729   updateTimer (&timer);
00730 
00731   // Handle keyboard input
00732   handleKeyboard (&keyboard);
00733 
00734   if (bAnimated)
00735     glutPostRedisplay ();
00736 }
00737 
00738 
00739 // -------------------------------------------------------------------------
00740 // windowStatus
00741 //
00742 // Window status glut callback function.  Called when the status of
00743 // the window changes.
00744 // -------------------------------------------------------------------------
00745 
00746 static void
00747 windowStatus (int state)
00748 {
00749   // Disable rendering and/or animation when the
00750   // window is not visible
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 // main
00765 //
00766 // Application main entry point.
00767 // -------------------------------------------------------------------------
00768 
00769 int
00770 main (int argc, char *argv[])
00771 {
00772   // Initialize GLUT
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   // create an OpenGL window
00782   glutInitDisplayMode (GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
00783   glutInitWindowSize (640, 480);
00784   glutCreateWindow ("Quake 3's MD3 Model Viewer");
00785 
00786   // Initialize application
00787   atexit (shutdownApp);
00788   init (argv[1], (argc > 2) ? argv[2] : string ());
00789 
00790   // Setup glut callback functions
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   // Enter the main loop
00803   glutMainLoop ();
00804 
00805   return 0;
00806 }