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
00015
00016
00017 class GLUT_MANAGER : public FD_MANAGER {
00018 protected:
00019
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
00046
00047
00048 public :
00049
00050
00051
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
00063 ARRAY<tty_to_id> _ids;
00064 stop_watch _frame_timer;
00065 GLUT_WINSYS* _blocker;
00066
00067 public:
00068
00069 GLUT_MANAGER() : _blocker(NULL) {}
00070 virtual ~GLUT_MANAGER() {}
00071
00072
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
00121
00122
00123
00124
00125
00126
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;
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();
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
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
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