wave-glut/tool/bvhViewer/main.cpp

Go to the documentation of this file.
00001 /*
00002  * main.cpp
00003  *
00004  * Copyright (C) 2009  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  * Viewer for BVH files.
00008  */
00009 
00010 ////////////////////////////////////////////////////////////////////////////////
00011 ///
00012 /// \ingroup tool
00013 /// \defgroup tool_bvh_view OpenGL BVH Viewer
00014 ///
00015 /// Simple OpenGL-based BVH file/animation viewer.
00016 ///
00017 ////////////////////////////////////////////////////////////////////////////////
00018 
00019 
00020 // includes --------------------------------------------------------------------
00021 #include "common/wave_ex.h"
00022 
00023 #include "bvh/bvh.h"
00024 #include "glut/camera.h"
00025 #include "glut/glut.h"
00026 #include "glut/glut_2d.h"
00027 #include "glut-font/glut-font.h"
00028 #include "perf/perf.h"
00029 #include "util/file.h"
00030 
00031 
00032 static const int s_defaultWidth                 = 800;
00033 static const int s_defaultHeight                = 600;
00034 
00035 static int s_retval                             = 0;
00036 
00037 static float s_delta                            = 1;
00038 
00039 static const float s_d2Rotate                   = 0.25;
00040 static float s_dRotate                          = 0;
00041 
00042 static const int s_maxLight                     = 4;
00043 
00044 static int s_names                              = 0;    // no names
00045 
00046 static int s_animSpeed                          = 0;
00047 static int s_maxSpeed                           = 2;
00048 
00049 
00050 static smart_ptr<perf::Timer> s_overallTimer;
00051 
00052 
00053 ////////////////////////////////////////////////////////////////////////////////
00054 //
00055 //      static helper methods
00056 //
00057 ////////////////////////////////////////////////////////////////////////////////
00058 
00059 static const char *
00060 getSpeed
00061 (
00062 void
00063 )
00064 throw()
00065 {
00066         switch (s_animSpeed) {
00067         case 0:         return "stopped";
00068         case 1:         return "slow";
00069         case 2:         return "normal";
00070         }
00071 
00072         return "bogus";
00073 }
00074 
00075 
00076 
00077 ////////////////////////////////////////////////////////////////////////////////
00078 //
00079 //      BvhHost -- class that implements the glut::Host interface for the
00080 //              BVH viewer
00081 //
00082 ////////////////////////////////////////////////////////////////////////////////
00083 
00084 class BvhHost : public glut::Host {
00085 public:
00086         BvhHost(void) throw() : m_nodes(NULL) { }
00087         ~BvhHost(void) throw() { }
00088 
00089         // glut::Host class interface methods ----------------------------------
00090         void init(void);
00091         void display(IN int w, IN int h);
00092         int shutdown(void);
00093         eBehavior keyboard(IN int key, IN int mods);
00094         eBehavior specialKey(IN int key, IN int mods);
00095 
00096         // static factory methods ----------------------------------------------
00097         static smart_ptr<glut::Host> create(IN const char * directory) {
00098                         ASSERT(directory, "null");
00099 
00100                         smart_ptr<BvhHost> local = new BvhHost;
00101                         ASSERT(local, "out of memory");
00102 
00103                         local->m_dir = directory;
00104 
00105                         return local;
00106                 }
00107 
00108 private:
00109         // private helper methods ----------------------------------------------
00110         void loadSkeleton(void);
00111         void drawSkeleton(void);
00112 
00113         // private member data -------------------------------------------------
00114         std::string                     m_file;
00115         std::string                     m_dir;
00116         VecString                       m_files;
00117         int                             m_currFile;
00118         smart_ptr<bvh::Skeleton>        m_skeleton;
00119         glut::Viewer                    m_viewer;
00120         bvh::node_position_t *          m_nodes;
00121         int                             m_nNodes;
00122         perf::time_t                    m_prevTime;
00123         perf::time_t                    m_currTime;
00124         float                           m_animTime;
00125 };
00126 
00127 
00128 
00129 ////////////////////////////////////////////////////////////////////////////////
00130 //
00131 //      BvhHost -- glut::Host class interface methods
00132 //
00133 ////////////////////////////////////////////////////////////////////////////////
00134 
00135 void
00136 BvhHost::init
00137 (
00138 void
00139 )
00140 {
00141         // get all children
00142         walkDirectoryTree(m_dir.c_str(), "bvh", m_files);
00143         DPRINTF("Found %d BVH files", (int) m_files.size());
00144 
00145         // initialize iterator
00146         m_currFile = 0;
00147 
00148         // initialize
00149         this->loadSkeleton();
00150 
00151         // figure out starting distance from center
00152 
00153         // set starting position
00154         m_viewer.setPosition(point3d_t(0, 0, -100.0));
00155 }
00156 
00157 
00158 void
00159 BvhHost::display
00160 (
00161 IN int width,
00162 IN int height
00163 )
00164 {
00165         perf::Timer timer("display");
00166 
00167         // update previous time
00168         m_prevTime = m_currTime;
00169 
00170         // update FPS
00171         m_currTime = perf::getNow();
00172         static glut::fps_t s_fps(m_currTime);
00173         s_fps.tick(m_currTime);
00174 
00175         // clear buffers
00176         glClearColor(0.0, 0.0, 0.0, 0.0);
00177         glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
00178 
00179         // set up glut for drawing
00180         glut::camera_t camera;
00181         glut::setOpenGLProjection(camera);
00182         glut::setOpenGLViewer(m_viewer);
00183 
00184         // rotate object
00185         static float angle = 0.0;
00186         angle += s_dRotate;
00187         glRotatef(angle, 0.0, 1.0, 0.0);
00188 
00189         // draw object
00190         this->drawSkeleton();
00191 
00192         // disable lighting
00193         glDisable(GL_LIGHTING);
00194 
00195         // draw axes
00196         glColor3f(0, 0, 1);     // blue: y
00197         glBegin(GL_LINES);
00198                 glVertex3f(0, 1, 0);
00199                 glVertex3f(0, 2, 0);
00200         glEnd();
00201 
00202         glColor3f(1, 0, 0);     // red: x
00203         glBegin(GL_LINES);
00204                 glVertex3f(1, 0, 0);
00205                 glVertex3f(2, 0, 0);
00206         glEnd();
00207 
00208         glColor3f(0, 1, 0);     // green: z
00209         glBegin(GL_LINES);
00210                 glVertex3f(0, 0, 1);
00211                 glVertex3f(0, 0, 2);
00212         glEnd();
00213 
00214 
00215         // disable expensive stuff before rendering fonts!
00216 //      glDisable(GL_DEPTH_TEST);
00217 //      glDisable(GL_BLEND);
00218 
00219         // output FPS
00220         int textHeight = 14;
00221         int lineSpace = 2;
00222         int lineHeight = textHeight + lineSpace;
00223         glColor3f(1.0, 1.0, 1.0);
00224         glut::push2D(width, height);
00225         char buffer[128];
00226 
00227         sprintf(buffer, "%s", m_file.c_str());
00228         glut::Font * font = glut::getDefaultFont();
00229         font->display(1, lineHeight, 0, buffer);
00230 
00231         sprintf(buffer, "%4.1lf fps", s_fps.getFPS());
00232         font->display(1, 2 * lineHeight, 0, buffer);
00233 
00234         sprintf(buffer, "(r/R)otate: %5.2lf degrees/frame", s_dRotate);
00235         font->display(width - 300, height - lineSpace, 0, buffer);
00236 
00237         sprintf(buffer, "(a)nimation time: %5.2fs (%s)", m_animTime, getSpeed());
00238         font->display(1, height - lineSpace, 0, buffer);
00239 
00240         sprintf(buffer, "(n)ames: %s", (s_names ? "yes" : "no"));
00241         font->display(1, height - lineHeight, 0, buffer);
00242 
00243         point3d_t pos = m_viewer.getPosition();
00244         sprintf(buffer, "position: (%f, %f, %f)", pos.x, pos.y, pos.z);
00245         font->display(width - 450, lineHeight, 0, buffer);
00246 
00247         glut::pop2D();
00248 }
00249 
00250 
00251 
00252 int
00253 BvhHost::shutdown
00254 (
00255 void
00256 )
00257 {
00258         s_overallTimer = NULL;
00259         perf::dumpTimingSummary(std::cerr);
00260         return 0;
00261 }
00262 
00263 
00264 
00265 glut::Host::eBehavior
00266 BvhHost::keyboard
00267 (
00268 IN int key,
00269 IN int mods
00270 )
00271 {
00272         switch (key) {
00273         case 'q':
00274         case 27:                // escape key
00275                 return eExit;
00276 
00277         case 'a':
00278                 s_animSpeed++;
00279                 if (s_animSpeed > s_maxSpeed) {
00280                         s_animSpeed = 0;
00281                 }
00282                 break;
00283 
00284         case 'r':
00285                 s_dRotate += s_d2Rotate;
00286                 break;
00287 
00288         case 'R':
00289                 s_dRotate -= s_d2Rotate;
00290                 break;
00291 
00292         case '+':
00293         case '=':
00294                 m_viewer.move(s_delta, 0, 0);
00295                 break;
00296 
00297         case '-':
00298                 m_viewer.move(-s_delta, 0, 0);
00299                 break;
00300 
00301         case 'n':
00302                 s_names = 1 - s_names;
00303                 break;
00304         }
00305 
00306         return eContinue;
00307 }
00308 
00309 
00310 
00311 glut::Host::eBehavior
00312 BvhHost::specialKey
00313 (
00314 IN int key,
00315 IN int mods
00316 )
00317 {
00318         int deltaF = 0;
00319 
00320         switch (key) {
00321         case GLUT_KEY_UP:
00322                 m_viewer.move(0, 0, s_delta);
00323                 break;
00324 
00325         case GLUT_KEY_DOWN:
00326                 m_viewer.move(0, 0, -s_delta);
00327                 break;
00328 
00329         case GLUT_KEY_LEFT:
00330                 m_viewer.move(0, -s_delta, 0);
00331                 break;
00332 
00333         case GLUT_KEY_RIGHT:
00334                 m_viewer.move(0, s_delta, 0);
00335                 break;
00336 
00337         case GLUT_KEY_PAGE_UP:
00338                 deltaF = -1;
00339                 break;
00340 
00341         case GLUT_KEY_PAGE_DOWN:
00342                 deltaF = +1;
00343                 break;
00344 
00345         }
00346 
00347         if (deltaF) {
00348                 m_currFile += deltaF;
00349                 if (m_currFile < 0) {
00350                         m_currFile = m_files.size() - 1;
00351                 } else if (m_currFile >= (int) m_files.size()) {
00352                         m_currFile = 0;
00353                 }
00354                 this->loadSkeleton();
00355         }
00356 
00357         return eContinue;
00358 }
00359 
00360 
00361 
00362 ////////////////////////////////////////////////////////////////////////////////
00363 //
00364 //      BvhHost -- private helper methods
00365 //
00366 ////////////////////////////////////////////////////////////////////////////////
00367 
00368 void
00369 BvhHost::loadSkeleton
00370 (
00371 void
00372 )
00373 {
00374         if (m_nodes) {
00375                 delete[] m_nodes;
00376                 m_nodes = NULL;
00377         }
00378         m_skeleton = NULL;
00379         m_currFile = m_currFile % m_files.size();
00380 
00381         // load skeleton
00382         m_file = m_files[m_currFile];
00383 
00384         std::string path = m_dir;
00385         path += "/";
00386         path += m_file;
00387         m_skeleton = bvh::Skeleton::load(path.c_str());
00388         ASSERT(m_skeleton, "null");
00389 }
00390 
00391 
00392 
00393 void
00394 BvhHost::drawSkeleton
00395 (
00396 void
00397 )
00398 {
00399         perf::Timer timer("drawSkeleton");
00400         if (!m_skeleton)
00401                 return;
00402 
00403         float deltaT = float(m_currTime.getSeconds() - m_prevTime.getSeconds());
00404         if (1 == s_animSpeed) {
00405                 m_animTime += 0.2 * deltaT;
00406         } else if (2 == s_animSpeed) {
00407                 m_animTime += deltaT;
00408         }
00409 
00410         // need to allocate node position array?
00411         if (!m_nodes) {
00412                 m_nNodes = m_skeleton->getNodeCount(0);
00413                 ASSERT(m_nNodes > 0, "bad node count: %d", m_nNodes);
00414 
00415                 m_nodes = new bvh::node_position_t[m_nNodes];
00416                 ASSERT(m_nodes, "out of memory");
00417 
00418                 m_animTime = 0.0;
00419         }
00420 
00421         // update node positions given current time
00422         m_skeleton->getNodePositions(0, m_animTime, m_nodes);
00423 
00424         // first pass--get weighted average of center
00425         point3d_t avg(0, 0, 0);
00426         for (int i = 0; i < m_nNodes; ++i) {
00427                 const bvh::node_position_t&n = m_nodes[i];
00428                 avg += n.pos;
00429         }
00430         avg *= (1.0 / m_nNodes);
00431         avg.clear();
00432 
00433         // okay, now walk all nodes and draw!
00434         float dx = 0.25;                // sizing
00435         glut::Font * font = glut::getDefaultFont();
00436         for (int i = 0; i < m_nNodes; ++i) {
00437                 const bvh::node_position_t&n = m_nodes[i];
00438 
00439                 point3d_t r = n.pos - avg;
00440 
00441                 // draw a small sphere here...
00442                 glMatrixMode(GL_MODELVIEW);
00443                 glPushMatrix();
00444                 glColor3f(0.4, 0.4, 0.4);
00445                 glTranslatef(r.x, r.y, r.z);
00446                 glutSolidSphere(dx, 8, 8);
00447                 glPopMatrix();
00448 
00449                 if (s_names) {
00450                         glColor3f(0, 1, 0);
00451                         font->display(r.x, r.y, r.z, n.name);
00452                 }
00453 
00454                 // draw a line to the parent
00455                 if (n.parent) {
00456                         point3d_t q = n.parent->pos - avg;
00457 
00458                         glColor3f(0.8, 0.3, 0.1);
00459                         glBegin(GL_LINES);
00460                         glVertex3f(q.x + dx, q.y, q.z);
00461                         glVertex3f(r.x + dx, r.y, r.z);
00462                         glVertex3f(q.x - dx, q.y, q.z);
00463                         glVertex3f(r.x - dx, r.y, r.z);
00464                         glVertex3f(q.x, q.y, q.z + dx);
00465                         glVertex3f(r.x, r.y, r.z + dx);
00466                         glVertex3f(q.x, q.y, q.z - dx);
00467                         glVertex3f(r.x, r.y, r.z - dx);
00468                         glVertex3f(q.x, q.y + dx, q.z);
00469                         glVertex3f(r.x, r.y + dx, r.z);
00470                         glVertex3f(q.x, q.y - dx, q.z);
00471                         glVertex3f(r.x, r.y - dx, r.z);
00472                         glEnd();
00473                 }
00474         }
00475 }
00476 
00477 
00478 
00479 ////////////////////////////////////////////////////////////////////////////////
00480 //
00481 //      entry point
00482 //
00483 ////////////////////////////////////////////////////////////////////////////////
00484 
00485 int
00486 main
00487 (
00488 IN int argc,
00489 IN const char * argv[]
00490 )
00491 {
00492         ASSERT(2 == argc, "Usage: bvhViewer <directory>");
00493         const char * directory = argv[1];
00494 
00495         try {
00496                 s_overallTimer = new perf::Timer("overall timer");
00497                 ASSERT(s_overallTimer, "null");
00498 
00499                 // create host object
00500                 smart_ptr<glut::Host> host = BvhHost::create(directory);
00501                 ASSERT(host, "null");
00502 
00503                 // ask glut to run
00504                 std::string title = "BVH Viewer: ";
00505                 title += directory;
00506 
00507                 glut::start(argc, argv, s_defaultWidth, s_defaultHeight,
00508                     title.c_str(), NULL, host);
00509 
00510         } catch (std::exception& e) {
00511                 DPRINTF("Exception: %s", e.what());
00512                 s_retval = 1;
00513         }
00514 
00515         return 1;       // never get here!
00516 }
00517