Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

tty_glut.H

Go to the documentation of this file.
00001 #ifndef TTY_GLUT_HAS_BEEN_INCLUDED
00002 #define TTY_GLUT_HAS_BEEN_INCLUDED
00003 
00004 #include "std/support.H"
00005 #include "std/stop_watch.H"
00006 #include "std/config.H"
00007 #include "dev/tty.H"
00008 
00009 #include <GL/glut.h>
00010 
00011 class GLUT_WINSYS;
00012 
00013 /*****************************************************************
00014  * GLUT_MANAGER
00015  *****************************************************************/
00016 
00017 class GLUT_MANAGER : public FD_MANAGER {
00018  protected:
00019   /******** MEMBER CLASSES ********/
00020    class tty_to_id {
00021     public:
00022       FD_EVENT    *_fd;
00023       tty_to_id(FD_EVENT *fd=0) : _fd(fd) { }
00024       int operator == (const tty_to_id &i) const { return _fd == i._fd; }
00025 #ifdef WIN32
00026       int ready() {
00027          COMSTAT stat;  DWORD eflags;
00028          if (ClearCommError((HANDLE)(_fd->fd()), &eflags, &stat))      
00029             return stat.cbInQue > 0;
00030          else if (_fd->fd() == fileno(stdin))           
00031             return num_bytes_to_read(fileno(stdin)) > 0;
00032          else {
00033             static int msec_wait = Config::get_var_int("GLUT_WAIT",0,true);
00034             struct timeval tm; tm.tv_usec = msec_wait; tm.tv_sec = 0;
00035             fd_set fd;  FD_ZERO(&fd);  FD_SET(_fd->fd(), &fd);
00036             if (select(_fd->fd()+1, &fd, NULL, NULL, &tm) != SOCKET_ERROR) 
00037                return FD_ISSET(_fd->fd(), &fd);
00038             else 
00039                return 0;
00040          }
00041       }
00042 #endif
00043 };
00044  protected:    
00045   /******** STATIC MEMBER VARIABLES ********/
00046 
00047 
00048  public :    
00049    /******** STATIC MEMBER METHODS ********/
00050    // XXX - Assuming, really, that there's only one GLUT_WINSYS window...
00051    //       Otherwise, only the master window should use these... or something...
00052    static void idle_cb() {
00053       ((GLUT_MANAGER*)FD_MANAGER::mgr())->do_idle();   
00054    }
00055 
00056    static void display_cb() {
00057       ((GLUT_MANAGER*)FD_MANAGER::mgr())->do_display();
00058    }
00059 
00060 
00061  protected:
00062    /******** MEMBER VARIABLES ********/
00063    ARRAY<tty_to_id>  _ids;
00064    stop_watch        _frame_timer;
00065    GLUT_WINSYS*      _blocker;
00066 
00067  public:
00068    /******** CONSTRUCTOR/DECONSTRUCTOR *******/
00069    GLUT_MANAGER() : _blocker(NULL) {}
00070    virtual ~GLUT_MANAGER() {}
00071 
00072    /******** MEMBER METHODS ********/
00073  public:
00074     GLUT_WINSYS*  get_blocker()                 { return _blocker; }
00075     void          set_blocker(GLUT_WINSYS *w)   { assert(!_blocker); w->block(); _blocker = w; };
00076     void          clear_blocker(GLUT_WINSYS *w) { assert(_blocker == w); _blocker = NULL; w->unblock(); };
00077 
00078  protected:
00079 
00080    void do_idle() {
00081       int readyFDs = 0;
00082       static bool debug = Config::get_var_bool("DEBUG_JOT_GLUT_IDLE_CB", false);
00083       stop_watch clock;
00084       if (!_blocker) {
00085 #ifdef WIN32
00086          for (int i=0; i<_ids.num(); i++) {
00087             if (_ids[i].ready()) {
00088                readyFDs++;
00089                ((FD_EVENT*)_ids[i]._fd)->sample();
00090             }
00091          }
00092 #else
00093          struct timeval  tval;      
00094          static int msec_wait = Config::get_var_int("GLUT_WAIT", 0);
00095          static bool done = false;
00096          if (debug && !done) {
00097             done = true;
00098             cerr << "GLUT_WAIT: " << msec_wait << " milliseconds" << endl;
00099          }
00100          tval.tv_usec =  msec_wait;
00101          tval.tv_sec  = 0;
00102 
00103          fd_set selectFDs; FD_ZERO(&selectFDs); 
00104          fd_set exceptFDs; FD_ZERO(&exceptFDs);
00105 
00106          int max = -1, fd, num = 0, readyFDs;
00107          for (int i = _ids.num() - 1; i >= 0; i--) {
00108             fd = _ids[i]._fd->fd();
00109             if (fd >= 0) {
00110                FD_SET(fd, &selectFDs);
00111                FD_SET(fd, &exceptFDs);
00112                if (fd > max)
00113                   max = fd;
00114             } else {
00115                cerr << "GLUT_MANAGER::do_idle: removing bad FD_EVENT"
00116                     << endl;
00117                rem(_ids[i]._fd);
00118             }
00119          }
00120          // from the man page for select:
00121          //
00122          //   The select function may update the timeout
00123          //   parameter to indicate how much time was left.
00124          //
00125          // so we always make a local copy of the timeval struct
00126          // and pass that in.
00127          struct timeval t = tval;
00128          readyFDs = select(max + 1, &selectFDs, 0, &exceptFDs, &t);
00129 
00130          for (int i = 0; i < _ids.num() && (num < readyFDs); i++) {
00131             if (FD_ISSET(_ids[i]._fd->fd(), &selectFDs)) {
00132                _ids[i]._fd->sample();  num++;
00133             }   
00134             if (FD_ISSET(_ids[i]._fd->fd(), &exceptFDs)) {
00135                _ids[i]._fd->except();  num++;
00136             }   
00137          }
00138 #endif
00139       }
00140 
00141       if (debug && clock.elapsed_time() > 1e-3) {
00142          cerr << "GLUT_MANAGER::do_idle: "
00143               << clock.elapsed_time()
00144               << " seconds in select"
00145               << endl;
00146       }
00147       if (readyFDs == 0) {
00148          GLUT_WINSYS *w = (GLUT_WINSYS *)VIEWS[0]->win();
00149 
00150          if (w) {
00151             double msecs_passed = _frame_timer.elapsed_time() * 1e3; // milliseconds
00152 
00153             static int TIMEOUT_MS =
00154                Config::get_var_int("JOT_GLUT_REDRAW_TIMEOUT_MS",15);
00155             
00156             if (msecs_passed > TIMEOUT_MS) {
00157                int old_window = glutGetWindow();
00158 
00159                _frame_timer.set();      // reset the timer
00160                
00161                glutSetWindow(w->id());  
00162                glutPostRedisplay(); 
00163                glutSetWindow(old_window); 
00164             } else {
00165                static int SLEEP_MS =
00166                   Config::get_var_int("JOT_GLUT_REDRAW_SLEEP_MS",10,true);
00167                int sleep_ms = SLEEP_MS;
00168                if (msecs_passed > TIMEOUT_MS - SLEEP_MS/2)
00169                   sleep_ms = 0;
00170                if (sleep_ms > 0) {
00171 #ifdef WIN32
00172                Sleep(sleep_ms);
00173 #else
00174                // linux and macosx: use nanosleep
00175                struct timespec ts;
00176                ts.tv_sec = 0;
00177                ts.tv_nsec = sleep_ms * 1000;
00178                nanosleep(&ts, NULL);
00179 #endif
00180                }
00181             }
00182          } else {
00183             cerr << "GLUT_MANAGER::do_idle: No views" << endl;
00184          }
00185       } 
00186    }
00187 
00188    void do_display() {
00189       
00190       int old_window = glutGetWindow();
00191 
00192       if (!_blocker) {
00193          for (int i = 0; i < _timeouts.num(); i++) {
00194             _timeouts[i]->timeout();
00195          }
00196       }
00197 
00198       glutSetWindow(old_window); 
00199    }
00200 
00201    //******** FD_MANAGER METHODS ********
00202    virtual void add(FD_EVENT *fd)   { _ids += tty_to_id(fd); }
00203    virtual void rem(FD_EVENT *fd)   { _ids -= tty_to_id(fd); }
00204    virtual void loop(int infinite)  { assert(infinite); glutMainLoop(); }
00205 };
00206 
00207 #endif // TTY_GLUT_HAS_BEEN_INCLUDED
00208 
00209 // end of file tty_glut.H

Generated on Mon Sep 18 11:39:34 2006 for jot by  doxygen 1.4.4