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-font/glut-font.h"
00039 #include "perf/perf.h"
00040 #include "util/date.h"
00041 #include "wave-glut/glut_2d.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         eBehavior tick(IN float dt);
00222         void display(IN int w, IN int h);
00223         eBehavior mouseMove(IN int x, IN int y);
00224         eBehavior mouseButton(IN int button, IN int state, IN int x, IN int y);
00225         eBehavior keyboard(IN int key, IN int mods);
00226         eBehavior specialKey(IN int key, IN int mods);
00227         int shutdown(void);
00228 
00229 private:
00230         // private helper methods ----------------------------------------------
00231         void setLighting(void);
00232         void renderLines(IN int x, IN int y, IN int dy,
00233                                 IN DisplayLine::ePosition pos);
00234 
00235         // private member data -------------------------------------------------
00236         DemoHost *              m_host;
00237         bool                    m_wireframe;    // render wireframe?
00238         int                     m_light;        // lighting level (0 - 2)
00239         float                   m_rot;          // rotations (degrees/frame)
00240         float                   m_angle;        // degrees, not radians
00241         float                   m_delta;
00242         Viewer                  m_viewer;
00243         vec_display_lines_t     m_lines;
00244         smart_ptr<glut::RenderQueue> m_rQueue;
00245         smart_ptr<perf::Timer>  m_demoTimer;
00246         smart_ptr<FpsDisplay>   m_fps;
00247         smart_ptr<WireDisplay>  m_wire;
00248         smart_ptr<LightingDisplay> m_lighting;
00249         smart_ptr<PositionDisplay> m_position;
00250         smart_ptr<RotateDisplay> m_rotate;
00251 };
00252 
00253 
00254 
00255 Demo::Demo(void)
00256 :
00257 m_host(NULL),
00258 m_wireframe(false),
00259 m_light(0),
00260 m_rot(0.0),
00261 m_angle(0.0)
00262 {
00263 }
00264 
00265 
00266 
00267 Demo::~Demo(void)
00268 throw()
00269 {
00270 }
00271 
00272 
00273 
00274 void
00275 Demo::initialize
00276 (
00277 IN DemoHost * host
00278 )
00279 {
00280         ASSERT(host, "null");
00281         m_host = host;
00282 
00283         m_demoTimer = new perf::Timer("glut demo overall timer");
00284         THROW(m_demoTimer, "null");
00285 
00286         m_viewer.setPosition(point3d_t(0, 0, -10));
00287 
00288         // get step size
00289         m_delta = host->getDelta();
00290         ASSERT(m_delta > 0.0, "Bad step size: %f", m_delta);
00291 
00292         // add our own display lines first
00293         m_fps = new FpsDisplay;
00294         THROW(m_fps, "out of memory");
00295         m_lines.push_back(m_fps);
00296 
00297         m_wire = new WireDisplay;
00298         THROW(m_wire, "out of memory");
00299         m_lines.push_back(m_wire);
00300 
00301         m_lighting = new LightingDisplay;
00302         THROW(m_lighting, "out of memory");
00303         m_lines.push_back(m_lighting);
00304 
00305         m_position = new PositionDisplay;
00306         THROW(m_position, "out of memory");
00307         m_lines.push_back(m_position);
00308 
00309         m_rotate = new RotateDisplay;
00310         THROW(m_rotate, "out of memory");
00311         m_lines.push_back(m_rotate);
00312 
00313         // append whatever the host wanted
00314         vec_display_lines_t lines;
00315         m_host->getDisplayLines(lines);
00316         m_lines.insert(m_lines.end(), lines.begin(), lines.end());
00317         DPRINTF("I have %d display lines", (int) m_lines.size());
00318 
00319         // set up rendering queue
00320         int nSlots = 1024;
00321         m_rQueue = glut::RenderQueue::create(nSlots);
00322         ASSERT(m_rQueue, "failed to create render queue");
00323 }
00324 
00325 
00326 
00327 ////////////////////////////////////////////////////////////////////////////////
00328 //
00329 //      Demo -- glut::Host class interface methods
00330 //
00331 ////////////////////////////////////////////////////////////////////////////////
00332 
00333 void
00334 Demo::init
00335 (
00336 void
00337 )
00338 {
00339         // let host do something
00340         m_host->onInit();
00341 }
00342 
00343 
00344 
00345 Host::eBehavior
00346 Demo::tick
00347 (
00348 IN float dt
00349 )
00350 {
00351         ASSERT(dt >= 0.0, "bad time delta between frames: %f seconds", dt);
00352 
00353         m_host->onIdle(dt);
00354 
00355         return eContinue;
00356 }
00357 
00358 
00359 
00360 void
00361 Demo::display
00362 (
00363 IN int w,
00364 IN int h
00365 )
00366 {
00367         perf::Timer timer("Demo::display");
00368         ASSERT(m_rQueue, "null");
00369 
00370         // convenient hook
00371         m_delta = m_host->getDelta();
00372 
00373         // set up for 3D rendering
00374         m_fps->tick();
00375         m_wire->setWireframe(m_wireframe);
00376         m_lighting->setLighting(m_light);
00377         m_rotate->setRotate(m_rot);
00378         m_position->setPosition(m_viewer.getPosition());
00379 
00380         // basic capabilities
00381         glEnable(GL_DEPTH_TEST);
00382         glFrontFace(GL_CCW);    // counter clockwise is front
00383 
00384         // wireframe?  or polygon?
00385         if (m_wireframe) {
00386                 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00387                 glColor3f(1.0, 1.0, 1.0);
00388                 glDisable(GL_CULL_FACE);
00389         } else {
00390                 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00391                 glCullFace(GL_BACK);
00392                 glEnable(GL_CULL_FACE);
00393         }
00394 
00395         // clear buffers
00396         glClearColor(0.0, 0.0, 0.0, 0.0);
00397         glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
00398 
00399         // rotate
00400         m_angle += m_rot;
00401         m_viewer.setYRotation(m_angle * s_radiansPerDegree);
00402 
00403         // set up camera, viewer
00404         render_context_t rc;
00405         rc.viewport.left = 0;
00406         rc.viewport.top = 0;
00407         rc.viewport.right = w;
00408         rc.viewport.bottom = h;
00409         rc.camera.setAspect(w, h);
00410         rc.viewer = m_viewer;
00411 
00412         // set up glut for drawing
00413         setOpenGLProjection(rc.camera);
00414         setOpenGLViewer(rc.viewer);
00415 
00416         // set lighting
00417         this->setLighting();
00418 
00419         // let host know
00420         {
00421                 perf::Timer timer("host::display3D");
00422                 m_host->display3D(rc, m_rQueue);
00423         }
00424 
00425         // draw axes
00426         if (m_host->displayAxes()) {
00427                 glDisable(GL_LIGHTING);
00428                 glColor3f(0, 0, 1);
00429                 glBegin(GL_LINES);
00430                         glVertex3f(0, 1, 0);
00431                         glVertex3f(0, 2, 0);
00432                 glEnd();
00433 
00434                 glColor3f(1, 0, 0);
00435                 glBegin(GL_LINES);
00436                         glVertex3f(1, 0, 0);
00437                         glVertex3f(2, 0, 0);
00438                 glEnd();
00439 
00440                 glColor3f(0, 1, 0);
00441                 glBegin(GL_LINES);
00442                         glVertex3f(0, 0, 1);
00443                         glVertex3f(0, 0, 2);
00444                 glEnd();
00445         }
00446 
00447         // now draw any queued polygons (transparencies)
00448         glEnable(GL_BLEND);
00449         glEnable(GL_LIGHTING);
00450         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00451         glEnable(GL_TEXTURE_2D);
00452 
00453         // save and clear transformation matrix
00454         //   (queued vertices should be pre-transformed)
00455         glMatrixMode(GL_MODELVIEW);
00456         glPushMatrix();
00457         glLoadIdentity();
00458 
00459         // pop and draw all queued polygons
00460         if (m_host->displayQueuedPolys()) {
00461                 perf::Timer timer("queued polygons");
00462                 while (glut::poly_request_t * pr = m_rQueue->popRequest()) {
00463                         if (pr->nVertices < 3 || pr->textureId < 1) {
00464                                 DPRINTF("Skipping invalid request");
00465                                 continue;
00466                         }
00467 
00468                         // bind texture and normal
00469                         glBindTexture(GL_TEXTURE_2D, pr->textureId);
00470                         glNormal3fv((GLfloat *) &pr->normal.x);
00471 
00472                         // send vertices
00473                         glBegin(GL_POLYGON);
00474                         for (int i = 0; i < pr->nVertices; ++i) {
00475                                 glTexCoord2f(pr->u[i], pr->v[i]);
00476                                 glVertex3fv((GLfloat *) &pr->vertex[i].x);
00477                                 }
00478                         glEnd();
00479                 }
00480         }
00481 
00482         // done with queued polygons
00483         glDisable(GL_TEXTURE_2D);
00484         glDisable(GL_LIGHTING);
00485         glDisable(GL_LIGHT0);
00486         glDisable(GL_BLEND);
00487         glDisable(GL_CULL_FACE);
00488         glPopMatrix();
00489 
00490         // disable expensive 3D stuff
00491         glDisable(GL_DEPTH_TEST);
00492 
00493         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00494 
00495         // set up for 2D rendering
00496         perf::Timer timer2d("demo--2D drawing");
00497         push2D(w, h);
00498 
00499         // let host know
00500         {
00501                 perf::Timer timer("host::display2D");
00502                 m_host->display2D(w, h);
00503         }
00504 
00505         // render display lines
00506         glColor3f(1, 1, 1);
00507         int textHeight = 14;
00508         int lineSpace = 2;
00509         int lineHeight = textHeight + lineSpace;
00510         int rightMargin = 300;
00511         this->renderLines(1, lineHeight, lineHeight,
00512             DisplayLine::eTopLeft);
00513         this->renderLines(w - rightMargin, lineHeight, lineHeight,
00514             DisplayLine::eTopRight);
00515         this->renderLines(1, h - lineSpace, -lineHeight,
00516             DisplayLine::eBottomLeft);
00517         this->renderLines(w - rightMargin, h - lineSpace, -lineHeight,
00518             DisplayLine::eBottomRight);
00519 
00520         // clean up
00521         pop2D();
00522 }
00523 
00524 
00525 
00526 int
00527 Demo::shutdown
00528 (
00529 void
00530 )
00531 {
00532         // let the host know
00533         m_host->onShutdown();
00534 
00535         // close down
00536         m_demoTimer = NULL;
00537         perf::dumpTimingSummary(std::cerr);
00538         return 0;
00539 }
00540 
00541 
00542 
00543 Host::eBehavior
00544 Demo::mouseMove
00545 (
00546 IN int x,
00547 IN int y
00548 )
00549 {
00550         m_host->onCursor(x, y);
00551         return eContinue;
00552 }
00553 
00554 
00555 
00556 Host::eBehavior
00557 Demo::mouseButton
00558 (
00559 IN int button,
00560 IN int state,
00561 IN int x,
00562 IN int y
00563 )
00564 {
00565         m_host->onButton(button, state, x, y);
00566         return eContinue;
00567 }
00568 
00569 
00570 
00571 Host::eBehavior
00572 Demo::keyboard
00573 (
00574 IN int key,
00575 IN int mods
00576 )
00577 {
00578         switch (key) {
00579         case 'l':       m_light = (m_light + 1) % s_maxLighting;        break;
00580 
00581         case 'q':
00582         case 27:        // escape key
00583                 return eExit;
00584 
00585         case 'r':       m_rot += s_dRot;                                break;
00586 
00587         case 'R':       m_rot -= s_dRot;                                break;
00588 
00589         case 'w':       m_wireframe = !m_wireframe;                     break;
00590 
00591         case '+':
00592         case '=':
00593                         m_viewer.move(m_delta, 0, 0);                   break;
00594 
00595         case '-':
00596                         m_viewer.move(-m_delta, 0, 0);                  break;
00597         }
00598 
00599         // let the host take a look
00600         m_host->onKey(key, mods);
00601 
00602         // all done
00603         return eContinue;
00604 }
00605 
00606 
00607 
00608 Host::eBehavior
00609 Demo::specialKey
00610 (
00611 IN int key,
00612 IN int mods
00613 )
00614 {
00615         // DPRINTF("mods = %d = 0x%08x", mods, mods);
00616         bool shiftDown = (1 & mods);
00617 
00618         const float s_up = 0.03;        // radians
00619 
00620         switch (key) {
00621         case GLUT_KEY_UP:
00622                 if (shiftDown)
00623                         m_viewer.rotateUp(-s_up);
00624                 else
00625                         m_viewer.move(0, 0, m_delta);   
00626                 break;
00627         case GLUT_KEY_DOWN:
00628                 if (shiftDown)
00629                         m_viewer.rotateUp(+s_up);
00630                 else 
00631                         m_viewer.move(0, 0, -m_delta);
00632                 break;
00633         case GLUT_KEY_LEFT:     m_viewer.move(0, -m_delta, 0);          break;
00634         case GLUT_KEY_RIGHT:    m_viewer.move(0, m_delta, 0);           break;
00635         }
00636 
00637         return eContinue;
00638 }
00639 
00640 
00641 
00642 ////////////////////////////////////////////////////////////////////////////////
00643 //
00644 //      Demo -- private helper methods
00645 //
00646 ////////////////////////////////////////////////////////////////////////////////
00647 
00648 void
00649 Demo::setLighting
00650 (
00651 void
00652 )
00653 {
00654         // no lighting wanted?  quick exit...
00655         if (m_light < 1) {
00656                 glDisable(GL_LIGHTING);
00657                 glDisable(GL_LIGHT0);
00658                 glDisable(GL_LIGHT1);
00659                 return;
00660         }
00661 
00662         // some lighting is needed
00663         glEnable(GL_LIGHTING);
00664         glEnable(GL_LIGHT0);
00665         glShadeModel(GL_SMOOTH);
00666 
00667         // first light level: ambient white light
00668         float lightModelAmbient[] = { 0.2, 0.2, 0.2, 1.0 };
00669         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lightModelAmbient);
00670         if (m_light < 2)
00671                 return;         // that's enough
00672 
00673         // second light level
00674         glEnable(GL_LIGHT1);
00675         float lightDirection[] = { s_2, 0, s_2, 0 };
00676         glLightfv(GL_LIGHT1, GL_POSITION, lightDirection);
00677 
00678         float lightDiffuse[] = { 1, 1, 1, 1 };
00679         glLightfv(GL_LIGHT1, GL_DIFFUSE, lightDiffuse);
00680         glLightfv(GL_LIGHT1, GL_SPECULAR, lightDiffuse);
00681 
00682         float lightAmbient[] = { 0.2, 0, 0.2, 1 };
00683         glLightfv(GL_LIGHT1, GL_AMBIENT, lightAmbient);
00684 }
00685 
00686 
00687 
00688 void
00689 Demo::renderLines
00690 (
00691 IN int x,
00692 IN int y,
00693 IN int dy,
00694 IN DisplayLine::ePosition pos
00695 )
00696 {
00697         glut::Font * font = glut::getDefaultFont();
00698         for (vec_display_lines_t::iterator i = m_lines.begin();
00699              i != m_lines.end(); ++i) {
00700                 DisplayLine * pdl = *i;
00701                 ASSERT(pdl, "null display line in vector");
00702 
00703                 if (pdl->getPosition() != pos)
00704                         continue;       // line doesn't match position
00705 
00706                 const char * txt = pdl->getText();
00707                 font->display(x, y, 0, txt);
00708                 y += dy;
00709         }
00710 }
00711 
00712 
00713 
00714 ////////////////////////////////////////////////////////////////////////////////
00715 //
00716 //      DemoHost -- implementation
00717 //
00718 ////////////////////////////////////////////////////////////////////////////////
00719 
00720 DemoHost::~DemoHost(void)
00721 throw()
00722 {
00723 }
00724 
00725 
00726 
00727 ////////////////////////////////////////////////////////////////////////////////
00728 //
00729 //      public API
00730 //
00731 ////////////////////////////////////////////////////////////////////////////////
00732 
00733 void
00734 startDemo
00735 (
00736 IN int argc,
00737 IN const char * argv[],
00738 IN const char * title,
00739 IN DemoHost * host
00740 )
00741 {
00742         ASSERT(argc >= 0, "Bad argument count: %d", argc);
00743         IMPLIES(argc, argv, "null");
00744         ASSERT(title, "null");
00745         ASSERT(host, "null");
00746 
00747         // create a new Demo object to handle glut callbacks
00748         smart_ptr<Demo> demo = new Demo;
00749         THROW(demo, "out of memory");
00750         demo->initialize(host);
00751 
00752         int width = host->getWidth();
00753         int height = host->getHeight();
00754 
00755         // cast
00756         smart_ptr<Host> glutHost = demo;
00757         THROW(glutHost, "failed to downcast");
00758         glut::start(argc, argv, width, height, title, NULL, glutHost);
00759 }
00760 
00761 
00762 
00763 };      // glut namespace
00764