home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / demos / audio / drive / Driver.c++ < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  21.9 KB  |  1,036 lines

  1. /*
  2.  * Copyright 1992-1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /////////////////////////////////////////////////////////////////////
  18. //
  19. // Driver.c++ - implementation of the driver class
  20. //
  21. // Driver is the interface to the user. It receives user
  22. // input and displays output.
  23. //
  24. //////////////////////////////////////////////////////////////////////
  25.  
  26. #include <Inventor/SbTime.h>
  27. #include <Inventor/SbPList.h>
  28. #include <gl/gl.h>
  29. #include <gl/device.h>
  30. #include <gl/qcontrol.h>
  31. #include "Simulation.h"
  32. #include "Car.h"
  33. #include "Cockpit.h"
  34. #include "Engine.h"
  35. #include "Road.h"
  36. #include "Stretch.h"
  37. #include "Dynamics.h"
  38. #include "Driver.h"
  39. #include "Render.h"
  40. #include "Noise.h"
  41. #include "Keys.h"
  42. #include "Scenery.h"
  43. #include "Timer.h"
  44. #include "Help.h"
  45.  
  46. // Moving the mouse to the edge of the window is like turning
  47. // the steering wheel this many degrees
  48. const float EDGE_DEGREES = 180.0;
  49.  
  50. // frames behind the car that the helicopter lags
  51. const int HELICOPTER_LAG = 10;
  52.  
  53. // different views
  54. const int DRIVER = 0;
  55. const int HELICOPTER = 1;
  56.  
  57. Driver::Driver(Car *c)
  58. {
  59.     _car = c;
  60.  
  61.     open(); // open a window that the driver can see out of
  62.  
  63.     init_devices(); // initializes input devices
  64.  
  65.     init_render(); // initialize lighting, colors, etc.
  66.     
  67.     // must come after open() since does some GL
  68.     _cockpit = new Cockpit(_car);
  69.  
  70.     // each driver does her own timing
  71.     _timer = new Timer;
  72.     _timer->reset();
  73.     _first_timing = TRUE;
  74.  
  75.     // initialize view
  76.     _display.view = DRIVER;
  77.  
  78.     // initialize helicopter
  79.     _helio_offset.setValue(0.0,-10.0,-30.0); // from car
  80.     _helio_lag = (int)(0.1*_fps); // lag in seconds
  81.     _helio_orientation = new SbMatrix[_helio_lag]; // allocate the list
  82.     _helio_position = new SbVec3f[_helio_lag];
  83.     reset_helicopter();
  84.     
  85.     // keep going till we're outta here
  86.     _done = FALSE;
  87.  
  88.     // only if they ask for it
  89.     _helping = FALSE;
  90.  
  91.     _display.drawStyle = RENDER_FILLED;
  92.     _display.flags = FALSE;
  93.     _display.fog = FALSE;
  94.  
  95.     // nice grey on hollywood: r=224, g=224, b=208
  96.     _display.fog_params[0] = .005;
  97.     _display.fog_params[1] = 224./255.;
  98.     _display.fog_params[2] = 224./255.;
  99.     _display.fog_params[3] = 208./255.;
  100.  
  101.     _cranking = FALSE;
  102.     _crashed = FALSE;
  103.     _crash_handled = FALSE;
  104.     _broken_winshield = FALSE;
  105.  
  106.     // i love the sound of breaking glass
  107.     if (_car->get_simulation()->sound_capable())
  108.     {
  109.         SbString crashpath(_car->get_simulation()->get_path().getString());
  110.         SbString crashfile("crash.aiff");
  111.         crashpath += crashfile;
  112.         
  113.         _crash_noise = readsample(crashpath.getString());
  114.     }
  115.     else
  116.         _crash_noise = NULL;
  117.  
  118.     // save old key warp params and set new ones
  119.     // need this to prevent keyboard repeat
  120.     qcontrol(QC_GETKEYWARP, 0, (short *)NULL, 2, _old_keywarp);
  121.     short new_keywarp[2];
  122.     new_keywarp[0] = 1000;
  123.     new_keywarp[1] = 1000;
  124.     qcontrol(QC_SETKEYWARP, 2, new_keywarp, 0, (short *)NULL);
  125. }
  126.  
  127.  
  128. Driver::~Driver()
  129. {
  130.     // clear the overlay crap
  131.     _cockpit->clear_indicators();
  132.     
  133.     delete _cockpit;
  134. //    delete [_helio_lag] _helio_orientation;
  135. //    delete [_helio_lag] _helio_position;
  136.     delete [] _helio_orientation;
  137.     delete [] _helio_position;
  138.  
  139.     if (_crash_noise)
  140.         freesample(_crash_noise);
  141.  
  142.     // reset key repeat to original values
  143.     qcontrol(QC_SETKEYWARP, 2, _old_keywarp, 0, (short *)NULL);
  144. }
  145.  
  146.  
  147. void Driver::open()
  148. {
  149.     // open parent window
  150.     _parent_win.xmax = getgdesc(GD_XPMAX);
  151.     _parent_win.ymax = getgdesc(GD_YPMAX);
  152.  
  153.     long left = _parent_win.xmax/3 - 50;
  154.     long right = _parent_win.xmax - 1 - 50;
  155.     long bottom = _parent_win.ymax/3 - 50;
  156.     long top = _parent_win.ymax - 1 - 50;
  157.  
  158.     _parent_win.aspect = 1.0/(1.0 - COCKPIT_TOP);
  159.     _parent_win.sizex = right - left;
  160.     _parent_win.sizey = top - bottom;
  161.  
  162. #ifdef DEBUG    
  163.     foreground();
  164. #endif
  165.     
  166.     prefposition(left,right,bottom,top);
  167.     _parent_win.wid = winopen("Backseat Driver");
  168.     icontitle("Driver");
  169.     color(0); clear(); // clear the muck
  170.     keepaspect(_parent_win.xmax, _parent_win.ymax);
  171.     winconstraints();
  172.  
  173.     // open out-the-window view subwindow, double buffered
  174.     _view_win.wid = swinopen(_parent_win.wid);
  175.     doublebuffer();
  176.     RGBmode();
  177.     gconfig();
  178.     mmode(MVIEWING);
  179.  
  180.     // open cockpit subwindow, single buffered
  181.     _cockpit_win.wid = swinopen(_parent_win.wid);
  182.     RGBmode();
  183.     gconfig();
  184.     mmode(MVIEWING);
  185.  
  186.     // force initial redraw by inserting REDRAW into
  187.     // event queue, not by explicity drawing. This allows
  188.     // a chance to read window info (size, position, etc)
  189.     _redraw_cockpit = _redraw_view = FALSE;
  190.     qenter(REDRAW,(short)_parent_win.wid);
  191.  
  192.     char gstring[12]; // hah hah
  193.     gversion(gstring);
  194.     gstring[6] = (char)NULL;
  195.  
  196.     // set up hardware dependent things
  197.     // take an initial guess at fps, it will get updated as soon
  198.     // as the rendering loop starts
  199.  
  200.     _max_fps = _fps = 60.0;
  201.     _last_frame_time = 125000; // usecs
  202.     _display.zbuffer = FALSE;
  203.     
  204.     if (strcmp( &gstring[4], "PI") == 0)
  205.     {
  206.         // fprintf(stderr,"On a PI, using shademodel(FLAT)\n");
  207.         // fprintf(stderr,"On a PI\n");
  208.         subpixel(FALSE);
  209.     }
  210.     else if (strcmp( &gstring[4], "VG") == 0)
  211.     {
  212.         // fprintf(stderr,"On a VGX, using subpixel(TRUE)\n");
  213.         subpixel(TRUE);
  214.     }
  215.     else if (strcmp( &gstring[4], "GT") == 0)
  216.     {
  217.         // fprintf(stderr,"On a GTX\n");
  218.     }
  219.     else if (strcmp( &gstring[4], "LG") == 0)
  220.     {
  221.         // fprintf(stderr,"On an LG, using subpixel(TRUE)\n");
  222.         subpixel(TRUE);
  223.         shademodel(FLAT);
  224.         _display.zbuffer = FALSE; // XXX SW zbuffer just ain't fast    enough
  225.     }
  226.     else
  227.         // fprintf(stderr,"On unknown graphics\n");
  228.         subpixel(TRUE);
  229.     
  230.     _parent_win.zmin = getgdesc(GD_ZMIN);
  231.     _parent_win.zmax = getgdesc(GD_ZMAX);
  232.  
  233.     winset(_view_win.wid);
  234.     zbuffer(_display.zbuffer && (_display.drawStyle == RENDER_FILLED));
  235.     backface(_display.drawStyle == RENDER_FILLED);
  236. }
  237.  
  238.  
  239. void Driver::init_devices()
  240. {
  241.     // express interest in user devices
  242.     qdevice(GAS);
  243.     qdevice(BRAKES);
  244.     qdevice(CLUTCH);
  245.     qdevice(STEERING);
  246.  
  247.     qdevice(VIEWKEY);
  248.     qdevice(DISPLAYKEY);
  249.     // qdevice(FLAGKEY);
  250.     qdevice(SOUNDKEY);
  251.     qdevice(IGNITIONKEY);
  252.     qdevice(RESETKEY);
  253.     qdevice(HELPKEY);
  254.     qdevice(FOGKEY);
  255.     // qdevice(NIGHTKEY);
  256.  
  257.     // qdevice(REVERSE);
  258.     qdevice(NEUTRAL);
  259.     qdevice(FIRST);
  260.     qdevice(SECOND);
  261.     qdevice(THIRD);
  262.     qdevice(FOURTH);
  263.     qdevice(FIFTH);
  264.  
  265.     qdevice(UPSHIFTKEY);
  266.     qdevice(DOWNSHIFTKEY);
  267.     
  268.     qdevice(QUITKEY);
  269.     qdevice(WINQUIT);
  270.     qdevice(WINSHUT);
  271.     qdevice(WINCLOSE);
  272. }
  273.  
  274.  
  275. void Driver::reshape_subwindow(long wid)
  276. {
  277.     if (wid == _cockpit_win.wid)
  278.     {
  279.         _cockpit_win.left = 0;
  280.         _cockpit_win.right = _parent_win.sizex-1;
  281.         _cockpit_win.bottom = 0;
  282.         _cockpit_win.top = (long)(COCKPIT_TOP*(float)_parent_win.sizey);
  283.  
  284.         _cockpit_win.sizex = _cockpit_win.right - _cockpit_win.left + 1;
  285.         _cockpit_win.sizey = _cockpit_win.top - _cockpit_win.bottom + 1;
  286.         _cockpit_win.orgx = _cockpit_win.left;
  287.         _cockpit_win.orgy = _cockpit_win.bottom;
  288.  
  289.         winset(_cockpit_win.wid);
  290.         winposition(
  291.             _cockpit_win.left,_cockpit_win.right,
  292.             _cockpit_win.bottom,_cockpit_win.top);
  293.         
  294.         reshapeviewport();
  295.     }
  296.     else if (wid == _view_win.wid)
  297.     {
  298.         // will be positioned by the REDRAW
  299.         // limits relative to parent window
  300.         _view_win.left = 0;
  301.         _view_win.right = _parent_win.sizex-1;
  302.         _view_win.bottom = (long)(COCKPIT_TOP*(float)_parent_win.sizey) + 1;
  303.         _view_win.top = _parent_win.sizey - 1;
  304.         
  305.         _view_win.sizex = _view_win.right - _view_win.left + 1;
  306.         _view_win.sizey = _view_win.top - _view_win.bottom + 1;
  307.         _view_win.orgx = _view_win.left;
  308.         _view_win.orgy = _view_win.bottom;
  309.  
  310.         winset(_view_win.wid);
  311.         winposition(
  312.             _view_win.left,_view_win.right,
  313.             _view_win.bottom,_view_win.top);
  314.         reshapeviewport();
  315.     }
  316. }
  317.  
  318.  
  319.  
  320. void Driver::event(long dev, short val)
  321. {
  322.     switch (dev)
  323.     {
  324.         case REDRAW:
  325.             // clear the overlay crap
  326.             winset(_view_win.wid);
  327.             _cockpit->clear_indicators();
  328.  
  329.             // get new size and position info
  330.             winset(_parent_win.wid);
  331.             getorigin(&_parent_win.orgx, &_parent_win.orgy);
  332.             getsize(&_parent_win.sizex,&_parent_win.sizey);
  333.             reshapeviewport();
  334.                 
  335.             if (val == _parent_win.wid)
  336.             {
  337.                 _redraw_cockpit = _redraw_view = TRUE;
  338.                 reshape_subwindow(_cockpit_win.wid);
  339.                 reshape_subwindow(_view_win.wid);
  340.             }            
  341.             else if (val == _cockpit_win.wid)
  342.             {
  343.                 _redraw_cockpit =  TRUE;
  344.                 reshape_subwindow(val);
  345.             }
  346.             else if (val == _view_win.wid)
  347.             {
  348.                 _redraw_view =  TRUE;
  349.                 reshape_subwindow(val);
  350.             }
  351.             
  352.             break;
  353.  
  354.         case INPUTCHANGE:
  355.             if (val)
  356.                 init_colormaps();
  357.             break;
  358.             
  359.         case CLUTCH:
  360.             _cockpit->set_clutch((float)val);
  361.             break;
  362.  
  363.         case BRAKES:
  364.             _cockpit->set_brakes((float)val);
  365.  
  366.             break;
  367.  
  368.         case GAS:
  369.             _cockpit->set_gas((float)val);
  370.                 
  371.             break;
  372.                 
  373.         case STEERING:
  374.             // scale mouse val, -1.0 to 1.0
  375.             _mouse_x =
  376.                 2.0*((float)(val - _parent_win.orgx)/
  377.                 (float)_parent_win.sizex) - 1.0;
  378.  
  379.             // edges window corresponds to an EDGE_DEGREES degree turn
  380.             // steering is positive clockwise
  381.             // steering is saved as radians
  382.             _cockpit->set_steering(EDGE_DEGREES * M_PI/180.0 * _mouse_x);
  383.             
  384.             break;
  385.  
  386.         case VIEWKEY:
  387.             if (val)
  388.             {
  389.                 if (_display.view == HELICOPTER)
  390.                     _display.view = DRIVER;
  391.                 else
  392.                     _display.view = HELICOPTER;
  393.  
  394.                 _redraw_view = TRUE;
  395.             }
  396.             break;
  397.  
  398.         case DISPLAYKEY:
  399.             if (val)
  400.             {
  401.                 if (_display.drawStyle == RENDER_FILLED)
  402.                     _display.drawStyle = RENDER_WIREFRAME;
  403.                 else
  404.                     _display.drawStyle = RENDER_FILLED;
  405.  
  406.                 
  407.                 const SbPList *car_list=_car->get_simulation()->get_car_list();
  408.                 for (int i = 0; i < car_list->length(); i++)
  409.                 {
  410.                     Car * car = (Car *)(* car_list)[i];
  411.                     car->setDrawStyle(_display.drawStyle);
  412.                 }
  413.                 
  414.                 _redraw_view = TRUE;
  415.                 
  416.                 zbuffer(_display.zbuffer && (_display.drawStyle == RENDER_FILLED));
  417.                 backface(_display.drawStyle == RENDER_FILLED);
  418.             }
  419.  
  420.             break;
  421.  
  422. /*
  423.         case FLAGKEY:
  424.             if (val)
  425.             {
  426.                 _display.flags = ! _display.flags;
  427.                 _redraw_view = TRUE;
  428.             }
  429.             break;
  430. */
  431.  
  432.         case SOUNDKEY:
  433.             if (val)
  434.                 _car->get_engine()->set_sound(
  435.                     _car->get_simulation()->toggle_sound());
  436.             break;
  437.  
  438.         case FOGKEY:
  439.             if (val)
  440.             {
  441.                 _display.fog = ! _display.fog;
  442.                 if (_display.fog)
  443.                 {
  444.                     winset(_view_win.wid);
  445.                     fogvertex(FG_VTX_EXP,_display.fog_params);
  446.                     fogvertex(FG_ON,(float *)NULL);
  447.                 }
  448.                 else
  449.                 {
  450.                     winset(_view_win.wid);
  451.                     fogvertex(FG_OFF,(float *)NULL);
  452.                 }
  453.             
  454.                 _redraw_view = TRUE;
  455.             }
  456.             break;
  457.  
  458.         case RESETKEY:
  459.             if (val)
  460.                 reset_all();
  461.  
  462.             break;
  463.  
  464.         case HELPKEY:
  465.             if (val)
  466.             {
  467.                 qdevice(KEYBD);
  468.                 _timer->stop();
  469.                 _helping = TRUE;
  470.                 _redraw_view = TRUE;
  471.             }
  472.  
  473.             break;
  474.  
  475.         case KEYBD:
  476.             _helping = FALSE;
  477.             unqdevice(KEYBD);
  478.             _redraw_view = TRUE;
  479.             if (! _first_timing)
  480.                 _timer->start();
  481.             break;
  482.  
  483.         case IGNITIONKEY:
  484.             // beware of keyboard repeat
  485.             if ((_cranking && (!val)) || ((!_cranking) && val))
  486.             {
  487.                 _cranking = val;
  488.  
  489.                 // move to beginning
  490.                 // Go to neutral - drivers never remember
  491.                 if (val && _crashed)
  492.                 {
  493.                     // remove the car from the stretch it
  494.                     // was on
  495.                     _car->get_dynamics()->get_stretch(BACK)->remove_car(_car);
  496.  
  497.                     // and put it back to the beginning.
  498.                     // (reset_to_start adds the car to
  499.                     // the stretch)
  500.                     _car->get_dynamics()->reset_to_start(
  501.                         _car->get_dynamics()->get_stretch(BACK),
  502.                         RIGHT);
  503.                         
  504.                     _car->get_engine()->set_gear(0);
  505.  
  506.                     _broken_winshield = FALSE;
  507.                     _crashed = FALSE;
  508.  
  509.                     _redraw_view = TRUE;
  510.  
  511.                     // put helicopter back where car is
  512.                     reset_helicopter();
  513.                 }
  514.                     
  515.             }
  516.             break;
  517.  
  518.         /*
  519.         case REVERSE:
  520.             if (val)
  521.                 _car->get_engine()->set_gear(-1);
  522.             break;
  523.         */
  524.         
  525.         case NEUTRAL:
  526.             if (val)
  527.                 _car->get_engine()->set_gear(0);
  528.             break;
  529.  
  530.         case FIRST:
  531.             if (val)
  532.                 _car->get_engine()->set_gear(1);
  533.             break;
  534.             
  535.         case SECOND:
  536.             if (val)
  537.                 _car->get_engine()->set_gear(2);
  538.             break;
  539.             
  540.         case THIRD:
  541.             if (val)
  542.                 _car->get_engine()->set_gear(3);
  543.             break;
  544.             
  545.         case FOURTH:
  546.             if (val)
  547.                 _car->get_engine()->set_gear(4);
  548.             break;
  549.             
  550.         case FIFTH:
  551.             if (val)
  552.                 _car->get_engine()->set_gear(5);
  553.             break;
  554.  
  555.         case UPSHIFTKEY:
  556.             if (val)
  557.                 _car->get_engine()->upshift();
  558.             break;
  559.         
  560.         case DOWNSHIFTKEY:
  561.             if (val)
  562.                 _car->get_engine()->downshift();
  563.             break;
  564.         
  565.         case WINQUIT:
  566.         case WINCLOSE:
  567.         case WINSHUT:
  568.             _done = TRUE;
  569.             break;
  570.         
  571.         case QUITKEY:
  572.             if (! val)
  573.                 _done = TRUE;
  574.             break;
  575.     }
  576. }
  577.  
  578.  
  579. void Driver::draw_flags()
  580. {
  581.     const SbPList *car_list=_car->get_simulation()->get_car_list();
  582.     
  583.     for (int i = 0; i < car_list->length(); i++)
  584.     {
  585.         Car * car = (Car *)(* car_list)[i];
  586.  
  587.         SbVec3f flag[2];
  588.  
  589.         for (int end = BACK; end <= FRONT; end++)
  590.         {
  591.             if (end == FRONT)
  592.                 cpack(0xFFFFFF);
  593.             else
  594.                 cpack(0xFF);
  595.                             
  596.             flag[0] = flag[1] = 
  597.                 car->get_dynamics()->get_position(end);
  598.                         
  599.             flag[1][1] += 5.0;
  600.             bgnline();
  601.                 v3f((float *)flag[0].getValue());
  602.                 v3f((float *)flag[1].getValue());
  603.             endline();
  604.  
  605.             if (car->get_type() == LOCAL_CAR)
  606.                 for (int side = LEFT; side <= RIGHT; side++)
  607.                 {
  608.                     flag[0] = flag[1] = 
  609.                     car->get_dynamics()->get_flag(side, end);
  610.                         
  611.                     flag[1][1] += 5.0;
  612.  
  613.                     bgnline();
  614.                         v3f((float *)flag[0].getValue());
  615.                         v3f((float *)flag[1].getValue());
  616.                     endline();
  617.                 }
  618.         }
  619.  
  620.         for (int side = LEFT; side <= RIGHT; side++)
  621.         {
  622.             flag[0] = flag[1] = 
  623.             car->get_dynamics()->get_side_position(side);
  624.                         
  625.             flag[1][1] += 5.0;
  626.  
  627.             bgnline();
  628.                 v3f((float *)flag[0].getValue());
  629.                 v3f((float *)flag[1].getValue());
  630.             endline();
  631.         }
  632.  
  633.         // draw flag at car center
  634.         flag[0] = flag[1] = 
  635.         car->get_dynamics()->get_car_position();
  636.                 
  637.         flag[1][1] += 5.0;
  638.  
  639.         cpack(0xFFFFFF);
  640.         bgnline();
  641.             v3f((float *)flag[0].getValue());
  642.             v3f((float *)flag[1].getValue());
  643.         endline();
  644.     }
  645. }
  646.  
  647.  
  648.  
  649. void Driver::draw_view()
  650. {
  651.     if (_display.drawStyle == RENDER_FILLED)
  652.     {
  653.         if (! _display.fog)
  654.         {
  655.             if (_display.zbuffer)
  656.                 czclear(SKY_COL,_parent_win.zmax);
  657.             else
  658.             {
  659.                 cpack(SKY_COL);
  660.                 clear();
  661.             }
  662.         }
  663.         else
  664.         {
  665.             c3f(&_display.fog_params[1]);
  666.             clear();
  667.             if (_display.zbuffer)
  668.                 zclear();
  669.         }
  670.     }
  671.     else
  672.     {
  673.         cpack(0);
  674.         clear();
  675.     }
  676.  
  677.     pushmatrix();
  678.         // set the viewing xform
  679.         set_view();
  680.  
  681. /*
  682.         // XXX kills the frame rate -- need a better terrain
  683.         // model
  684.         // use a very far far so the mountains don't get clipped
  685.         perspective(450, _parent_win.aspect, 1.0, 4000.0);
  686.  
  687.         // XXX Ooooh. I just love cheap hacks.
  688.         if (_display.drawStyle == RENDER_FILLED)
  689.             draw_mountains(
  690.             _car->get_dynamics()->get_yaw(),
  691.             2000.0, 45.0*_parent_win.aspect*M_PI/180.0);
  692. */
  693.  
  694.         // back to something reasonable
  695.         perspective(450, _parent_win.aspect, 1.0, 500.0);
  696.             
  697.         // the sun is in world coords, so bind after viewing xform
  698.         if (_display.drawStyle == RENDER_FILLED)
  699.         {
  700.             lmbind(LMODEL,1);
  701.             lmbind(LIGHT0,SUN);
  702.         }
  703.  
  704.         if (_display.view == HELICOPTER)
  705.         {
  706.             // draw the road starting with the stretch one before the one
  707.             // the car is on
  708.             _car->get_road()->draw(
  709.                 _car->get_dynamics()->get_stretch(BACK)->get_prev(),
  710.                 0,
  711.                 _display.drawStyle,
  712.                 (Car *)NULL); // draw all cars including mine
  713.  
  714.             if (_display.drawStyle == RENDER_FILLED)
  715.             {
  716.                 lmbind(LMODEL,1);
  717.                 lmbind(LIGHT0,SUN);
  718.             }
  719.         }
  720.         else
  721.         {
  722.             // draw the road starting with the stretch the 
  723.             // the car is on
  724.             _car->get_road()->draw(
  725.                 _car->get_dynamics()->get_stretch(BACK), 
  726.                 _car->get_dynamics()->get_marker(BACK), 
  727.                 _display.drawStyle,
  728.                 (Car *) _car); // draw all cars except mine
  729.         }
  730.  
  731.         if (_display.flags)
  732.             draw_flags();
  733.                 
  734.     popmatrix();
  735.     
  736.     // hood is drawn relative to eye position
  737.     if (_display.view == DRIVER)
  738.         _cockpit->draw_hood(_display.drawStyle);
  739.  
  740.     if (_broken_winshield)
  741.         draw_crash();
  742. }
  743.  
  744.  
  745. void Driver::draw() 
  746. {
  747.     if (_redraw_view)
  748.     {
  749.         winset(_view_win.wid);
  750.  
  751.         if (_helping)
  752.             draw_help(_parent_win.sizex, _parent_win.sizey);
  753.         else
  754.             draw_view();
  755.             
  756.  
  757.         swapbuffers();
  758.     }
  759.     
  760.     winset(_cockpit_win.wid);
  761.  
  762.     if (_redraw_cockpit) // only draw static portions if necessary
  763.         _cockpit->draw_cockpit((int)_cockpit_win.sizex);
  764.  
  765.     // indicators get drawn in the pup planes
  766.     _cockpit->draw_indicators(FALSE);
  767. }
  768.  
  769.  
  770. // XXX Use Inventor camera positioning
  771. void Driver::set_view()
  772. {
  773.     SbMatrix orientation;
  774.  
  775.     // turn the quaternion into a rotation matrix
  776.     _car->get_dynamics()->get_view_orientation().getValue(orientation);
  777.  
  778.     const SbVec3f car_pos = _car->get_dynamics()->get_car_position();
  779.     const SbVec3f eye_pos = _car->get_dynamics()->get_eye_position();
  780.     
  781.  
  782.     // if first time, fill up the circular buffer
  783.     if (_helio_fill_index == _helio_use_index)
  784.     {
  785.         for (int i = 0; i < _helio_lag; i++)
  786.         {
  787.             _helio_orientation[_helio_fill_index] = orientation;
  788.             _helio_position[_helio_fill_index++] = - car_pos - eye_pos;
  789.         }
  790.  
  791.         _helio_use_index = 0;
  792.         _helio_fill_index = _helio_lag - 1;
  793.     }
  794.  
  795.     _helio_orientation[_helio_fill_index] = orientation;
  796.     _helio_position[_helio_fill_index++] = - car_pos - eye_pos;
  797.     _helio_fill_index %= _helio_lag;
  798.     
  799.     if (_display.view == HELICOPTER)
  800.     {
  801.         rotate(184,'x');
  802.         translate(_helio_offset[0], _helio_offset[1], _helio_offset[2]);
  803.  
  804.         multmatrix((Matrix) &_helio_orientation[_helio_use_index][0][0]);
  805.         translate(_helio_position[_helio_use_index][0],
  806.                   _helio_position[_helio_use_index][1],
  807.                   _helio_position[_helio_use_index][2]);
  808.     }
  809.     else // _display.view == DRIVER
  810.     {
  811.         multmatrix((Matrix) &orientation[0][0]);
  812.         translate(-car_pos[0], -car_pos[1], -car_pos[2]);
  813.         translate(-eye_pos[0], -eye_pos[1], -eye_pos[2]);
  814.     }
  815.  
  816.     // increment even if not used so helicopter doesn't sit still
  817.     // when view first invoked
  818.     _helio_use_index = (_helio_use_index + 1)%_helio_lag;
  819.  
  820. }
  821.  
  822.  
  823. void Driver::reset_helicopter()
  824. {
  825.     // set the circular list pointers to the same place
  826.     // this makes the list empty, and puts the helicopter right
  827.     // behind the car
  828.     _helio_fill_index = _helio_use_index = 0;
  829. }
  830.  
  831.  
  832. void Driver::reset_all()
  833. {
  834.     _helio_fill_index = _helio_use_index = 0; // in circular list
  835.     
  836.     _cranking = FALSE;
  837.     _crashed = FALSE;
  838.     _crash_handled = FALSE;
  839.     _broken_winshield = FALSE;
  840.  
  841.     _car->get_engine()->reset_all();
  842.  
  843.     // remove the car from the stretch it is on
  844.     _car->get_dynamics()->get_stretch(BACK)->remove_car(_car);
  845.  
  846.     // and put it back to the beginning
  847.     _car->get_dynamics()->reset_to_start(_car->get_road()->get_start(), RIGHT);
  848.  
  849.     _redraw_view = TRUE;
  850.  
  851.     _timer->reset();
  852.     _first_timing = TRUE;
  853. }
  854.  
  855.  
  856. void Driver::handle_crash()
  857. {
  858.     _car->get_engine()->stall(FALSE); // don't play stalling noise
  859.     
  860.     if (_car->get_simulation()->play_sound())
  861.         playsample(_crash_noise);
  862.  
  863.     _crash_handled = TRUE;
  864. }
  865.  
  866.  
  867. // draw the windshield breaking
  868. void Driver::draw_crash()
  869. {
  870.     const int LEGS = 10;
  871.     const float WANDER = 5.0;
  872.     float a[2], b[2];
  873.  
  874.     ortho2(-.5,.5,-.5,.5);
  875.  
  876.     srand48(0); // make the windshield always look the same
  877.  
  878.     float theta = 0.0;
  879.     
  880.     for (int leg = 0; leg < LEGS; leg++)
  881.     {
  882.         a[0] = a[1] = 0.0;
  883.         for (float r = .1; r <= 0.75; r += .1)
  884.         {
  885.             b[0] = r*fcos(theta) + (drand48()-.5)/WANDER;
  886.             b[1] = r*fsin(theta) + (drand48()-.5)/WANDER;
  887.  
  888.             cpack(0xFFFFFF);
  889.             bgnline(); v2f(a); v2f(b); endline();
  890.  
  891.             a[0] = b[0]; a[1] = b[1];
  892.         }
  893.  
  894.         theta += 2.0*M_PI/(float)LEGS;
  895.     }
  896. }
  897.  
  898.  
  899. void Driver::timed_draw(Boolean include_in_avg)
  900. {
  901.     SbTime time;
  902.     long sec;
  903.     static SbTime start, end, s, e;
  904.     static long frame_count = 0;
  905.  
  906.     // minimum average fps
  907.     const float MIN_FPS = 4.0;
  908.  
  909.     // maximum individual frame time, in microseconds
  910.     // need this to prevent audio from trying to play when
  911.     // a long redraw occurs
  912.     const float MAX_FRAME_TIME = 125000.0;
  913.  
  914.     // frames to count when computing FPS    
  915.     const int SAMPLE_FRAMES = 10;
  916.  
  917.     s = SbTime::getTimeOfDay();
  918.     draw();
  919.     e = SbTime::getTimeOfDay();
  920.  
  921.     if (include_in_avg && (frame_count % SAMPLE_FRAMES) == 0)
  922.         start = s;
  923.  
  924.     // find last frame time in microseconds
  925.     // bold assumption that we are getting at least 1 fps
  926.     time = e - s;
  927.     time.getValue(sec, _last_frame_time);
  928.  
  929.     // ignore outrageouse frame times
  930.     if (_last_frame_time > MAX_FRAME_TIME)
  931.         _last_frame_time = MAX_FRAME_TIME;
  932.  
  933.     if (include_in_avg && ((++frame_count % SAMPLE_FRAMES) == 0))
  934.     {
  935.         long u_sec;
  936.         float seconds;
  937.     
  938.         end = e;
  939.                 
  940.         time = end - start;
  941.         time.getValue(sec, u_sec);
  942.         seconds = (float)sec + (float)u_sec/1000000.0;
  943.         
  944.         float fps = SAMPLE_FRAMES/seconds;
  945.  
  946.         if (fps > MIN_FPS) // ignore outrageous times
  947.             _fps = fps;
  948.     }
  949.  
  950.     _redraw_cockpit = _redraw_view = FALSE;
  951. }
  952.  
  953.  
  954. // Being the only car (only_car == TRUE) implies that it
  955. // is OK for this routine to go to sleep if nothing is happening.
  956. // Otherwise, must go back and update all other cars.
  957. void Driver::update(Boolean only_car)
  958. {
  959.     static Boolean moving = FALSE;
  960.     static Boolean revving = FALSE;
  961.  
  962.     long any_events = qtest();
  963.     
  964.     while 
  965.         ((! _done) && 
  966.         (any_events || 
  967.             (only_car && (!_cranking)&&
  968.              (! moving)&&(! revving)&&(! _redraw_view)&&(!_redraw_cockpit))))
  969.     {
  970.         long dev; short val;
  971.  
  972.         // need to redraw once before going to sleep
  973.         // so speedo will get to zero
  974.         if ((! any_events) && (! moving))
  975.             timed_draw(FALSE);
  976.             
  977.         dev = qread(&val);
  978.         event(dev,val);
  979.  
  980.         if (only_car && 
  981.             (! moving) && (! revving) && (! _crashed) && (!    _helping))
  982.         {
  983.             _car->get_engine()->update();
  984.             revving = _car->get_engine()->revving();
  985.                 
  986.             _car->get_dynamics()->update();
  987.             moving = _car->get_dynamics()->moving();
  988.         }
  989.  
  990.         any_events = qtest();
  991.     }
  992.  
  993.     if ((! _crashed) && (! _helping))
  994.     {
  995.         _car->get_engine()->update();
  996.         _car->get_dynamics()->update();
  997.     }
  998.  
  999.  
  1000.     if (only_car)
  1001.     {
  1002.         revving = _car->get_engine()->revving();
  1003.         moving = _car->get_dynamics()->moving();
  1004.  
  1005.         if (! _redraw_view)
  1006.             _redraw_view = moving;
  1007.     }
  1008.     else
  1009.         // if other cars are on the road, always redraw
  1010.         _redraw_view = TRUE;
  1011.  
  1012.     if (_crashed && (! _crash_handled))
  1013.     {
  1014.         // stall the engine, play the crashing noise 
  1015.         handle_crash();
  1016.         
  1017.         _broken_winshield = TRUE;
  1018.         _crash_handled = TRUE;
  1019.         _redraw_view = TRUE;
  1020.     }
  1021.     else if (_cranking)
  1022.         _car->get_engine()->crank(TRUE);
  1023.  
  1024.  
  1025.     if (_first_timing && _car->get_engine()->get_gear() >= 1)
  1026.     {
  1027.         _timer->start();
  1028.         _first_timing = FALSE;
  1029.     }
  1030.  
  1031.     _timer->update();
  1032.  
  1033.     if (_redraw_cockpit || _redraw_view || moving || revving)
  1034.         timed_draw(TRUE);
  1035. }
  1036.