glut-demo.cpp

Go to the documentation of this file.
00001 /*
00002  * glut-demo.cpp
00003  *
00004  * Copyright (C) 2010  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  */
00031 
00032 // includes --------------------------------------------------------------------
00033 #include "glut-demo.h"          // always include our own header first
00034 
00035 #include <iostream>
00036 #include <math.h>
00037 
00038 #include "glut/glut_2d.h"
00039 #include "glut-font/glut-font.h"
00040 #include "perf/perf.h"
00041 #include "util/date.h"
00042 
00043 
00044 namespace glut {
00045 
00046 
00047 // interface destructors
00048 DisplayLine::~DisplayLine(void) throw() { }
00049 
00050 
00051 // constants
00052 static const int s_maxBufferSize                = 256;
00053 static const int s_maxLighting                  = 3;
00054 static const float s_dRot                       = 0.25; // degrees per frame
00055 static const float s_2                          = sqrt(0.5);
00056 
00057 static const float s_radiansPerDegree           = M_PI / 180.0;
00058 
00059 
00060 ////////////////////////////////////////////////////////////////////////////////
00061 //
00062 //      static helper methods
00063 //
00064 ////////////////////////////////////////////////////////////////////////////////
00065 
00066 
00067 
00068 ////////////////////////////////////////////////////////////////////////////////
00069 //
00070 //      common display line objects
00071 //
00072 ////////////////////////////////////////////////////////////////////////////////
00073 
00074 class FpsDisplay : public DisplayLine {
00075 public:
00076         // constructor, destructor ---------------------------------------------
00077         FpsDisplay(void) throw() : m_fps(perf::getNow()) { }
00078         ~FpsDisplay(void) throw() { }
00079 
00080         // public class methods ------------------------------------------------
00081         void tick(void) throw() {
00082                         m_fps.tick(perf::getNow());
00083                 }
00084 
00085         // glut::DisplayLine class interface methods ---------------------------
00086         ePosition getPosition(void) { return eTopLeft; }
00087         const char * getText(void) {
00088                         int fps = (int) (m_fps.getFPS() + 0.5);
00089                         sprintf(m_buffer, "%d fps", fps);
00090                         return m_buffer;
00091                 }
00092 
00093 private:
00094         // private member data -------------------------------------------------
00095         char            m_buffer[s_maxBufferSize];
00096         fps_t           m_fps;  
00097 };
00098 
00099 
00100 
00101 class WireDisplay : public DisplayLine {
00102 public:
00103         // constructor, destructor ---------------------------------------------
00104         WireDisplay(void) throw() : m_wire(false) { }
00105         ~WireDisplay(void) throw() { }
00106 
00107         // public class methods ------------------------------------------------
00108         void setWireframe(IN bool wireframe) throw() { m_wire = wireframe; }
00109 
00110         // glut::DisplayLine class interface methods ---------------------------
00111         ePosition getPosition(void) { return eTopLeft; }
00112         const char * getText(void) {
00113                         sprintf(m_buffer, "(w)ireframe: %s",
00114                             m_wire ? "yes" : "no");
00115                         return m_buffer;
00116                 }
00117 
00118 private:
00119         // private member data -------------------------------------------------
00120         char            m_buffer[s_maxBufferSize];
00121         bool            m_wire;
00122 };
00123 
00124 
00125 
00126 class LightingDisplay : public DisplayLine {
00127 public:
00128         // constructor, destructor ---------------------------------------------
00129         LightingDisplay(void) throw() : m_light(0) { }
00130         ~LightingDisplay(void) throw() { }
00131 
00132         // public class methods ------------------------------------------------
00133         void setLighting(IN int level) throw() { m_light = level; }
00134 
00135         // glut::DisplayLine class interface methods ---------------------------
00136         ePosition getPosition(void) { return eTopRight; }
00137         const char * getText(void) {
00138                         const char * txt = "(unknown?)";
00139                         switch (m_light) {
00140                         case 0: txt = "none";                   break;
00141                         case 1: txt = "ambient only";           break;
00142                         case 2: txt = "ambient and directed";   break;
00143                         }
00144                         sprintf(m_buffer, "(l)ighting: %s", txt);
00145                         return m_buffer;
00146                 }
00147 
00148 private:
00149         // private member data -------------------------------------------------
00150         char            m_buffer[s_maxBufferSize];
00151         int             m_light;
00152 };
00153 
00154 
00155 
00156 class PositionDisplay : public DisplayLine {
00157 public:
00158         // constructor, destructor ---------------------------------------------
00159         ~PositionDisplay(void) throw() { }
00160 
00161         // public class methods ------------------------------------------------
00162         void setPosition(IN const point3d_t& pos) { m_pos = pos; }
00163 
00164         // glut::DisplayLine class interface methods ---------------------------
00165         ePosition getPosition(void) { return eTopRight; }
00166         const char * getText(void) {
00167                         sprintf(m_buffer, "position: (%.1f, %.1f, %.1f)",
00168                             m_pos.x, m_pos.y, m_pos.z);
00169                         return m_buffer;
00170                 }
00171 
00172 private:
00173         // private member data -------------------------------------------------
00174         char            m_buffer[s_maxBufferSize];
00175         point3d_t       m_pos;
00176 };
00177 
00178 
00179 
00180 class RotateDisplay : public DisplayLine {
00181 public:
00182         // constructor, destructor ---------------------------------------------
00183         ~RotateDisplay(void) throw() { }
00184 
00185         // public class methods ------------------------------------------------
00186         void setRotate(IN float dRot) throw() { m_rot = dRot; }
00187 
00188         // glut::DisplayLine class interface methods ---------------------------
00189         ePosition getPosition(void) { return eBottomRight; }
00190         const char * getText(void) {
00191                         sprintf(m_buffer, "(r/R)otate: %.2f degrees/frame",
00192                             m_rot);
00193                         return m_buffer;
00194                 }
00195 
00196 private:
00197         // private member data -------------------------------------------------
00198         char            m_buffer[s_maxBufferSize];
00199         float           m_rot;
00200 };
00201 
00202 
00203 
00204 ////////////////////////////////////////////////////////////////////////////////
00205 //
00206 //      Demo - class that implements the glut::Host interface
00207 //
00208 ////////////////////////////////////////////////////////////////////////////////
00209 
00210 class Demo : public Host {
00211 public:
00212         // constructor, destructor ---------------------------------------------
00213         Demo(void);
00214         ~Demo(void) throw();
00215 
00216         // public class methods ------------------------------------------------
00217         void initialize(IN DemoHost * host);
00218 
00219         // glut::Host class interface methods ----------------------------------
00220         void init(void);
00221         void display(IN int w, IN int h);
00222         eBehavior mouseMove(IN int x, IN int y);
00223         eBehavior mouseButton(IN int button, IN int state, IN int x, IN int y);
00224         eBehavior keyboard(IN int key, IN int mods);
00225         eBehavior specialKey(IN int key, IN int mods);
00226         int shutdown(void);
00227 
00228 private:
00229         // private helper methods ----------------------------------------------
00230         void setLighting(void);
00231         void renderLines(IN int x, IN int y, IN int dy,
00232                                 IN DisplayLine::ePosition pos);
00233 
00234         // private member data -------------------------------------------------
00235         DemoHost *              m_host;
00236         bool                    m_wireframe;    // render wireframe?
00237         int                     m_light;        // lighting level (0 - 2)
00238         float                   m_rot;          // rotations (degrees/frame)
00239         float                   m_angle;        // degrees, not radians
00240         float                   m_delta;
00241         Viewer                  m_viewer;
00242         vec_display_lines_t     m_lines;
00243         smart_ptr<glut::RenderQueue> m_rQueue;
00244         smart_ptr<perf::Timer>  m_demoTimer;
00245         smart_ptr<FpsDisplay>   m_fps;
00246         smart_ptr<WireDisplay>  m_wire;
00247         smart_ptr<LightingDisplay> m_lighting;
00248         smart_ptr<PositionDisplay> m_position;
00249         smart_ptr<RotateDisplay> m_rotate;
00250 };
00251 
00252 
00253 
00254 Demo::Demo(void)
00255 :
00256 m_host(NULL),
00257 m_wireframe(false),
00258 m_light(0),
00259 m_rot(0.0),
00260 m_angle(0.0)
00261 {
00262 }
00263 
00264 
00265 
00266 Demo::~Demo(void)
00267 throw()
00268 {
00269 }
00270 
00271 
00272 
00273 void
00274 Demo::initialize
00275 (
00276 IN DemoHost * host
00277 )
00278 {
00279         ASSERT(host, "null");
00280         m_host = host;
00281 
00282         m_demoTimer = new perf::Timer("glut demo overall timer");
00283         THROW(m_demoTimer, "null");
00284 
00285         m_viewer.setPosition(point3d_t(0, 0, -10));
00286 
00287         // get step size
00288         m_delta = host->getDelta();
00289         ASSERT(m_delta > 0.0, "Bad step size: %f", m_delta);
00290 
00291         // add our own display lines first
00292         m_fps = new FpsDisplay;
00293         THROW(m_fps, "out of memory");
00294         m_lines.push_back(m_fps);
00295 
00296         m_wire = new WireDisplay;
00297         THROW(m_wire, "out of memory");
00298         m_lines.push_back(m_wire);
00299 
00300         m_lighting = new LightingDisplay;
00301         THROW(m_lighting, "out of memory");
00302         m_lines.push_back(m_lighting);
00303 
00304         m_position = new PositionDisplay;
00305         THROW(m_position, "out of memory");
00306         m_lines.push_back(m_position);
00307 
00308         m_rotate = new RotateDisplay;
00309         THROW(m_rotate, "out of memory");
00310         m_lines.push_back(m_rotate);
00311 
00312         // append whatever the host wanted
00313         vec_display_lines_t lines;
00314         m_host->getDisplayLines(lines);
00315         m_lines.insert(m_lines.end(), lines.begin(), lines.end());
00316         DPRINTF("I have %d display lines", (int) m_lines.size());
00317 
00318         // set up rendering queue
00319         int nSlots = 1024;
00320         m_rQueue = glut::RenderQueue::create(nSlots);
00321         ASSERT(m_rQueue, "failed to create render queue");
00322 }
00323 
00324 
00325 
00326 ////////////////////////////////////////////////////////////////////////////////
00327 //
00328 //      Demo -- glut::Host class interface methods
00329 //
00330 ////////////////////////////////////////////////////////////////////////////////
00331 
00332 void
00333 Demo::init
00334 (
00335 void
00336 )
00337 {
00338         // let host do something
00339         m_host->onInit();
00340 }
00341 
00342 
00343 
00344 void
00345 Demo::display
00346 (
00347 IN int w,
00348 IN int h
00349 )
00350 {
00351         perf::Timer timer("Demo::display");
00352         ASSERT(m_rQueue, "null");
00353 
00354         // convenient hook
00355         m_delta = m_host->getDelta();
00356 
00357         // set up for 3D rendering
00358         m_fps->tick();
00359         m_wire->setWireframe(m_wireframe);
00360         m_lighting->setLighting(m_light);
00361         m_rotate->setRotate(m_rot);
00362         m_position->setPosition(m_viewer.getPosition());
00363 
00364         // basic capabilities
00365         glEnable(GL_DEPTH_TEST);
00366         glFrontFace(GL_CCW);    // counter clockwise is front
00367 
00368         // wireframe?  or polygon?
00369         if (m_wireframe) {
00370                 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00371                 glColor3f(1.0, 1.0, 1.0);
00372                 glDisable(GL_CULL_FACE);
00373         } else {
00374                 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00375                 glCullFace(GL_BACK);
00376                 glEnable(GL_CULL_FACE);
00377         }
00378 
00379         // clear buffers
00380         glClearColor(0.0, 0.0, 0.0, 0.0);
00381         glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
00382 
00383         // rotate
00384         m_angle += m_rot;
00385         m_viewer.setYRotation(m_angle * s_radiansPerDegree);
00386 
00387         // set up camera, viewer
00388         render_context_t rc;
00389         rc.viewport.left = 0;
00390         rc.viewport.top = 0;
00391         rc.viewport.right = w;
00392         rc.viewport.bottom = h;
00393         rc.camera.setAspect(w, h);
00394         rc.viewer = m_viewer;
00395 
00396         // set up glut for drawing
00397         setOpenGLProjection(rc.camera);
00398         setOpenGLViewer(rc.viewer);
00399 
00400         // set lighting
00401         this->setLighting();
00402 
00403         // let host know
00404         {
00405                 perf::Timer timer("host::display3D");
00406                 m_host->display3D(rc, m_rQueue);
00407         }
00408 
00409         // draw axes
00410         if (m_host->displayAxes()) {
00411                 glDisable(GL_LIGHTING);
00412                 glColor3f(0, 0, 1);
00413                 glBegin(GL_LINES);
00414                         glVertex3f(0, 1, 0);
00415                         glVertex3f(0, 2, 0);
00416                 glEnd();
00417 
00418                 glColor3f(1, 0, 0);
00419                 glBegin(GL_LINES);
00420                         glVertex3f(1, 0, 0);
00421                         glVertex3f(2, 0, 0);
00422                 glEnd();
00423 
00424                 glColor3f(0, 1, 0);
00425                 glBegin(GL_LINES);
00426                         glVertex3f(0, 0, 1);
00427                         glVertex3f(0, 0, 2);
00428                 glEnd();
00429         }
00430 
00431         // now draw any queued polygons (transparencies)
00432         glEnable(GL_BLEND);
00433         glEnable(GL_LIGHTING);
00434         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00435         glEnable(GL_TEXTURE_2D);
00436 
00437         // save and clear transformation matrix
00438         //   (queued vertices should be pre-transformed)
00439         glMatrixMode(GL_MODELVIEW);
00440         glPushMatrix();
00441         glLoadIdentity();
00442 
00443         // pop and draw all queued polygons
00444         if (m_host->displayQueuedPolys()) {
00445                 perf::Timer timer("queued polygons");
00446                 while (glut::poly_request_t * pr = m_rQueue->popRequest()) {
00447                         if (pr->nVertices < 3 || pr->textureId < 1) {
00448                                 DPRINTF("Skipping invalid request");
00449                                 continue;
00450                         }
00451 
00452                         // bind texture and normal
00453                         glBindTexture(GL_TEXTURE_2D, pr->textureId);
00454                         glNormal3fv((GLfloat *) &pr->normal.x);
00455 
00456                         // send vertices
00457                         glBegin(GL_POLYGON);
00458                         for (int i = 0; i < pr->nVertices; ++i) {
00459                                 glTexCoord2f(pr->u[i], pr->v[i]);
00460                                 glVertex3fv((GLfloat *) &pr->vertex[i].x);
00461                                 }
00462                         glEnd();
00463                 }
00464         }
00465 
00466         // done with queued polygons
00467         glDisable(GL_TEXTURE_2D);
00468         glDisable(GL_LIGHTING);
00469         glDisable(GL_LIGHT0);
00470         glDisable(GL_BLEND);
00471         glDisable(GL_CULL_FACE);
00472         glPopMatrix();
00473 
00474         // disable expensive 3D stuff
00475         glDisable(GL_DEPTH_TEST);
00476 
00477         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00478 
00479         // set up for 2D rendering
00480         perf::Timer timer2d("demo--2D drawing");
00481         push2D(w, h);
00482 
00483         // let host know
00484         {
00485                 perf::Timer timer("host::display2D");
00486                 m_host->display2D(w, h);
00487         }
00488 
00489         // render display lines
00490         glColor3f(1, 1, 1);
00491         int textHeight = 14;
00492         int lineSpace = 2;
00493         int lineHeight = textHeight + lineSpace;
00494         int rightMargin = 300;
00495         this->renderLines(1, lineHeight, lineHeight,
00496             DisplayLine::eTopLeft);
00497         this->renderLines(w - rightMargin, lineHeight, lineHeight,
00498             DisplayLine::eTopRight);
00499         this->renderLines(1, h - lineSpace, -lineHeight,
00500             DisplayLine::eBottomLeft);
00501         this->renderLines(w - rightMargin, h - lineSpace, -lineHeight,
00502             DisplayLine::eBottomRight);
00503 
00504         // clean up
00505         pop2D();
00506 }
00507 
00508 
00509 
00510 int
00511 Demo::shutdown
00512 (
00513 void
00514 )
00515 {
00516         // let the host know
00517         m_host->onShutdown();
00518 
00519         // close down
00520         m_demoTimer = NULL;
00521         perf::dumpTimingSummary(std::cerr);
00522         return 0;
00523 }
00524 
00525 
00526 
00527 Host::eBehavior
00528 Demo::mouseMove
00529 (
00530 IN int x,
00531 IN int y
00532 )
00533 {
00534         m_host->onCursor(x, y);
00535         return eContinue;
00536 }
00537 
00538 
00539 
00540 Host::eBehavior
00541 Demo::mouseButton
00542 (
00543 IN int button,
00544 IN int state,
00545 IN int x,
00546 IN int y
00547 )
00548 {
00549         m_host->onButton(button, state, x, y);
00550         return eContinue;
00551 }
00552 
00553 
00554 
00555 Host::eBehavior
00556 Demo::keyboard
00557 (
00558 IN int key,
00559 IN int mods
00560 )
00561 {
00562         switch (key) {
00563         case 'l':       m_light = (m_light + 1) % s_maxLighting;        break;
00564 
00565         case 'q':
00566         case 27:        // escape key
00567                 return eExit;
00568 
00569         case 'r':       m_rot += s_dRot;                                break;
00570 
00571         case 'R':       m_rot -= s_dRot;                                break;
00572 
00573         case 'w':       m_wireframe = !m_wireframe;                     break;
00574 
00575         case '+':
00576         case '=':
00577                         m_viewer.move(m_delta, 0, 0);                   break;
00578 
00579         case '-':
00580                         m_viewer.move(-m_delta, 0, 0);                  break;
00581         }
00582 
00583         // let the host take a look
00584         m_host->onKey(key, mods);
00585 
00586         // all done
00587         return eContinue;
00588 }
00589 
00590 
00591 
00592 Host::eBehavior
00593 Demo::specialKey
00594 (
00595 IN int key,
00596 IN int mods
00597 )
00598 {
00599         // DPRINTF("mods = %d = 0x%08x", mods, mods);
00600         bool shiftDown = (1 & mods);
00601 
00602         const float s_up = 0.03;        // radians
00603 
00604         switch (key) {
00605         case GLUT_KEY_UP:
00606                 if (shiftDown)
00607                         m_viewer.rotateUp(-s_up);
00608                 else
00609                         m_viewer.move(0, 0, m_delta);   
00610                 break;
00611         case GLUT_KEY_DOWN:
00612                 if (shiftDown)
00613                         m_viewer.rotateUp(+s_up);
00614                 else 
00615                         m_viewer.move(0, 0, -m_delta);
00616                 break;
00617         case GLUT_KEY_LEFT:     m_viewer.move(0, -m_delta, 0);          break;
00618         case GLUT_KEY_RIGHT:    m_viewer.move(0, m_delta, 0);           break;
00619         }
00620 
00621         return eContinue;
00622 }
00623 
00624 
00625 
00626 ////////////////////////////////////////////////////////////////////////////////
00627 //
00628 //      Demo -- private helper methods
00629 //
00630 ////////////////////////////////////////////////////////////////////////////////
00631 
00632 void
00633 Demo::setLighting
00634 (
00635 void
00636 )
00637 {
00638         // no lighting wanted?  quick exit...
00639         if (m_light < 1) {
00640                 glDisable(GL_LIGHTING);
00641                 glDisable(GL_LIGHT0);
00642                 glDisable(GL_LIGHT1);
00643                 return;
00644         }
00645 
00646         // some lighting is needed
00647         glEnable(GL_LIGHTING);
00648         glEnable(GL_LIGHT0);
00649         glShadeModel(GL_SMOOTH);
00650 
00651         // first light level: ambient white light
00652         float lightModelAmbient[] = { 0.2, 0.2, 0.2, 1.0 };
00653         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lightModelAmbient);
00654         if (m_light < 2)
00655                 return;         // that's enough
00656 
00657         // second light level
00658         glEnable(GL_LIGHT1);
00659         float lightDirection[] = { s_2, 0, s_2, 0 };
00660         glLightfv(GL_LIGHT1, GL_POSITION, lightDirection);
00661 
00662         float lightDiffuse[] = { 1, 1, 1, 1 };
00663         glLightfv(GL_LIGHT1, GL_DIFFUSE, lightDiffuse);
00664         glLightfv(GL_LIGHT1, GL_SPECULAR, lightDiffuse);
00665 
00666         float lightAmbient[] = { 0.2, 0, 0.2, 1 };
00667         glLightfv(GL_LIGHT1, GL_AMBIENT, lightAmbient);
00668 }
00669 
00670 
00671 
00672 void
00673 Demo::renderLines
00674 (
00675 IN int x,
00676 IN int y,
00677 IN int dy,
00678 IN DisplayLine::ePosition pos
00679 )
00680 {
00681         glut::Font * font = glut::getDefaultFont();
00682         for (vec_display_lines_t::iterator i = m_lines.begin();
00683              i != m_lines.end(); ++i) {
00684                 DisplayLine * pdl = *i;
00685                 ASSERT(pdl, "null display line in vector");
00686 
00687                 if (pdl->getPosition() != pos)
00688                         continue;       // line doesn't match position
00689 
00690                 const char * txt = pdl->getText();
00691                 font->display(x, y, 0, txt);
00692                 y += dy;
00693         }
00694 }
00695 
00696 
00697 
00698 ////////////////////////////////////////////////////////////////////////////////
00699 //
00700 //      DemoHost -- implementation
00701 //
00702 ////////////////////////////////////////////////////////////////////////////////
00703 
00704 DemoHost::~DemoHost(void)
00705 throw()
00706 {
00707 }
00708 
00709 
00710 
00711 ////////////////////////////////////////////////////////////////////////////////
00712 //
00713 //      public API
00714 //
00715 ////////////////////////////////////////////////////////////////////////////////
00716 
00717 void
00718 startDemo
00719 (
00720 IN int argc,
00721 IN const char * argv[],
00722 IN const char * title,
00723 IN DemoHost * host
00724 )
00725 {
00726         ASSERT(argc >= 0, "Bad argument count: %d", argc);
00727         IMPLIES(argc, argv, "null");
00728         ASSERT(title, "null");
00729         ASSERT(host, "null");
00730 
00731         // create a new Demo object to handle glut callbacks
00732         smart_ptr<Demo> demo = new Demo;
00733         THROW(demo, "out of memory");
00734         demo->initialize(host);
00735 
00736         int width = host->getWidth();
00737         int height = host->getHeight();
00738 
00739         // cast
00740         smart_ptr<Host> glutHost = demo;
00741         THROW(glutHost, "failed to downcast");
00742         glut::start(argc, argv, width, height, title, NULL, glutHost);
00743 }
00744 
00745 
00746 
00747 };      // glut namespace
00748