core/vgui/impl/glut/vgui_glut_adaptor.cxx
Go to the documentation of this file.
00001 // This is core/vgui/impl/glut/vgui_glut_adaptor.cxx
00002 #include "vgui_glut_adaptor.h"
00003 //:
00004 // \file
00005 // \author fsm
00006 
00007 #include "vgui_glut_window.h"
00008 #include "vgui_glut_popup_impl.h"
00009 #include "menu_hack.h"
00010 
00011 #include <vcl_cassert.h>
00012 #include <vcl_cstdlib.h>
00013 #include <vcl_iostream.h>
00014 #include <vcl_algorithm.h>
00015 
00016 #include <vgui/vgui_glut.h>
00017 #include <vgui/vgui_macro.h>
00018 #include <vgui/vgui_popup_params.h>
00019 #include <vgui/internals/vgui_overlay_helper.h>
00020 
00021 //--------------------------------------------------------------------------------
00022 
00023 vgui_glut_adaptor::vgui_glut_adaptor( vgui_window *win_, int id_ )
00024   : vgui_adaptor()
00025   //
00026   , id(id_)
00027   , win(win_)
00028   //
00029   , popup_modifier(vgui_MODIFIER_NULL)
00030   , popup_button(vgui_BUTTON_NULL)
00031   //, popup_button(vgui_RIGHT)
00032   //
00033   , ovl_established( false )
00034   , ovl_helper( 0 )
00035   //
00036   , super(0)
00037   //
00038   , popup(0)
00039 {
00040   all().push_back(this); // register
00041   register_static_callbacks();
00042 }
00043 
00044 vgui_glut_adaptor::~vgui_glut_adaptor()
00045 {
00046   // destroy the overlay helper, if necessary.
00047   if (ovl_helper)
00048     delete ovl_helper;
00049   ovl_helper = 0;
00050 
00051   // destroy the GLUT window through its handle.
00052   glutDestroyWindow( id );
00053   id = 0;
00054   win = 0;
00055 
00056   // deallocate popup.
00057   if (popup)
00058     delete popup;
00059   popup = 0;
00060 
00061   // destroy GLUT sub-contexts.
00062   for (unsigned i=0; i<sub_contexts.size(); ++i)
00063     delete sub_contexts[i];
00064   sub_contexts.clear();
00065 
00066   // remove `this' from `all()'.
00067   vcl_vector<vgui_glut_adaptor*>::iterator it = vcl_find(all().begin(), all().end(), this);
00068   assert(it != all().end());
00069   all().erase(it);
00070 }
00071 
00072 //--------------------------------------------------------------------------------
00073 
00074 void vgui_glut_adaptor::swap_buffers()
00075 {
00076   //vgui_macro_warning << "glutSwapBuffers()\n";
00077   int old = glutGetWindow();
00078   glutSetWindow( id );
00079   glutSwapBuffers();
00080   glutSetWindow( old );
00081 }
00082 
00083 void vgui_glut_adaptor::make_current()
00084 {
00085   glutSetWindow( id );
00086 }
00087 
00088 unsigned vgui_glut_adaptor::get_width() const
00089 {
00090   int old = glutGetWindow();
00091   glutSetWindow( id );
00092   unsigned val = glutGet(GLenum(GLUT_WINDOW_WIDTH));
00093   glutSetWindow( old );
00094   return val;
00095 }
00096 
00097 unsigned vgui_glut_adaptor::get_height() const
00098 {
00099   int old = glutGetWindow();
00100   glutSetWindow( id );
00101   unsigned val = glutGet(GLenum(GLUT_WINDOW_HEIGHT));
00102   glutSetWindow( old );
00103   return val;
00104 }
00105 
00106 void vgui_glut_adaptor::post_redraw()
00107 {
00108   int old = glutGetWindow();
00109   glutSetWindow( id );
00110   glutPostRedisplay();
00111   glutSetWindow( old );
00112 }
00113 
00114 void vgui_glut_adaptor::post_overlay_redraw()
00115 {
00116   int old = glutGetWindow();
00117   glutSetWindow( id );
00118   establish_overlays();
00119   if (ovl_helper)
00120     ovl_helper->post_overlay_redraw();
00121   else
00122     glutPostOverlayRedisplay();
00123   glutSetWindow( old );
00124 }
00125 
00126 extern void vgui_glut_impl_quit();
00127 
00128 void vgui_glut_adaptor::post_destroy()
00129 {
00130   //vgui_macro_warning << "calling exit()\n";
00131   //exit(1);
00132   vgui_glut_impl_quit();
00133 }
00134 
00135 //--------------------------------------------------------------------------------
00136 
00137 extern bool vgui_emulate_overlays;
00138 
00139 // This function is designed to be called multiple times, but only the first
00140 // invocation does something. That way, the caller doesn't need to check a
00141 // first-time flag all the time (the routine does it).
00142 void vgui_glut_adaptor::establish_overlays()
00143 {
00144   // make this function idempotent.
00145   if (ovl_established)
00146     return;
00147 
00148   // determine whether to use hardware or emulation overlays.
00149   make_current();
00150   bool use_hardware;
00151   if (vgui_emulate_overlays || getenv("vgui_emulate_overlays") != 0)
00152     use_hardware = false;
00153   else {
00154     glutInitDisplayMode( GLUT_RGBA | GLUT_SINGLE );
00155     use_hardware = glutLayerGet(GLenum(GLUT_OVERLAY_POSSIBLE)) != 0;
00156     if (!use_hardware) {
00157       // It could just be that GLUT does not (yet) support RGBA overlays, so
00158       // let's try asking for a colour indexed overlay plane instead :
00159       glutInitDisplayMode( GLUT_INDEX | GLUT_SINGLE );
00160       use_hardware = glutLayerGet(GLenum(GLUT_OVERLAY_POSSIBLE)) != 0;
00161     }
00162   }
00163 
00164   // now do it.
00165   if (use_hardware) {
00166     glutEstablishOverlay();
00167     // The callback must be registered after the overlay has been established.
00168     glutOverlayDisplayFunc(overlay_display_callback);
00169     // Establishing the layer implicitly makes it the current layer.
00170     glutUseLayer(GLenum(GLUT_NORMAL));
00171     vcl_cerr << "GLUT hardware overlay established\n";
00172   }
00173   else {
00174     assert(! ovl_helper);
00175     ovl_helper = new vgui_overlay_helper(this);
00176     vcl_cerr << "emulation overlay helper established\n";
00177   }
00178 
00179   // done.
00180   ovl_established = true;
00181 }
00182 
00183 bool vgui_glut_adaptor::glut_dispatch(vgui_event &e)
00184 {
00185   if (win)
00186     static_cast<vgui_glut_window*>(win)->hello_from_adaptor();
00187 
00188   // convert from window to viewport coordinates :
00189   e.wy = get_height()-1 - e.wy;
00190 
00191   // do not establish the overlay/helper until it is needed.
00192   if (e.type == vgui_DRAW_OVERLAY)
00193     establish_overlays();
00194 
00195   // -------------------- using emulation overlays --------------------
00196   if (ovl_helper)
00197     return ovl_helper->dispatch(e);
00198 
00199   // -------------------- using glut overlays --------------------
00200   else {
00201     // normal draw
00202     if (e.type == vgui_DRAW) {
00203       //vgui_macro_warning << "hardware normal redisplay\n";
00204       //glutUseLayer(GLenum(GLUT_NORMAL));
00205 
00206       bool f = dispatch_to_tableau(e);
00207 #ifdef DUMP_FRAME
00208       fsm_hook();
00209 #endif
00210       swap_buffers();
00211       return f;
00212     }
00213 
00214     // overlay draw
00215     else if (e.type == vgui_DRAW_OVERLAY)
00216     {
00217       //vgui_macro_warning << "hardware overlay redisplay\n";
00218       //glutUseLayer(GLenum(GLUT_OVERLAY));
00219 
00220       // set clear index or color :
00221       GLboolean is_index_mode;
00222       glGetBooleanv(GL_INDEX_MODE, &is_index_mode);
00223       if (is_index_mode)
00224       {
00225         // color index mode
00226         int index = glutLayerGet(GLenum(GLUT_TRANSPARENT_INDEX));
00227         {
00228           static bool once=false;
00229           if (!once)
00230           {
00231             GLint bits;
00232             glGetIntegerv(GL_INDEX_BITS, &bits);
00233             vcl_cerr << __FILE__ ": color index information:\n";
00234             int cmapsize = glutGet(GLenum(GLUT_WINDOW_COLORMAP_SIZE));
00235             vcl_cerr << "  color map size is " << cmapsize << vcl_endl
00236                      << "  transparent color index is " << index << vcl_endl
00237                      << "  # color index bits is " << bits << vcl_endl;
00238             // The default color index values appear to be all transparent
00239             // which is not very helpful, so let's set some more useful
00240             // values here.
00241             // - fsm
00242             //           i  r  g  b
00243             glutSetColor(0, 0, 0, 0);
00244             glutSetColor(1, 0, 0, 1); // b
00245             glutSetColor(2, 0, 1, 0); // g
00246             glutSetColor(3, 0, 1, 1);
00247             glutSetColor(4, 1, 0, 0);
00248             glutSetColor(5, 1, 0, 1); // r
00249             glutSetColor(6, 1, 1, 0);
00250             glutSetColor(7, 1, 1, 1);
00251             int tmp = cmapsize; tmp = 8; ++tmp;
00252 #if 1
00253             for (int cell=0; cell<tmp; ++cell)
00254               vcl_cerr << cell << ':'
00255                        << glutGetColor(cell, GLUT_RED) << ' '
00256                        << glutGetColor(cell, GLUT_GREEN) << ' '
00257                        << glutGetColor(cell, GLUT_BLUE) << vcl_endl;
00258 #endif
00259             once=true;
00260           }
00261         }
00262         glClearIndex(index);
00263       }
00264       else // RGBA mode
00265         glClearColor(0,0,0,0);
00266 
00267       // it's probably sufficient to clear the colour buffer
00268       // in the overlay plane.
00269       glClear(GL_COLOR_BUFFER_BIT);
00270 
00271       //
00272       return dispatch_to_tableau(e);
00273     }
00274 
00275     // all others
00276     else
00277       return dispatch_to_tableau(e);
00278   }
00279 }
00280 
00281 //--------------------------------------------------------------------------------
00282 
00283 void vgui_glut_adaptor::register_static_callbacks()
00284 {
00285   make_current();
00286   glutDisplayFunc(display_callback);
00287   //glutOverlayDisplayFunc(overlay_display_callback);
00288   glutReshapeFunc(reshape_callback);
00289   glutKeyboardFunc(keyboard_callback);
00290   glutMouseFunc(mouse_callback);
00291   glutMotionFunc(motion_callback);
00292   glutPassiveMotionFunc(passive_motion_callback);
00293   glutEntryFunc(entry_callback);
00294   glutVisibilityFunc(visibility_callback);
00295   //these two are global callbacks:
00296   //  glutIdleFunc(idle_callback);
00297   //  glutTimerFunc(10,timer_callback,314159);
00298   glutSpecialFunc(special_callback);
00299 #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13) && !defined(VCL_KAI) //wrong
00300   glutKeyboardUpFunc(keyboard_up_callback);
00301   glutSpecialUpFunc(special_up_callback);
00302 #endif
00303   // this is also a global callback.
00304   glutMenuStatusFunc(menustatus_callback);
00305 }
00306 
00307 // returns a vcl_list of glut adaptors. having a static data member can cause
00308 // a segfault at module initialization time (linux-egcs).
00309 vcl_vector<vgui_glut_adaptor*> &vgui_glut_adaptor::all()
00310 {
00311   static vcl_vector<vgui_glut_adaptor*> *the_vector = 0;
00312   if (!the_vector)
00313     the_vector = new vcl_vector<vgui_glut_adaptor*>;
00314   return *the_vector;
00315 }
00316 
00317 vgui_glut_adaptor *vgui_glut_adaptor::get_adaptor(int window_id)
00318 {
00319   vcl_vector<vgui_glut_adaptor*> &all = vgui_glut_adaptor::all();
00320   for (unsigned i=0; i<all.size(); ++i)
00321     if (all[i]->id == window_id)
00322       return all[i];
00323   vgui_macro_warning << "window id " << window_id << " is not a glut context\n";
00324   return 0; // not one of our glut contexts.
00325 }
00326 
00327 //--------------------------------------------------------------------------------
00328 //
00329 // per-object (dynamic) callbacks
00330 //
00331 
00332 void vgui_glut_adaptor::display()
00333 {
00334   if (glutLayerGet(GLenum(GLUT_LAYER_IN_USE)) != GLUT_NORMAL)
00335     vgui_macro_warning << "*** current layer is overlay\n";
00336 
00337   // normal draw.
00338   vgui_event e(vgui_DRAW);
00339   glut_dispatch(e);
00340 }
00341 
00342 void vgui_glut_adaptor::overlay_display()
00343 {
00344   if (glutLayerGet(GLenum(GLUT_LAYER_IN_USE)) != GLUT_OVERLAY)
00345     vgui_macro_warning << "*** current layer is normal\n";
00346 
00347   {
00348     GLint isdouble=0;
00349     glGetIntegerv(GL_DOUBLEBUFFER, &isdouble);
00350     if (isdouble) // looks suspicious.....
00351       vgui_macro_warning << "overlay plane is double buffered\n";
00352   }
00353 
00354   // overlay draw.
00355   vgui_event e(vgui_DRAW_OVERLAY);
00356   glut_dispatch(e);
00357 }
00358 
00359 // do_modifiers sets the modifier bit flags in a vgui_event.
00360 static void do_modifiers(vgui_event &e)
00361 {
00362   static vgui_modifier last_mods = vgui_MODIFIER_NULL;
00363 
00364   if (e.type == vgui_KEY_PRESS ||
00365       e.type == vgui_KEY_RELEASE ||
00366       e.type == vgui_BUTTON_DOWN ||
00367       e.type == vgui_BUTTON_UP) {
00368     int mods=glutGetModifiers();
00369     int modifier = 0;
00370     if (mods & GLUT_ACTIVE_CTRL)
00371       modifier |= vgui_CTRL;
00372     if (mods & GLUT_ACTIVE_SHIFT)
00373       modifier |= vgui_SHIFT;
00374     if (mods & GLUT_ACTIVE_ALT)
00375       modifier |= vgui_META;
00376     last_mods = vgui_modifier(modifier);
00377   }
00378 
00379   //
00380   e.modifier = last_mods;
00381 }
00382 #if 0
00383 static void do_modifiers(vgui_event &e)
00384 {
00385   int mods=glutGetModifiers(); // can't call this during the motion() callback.
00386   int modifier = 0;
00387   if (mods & GLUT_ACTIVE_CTRL)
00388     modifier |= vgui_CTRL;
00389   if (mods & GLUT_ACTIVE_SHIFT)
00390     modifier |= vgui_SHIFT;
00391   if (mods & GLUT_ACTIVE_ALT)
00392     modifier |= vgui_META;
00393   e.modifier = vgui_modifier(modifier);
00394 }
00395 #endif
00396 #if 0
00397 #include <X11/X.h>
00398 extern unsigned __glutModifierMask;
00399 static void do_modifiers(vgui_event &e) // can call this at any time, though.
00400 {
00401   int modifier = 0;
00402   if (__glutModifierMask & ControlMask)
00403     modifier |= vgui_CTRL;
00404   if (__glutModifierMask & (ShiftMask|LockMask))
00405     modifier |= vgui_SHIFT;
00406   if (__glutModifierMask & Mod1Mask)
00407     modifier |= vgui_META;
00408   e.modifier = vgui_modifier(modifier);
00409 }
00410 #endif
00411 
00412 static vgui_key xlate_key_code(unsigned char key)
00413 {
00414   switch (key)
00415   {
00416    case 127: return vgui_DELETE; // works for me -- fsm
00417    default:  return vgui_key(key);
00418   }
00419 }
00420 
00421 void vgui_glut_adaptor::keyboard(unsigned char key,int x,int y)
00422 {
00423   vgui_event e(vgui_KEY_PRESS);
00424   do_modifiers(e);
00425   e.key = xlate_key_code(key);
00426   e.wx = x;
00427   e.wy = y;
00428   glut_dispatch(e);
00429 }
00430 
00431 void vgui_glut_adaptor::keyboard_up(unsigned char key,int x,int y)
00432 {
00433   vgui_event e(vgui_KEY_RELEASE);
00434   do_modifiers(e);
00435   e.key = xlate_key_code(key);
00436   e.wx = x;
00437   e.wy = y;
00438   glut_dispatch(e);
00439 }
00440 
00441 void vgui_glut_adaptor::mouse(int button,int state,int x,int y)
00442 {
00443   vgui_event e( (state == GLUT_DOWN) ? vgui_BUTTON_DOWN : vgui_BUTTON_UP );
00444   do_modifiers(e);
00445 
00446   if (vgui_glut_menu_hack::mouse(button, state, x, y))
00447     return;
00448 
00449   if (button == GLUT_LEFT_BUTTON)
00450     e.button = vgui_LEFT;
00451   else if (button == GLUT_MIDDLE_BUTTON)
00452     e.button = vgui_MIDDLE;
00453   else if (button == GLUT_RIGHT_BUTTON)
00454     e.button = vgui_RIGHT;
00455   else
00456     e.button = vgui_BUTTON_NULL;
00457   e.wx = x;
00458   e.wy = y;
00459   glut_dispatch(e);
00460 }
00461 
00462 void vgui_glut_adaptor::reshape(int width,int height)
00463 {
00464   vgui_event e;
00465   e.type = vgui_RESHAPE;
00466   bool f=glut_dispatch(e);
00467   if (!f) {
00468     glViewport(0, 0, width, height);
00469     glScissor (0, 0, width, height);
00470   }
00471 
00472   // call reshape on the sub-contexts :
00473   for (unsigned i=0;i<sub_contexts.size();i++) {
00474     // FIXME
00475     vgui_macro_warning << "subcontext reshape not implemented\n";
00476   }
00477 }
00478 
00479 void vgui_glut_adaptor::passive_motion(int x,int y)
00480 {
00481   vgui_event e(vgui_MOTION);
00482   do_modifiers(e);
00483   e.wx = x;
00484   e.wy = y;
00485   glut_dispatch(e);
00486 }
00487 
00488 void vgui_glut_adaptor::motion(int x,int y)
00489 {
00490   vgui_event e(vgui_MOTION);
00491   do_modifiers(e);
00492   e.wx = x;
00493   e.wy = y;
00494   glut_dispatch(e);
00495 }
00496 
00497 void vgui_glut_adaptor::timer(int value)
00498 {
00499   vgui_event e(vgui_TIMER);
00500   e.timer_id = value;
00501   glut_dispatch(e);
00502 }
00503 
00504 void vgui_glut_adaptor::entry(int state)
00505 {
00506   vgui_event e( (state == GLUT_ENTERED) ? vgui_ENTER : vgui_LEAVE );
00507   glut_dispatch(e);
00508 }
00509 
00510 void vgui_glut_adaptor::visibility(int /*state*/)
00511 {
00512 }
00513 
00514 static void xlate_special_key(int key,vgui_event &e)
00515 {
00516   switch (key)
00517   {
00518    case GLUT_KEY_LEFT:      e.key = vgui_CURSOR_LEFT; break;
00519    case GLUT_KEY_UP:        e.key = vgui_CURSOR_UP; break;
00520    case GLUT_KEY_RIGHT:     e.key = vgui_CURSOR_RIGHT; break;
00521    case GLUT_KEY_DOWN:      e.key = vgui_CURSOR_DOWN; break;
00522    case GLUT_KEY_PAGE_UP:   e.key = vgui_PAGE_UP; break;
00523    case GLUT_KEY_PAGE_DOWN: e.key = vgui_PAGE_DOWN; break;
00524    case GLUT_KEY_HOME:      e.key = vgui_HOME; break;
00525    case GLUT_KEY_END:       e.key = vgui_END; break;
00526    case GLUT_KEY_INSERT:    e.key = vgui_INSERT; break;
00527    case GLUT_KEY_F1: case GLUT_KEY_F2: case GLUT_KEY_F3: case GLUT_KEY_F4:
00528    case GLUT_KEY_F5: case GLUT_KEY_F6: case GLUT_KEY_F7: case GLUT_KEY_F8:
00529    case GLUT_KEY_F9: case GLUT_KEY_F10: case GLUT_KEY_F11: case GLUT_KEY_F12:
00530             e.key = vgui_key(vgui_F1 + key - GLUT_KEY_F1); break;
00531    default: e.key = vgui_key(key); break;
00532   }
00533 }
00534 
00535 void vgui_glut_adaptor::special(int key,int x,int y)
00536 {
00537   vgui_event e(vgui_KEY_PRESS);
00538   do_modifiers(e);
00539   xlate_special_key(key,e);
00540   e.wx = x;
00541   e.wy = y;
00542   glut_dispatch(e);
00543 }
00544 
00545 void vgui_glut_adaptor::special_up(int key,int x,int y)
00546 {
00547   vgui_event e(vgui_KEY_RELEASE);
00548   do_modifiers(e);
00549   xlate_special_key(key,e);
00550   e.wx = x;
00551   e.wy = y;
00552   glut_dispatch(e);
00553 }
00554 
00555 //--------------------------------------------------------------------------------
00556 
00557 // This is a the 'last_minute_change_callback' pass to menu_hack. It is called
00558 // just before glut starts popping up the menu with the given id. See menu_hack
00559 // for more details.
00560 void vgui_glut_adaptor::pre_menu_hook(int menu_id)
00561 {
00562   // Find out which glut adaptor is using the given menu id.
00563   // Then ask it to update the glut menu.
00564   for (unsigned i=0; i<all().size(); ++i) {
00565     vgui_glut_adaptor *ct = all()[i];
00566     if (ct->popup && ct->popup->menu_id==menu_id) {
00567       ct->make_popup();
00568       return;
00569     }
00570   }
00571   vgui_macro_warning << "unrecognised menu id " << menu_id << vcl_endl;
00572 }
00573 
00574 void vgui_glut_adaptor::make_popup()
00575 {
00576   make_current();
00577 
00578   // make a glut version of the menu :
00579   if (popup)
00580     popup->clear();
00581   else
00582     popup =  new vgui_glut_popup_impl;
00583   {
00584     vgui_popup_params params;
00585     params.x = 0; // FIXME
00586     params.y = 0; // FIXME
00587     params.recurse = true;
00588     vgui_menu menu;
00589     if (win)
00590       menu.include( static_cast<vgui_glut_window*>(win)->menubar );
00591     menu.include( get_total_popup(params) );
00592     popup->build( menu );
00593   }
00594 
00595   // translate vgui button to GLUT button :
00596   int button = 0;
00597   switch (popup_button)
00598   {
00599    case vgui_LEFT:
00600     button = GLUT_LEFT_BUTTON;
00601     break;
00602    case vgui_MIDDLE:
00603     button = GLUT_MIDDLE_BUTTON;
00604     break;
00605    default:
00606     vgui_macro_warning << "unknown vgui_button - assuming right button\n";
00607    case vgui_RIGHT:
00608     button = GLUT_RIGHT_BUTTON;
00609     break;
00610   }
00611 #ifdef DEBUG
00612   vcl_cerr << "button = " << button << '\n';
00613 #endif
00614 
00615   // translate vgui modifiers to GLUT modifiers :
00616   int mods = 0;
00617   if (popup_modifier & vgui_CTRL)
00618     mods |= GLUT_ACTIVE_CTRL;
00619   if (popup_modifier & vgui_SHIFT)
00620     mods |= GLUT_ACTIVE_SHIFT;
00621   if (popup_modifier & vgui_ALT)
00622     mods |= GLUT_ACTIVE_ALT;
00623 #ifdef DEBUG
00624   vcl_cerr << "mods = " << mods << '\n';
00625 #endif
00626 
00627   // bind buttons and set the menu_hack callback.
00628   vgui_glut_menu_hack::bind(button, mods, popup->menu_id);
00629   vgui_glut_menu_hack::last_minute_change_callback = pre_menu_hook;
00630 }
00631 
00632 void vgui_glut_adaptor::bind_popups(vgui_modifier mod, vgui_button but)
00633 {
00634   popup_button = but;
00635   popup_modifier = mod;
00636   this->make_popup();
00637 }
00638 
00639 //--------------------------------------------------------------------------------
00640 
00641 // Static callbacks. First the special cases :
00642 
00643 //: post timeout events
00644 struct vgui_glut_adaptor_callback_data
00645 {
00646   vgui_glut_adaptor *org;
00647   int val;
00648 };
00649 
00650 #include <vcl_utility.h>
00651 #include <vcl_list.h>
00652 typedef vcl_pair<void*, int> pair_Pv_i;
00653 typedef vcl_list<pair_Pv_i> list_Pv_i;
00654 static list_Pv_i *timer_posts = 0;
00655 
00656 //: timeout is in milliseconds
00657 void vgui_glut_adaptor::post_timer(float timeout, int name)
00658 {
00659   vgui_glut_adaptor_callback_data *ff = new vgui_glut_adaptor_callback_data;   // <*> acquire resource
00660   ff->org = this;
00661   ff->val = name;
00662 
00663   // convert the pointer 'ff' to an int 'value'.
00664   int value = 0;
00665   if (!timer_posts)
00666     timer_posts = new list_Pv_i;
00667   for (list_Pv_i::iterator i=timer_posts->begin(); i!=timer_posts->end(); ++i)
00668     if (value <= (*i).second)
00669       value = (*i).second + 1;
00670   timer_posts->push_front(pair_Pv_i(ff, value));
00671 
00672   // pass 'value' to the GLUT api.
00673   glutTimerFunc(int(timeout), vgui_glut_adaptor::timer_callback, value);
00674 }
00675 
00676 void vgui_glut_adaptor::timer_callback(int value)
00677 {
00678   // convert 'value' back to a pointer 'ff'.
00679   vgui_glut_adaptor_callback_data *ff = 0;
00680   assert(timer_posts);
00681   for (list_Pv_i::iterator i=timer_posts->begin(); i!=timer_posts->end(); ++i)
00682     if (value == (*i).second) {
00683       ff = static_cast<vgui_glut_adaptor_callback_data*>( (*i).first );
00684       timer_posts->erase(i);
00685       break;
00686     }
00687   assert(ff);
00688 
00689   ff->org->timer(ff->val);
00690   delete ff;                               // <*> release resource
00691 }
00692 
00693 //------------------------------------------------------------
00694 
00695 //: called when the menu status changes
00696 void vgui_glut_adaptor::menustatus_callback(int status, int x, int y)
00697 {
00698   vgui_glut_menu_hack::menustatus(status,x,y);
00699 }
00700 
00701 // dispatch macro which works in all other cases :
00702 #define implement_static_callback(name, proto, args) \
00703 void vgui_glut_adaptor::name##_callback proto \
00704 { \
00705   vgui_glut_adaptor *v=get_adaptor(glutGetWindow()); \
00706   if (v) v->name args; \
00707   else   vcl_abort(); \
00708 }
00709 
00710 implement_static_callback(display,(),());
00711 implement_static_callback(overlay_display,(),());
00712 implement_static_callback(reshape,(int width,int height),(width,height));
00713 implement_static_callback(keyboard,(unsigned char key,int x,int y),(key,x,y));
00714 implement_static_callback(keyboard_up,(unsigned char key,int x,int y),(key,x,y));
00715 implement_static_callback(mouse,(int button,int state,int x,int y),(button,state,x,y));
00716 implement_static_callback(visibility,(int state),(state));
00717 implement_static_callback(motion,(int x,int y),(x,y));
00718 implement_static_callback(entry,(int state),(state));
00719 implement_static_callback(passive_motion,(int x,int y),(x,y));
00720 implement_static_callback(special,(int key,int x,int y),(key,x,y));
00721 implement_static_callback(special_up,(int key,int x,int y),(key,x,y));
00722 
00723 //--------------------------------------------------------------------------------
00724 
00725 #ifdef DUMP_FRAME
00726 #include <vul/vul_sprintf.h>
00727 #include <vil1/vil1_save.h>
00728 #include <vil1/vil1_rgb.h>
00729 #include <vil1/vil1_rgba.h>
00730 #include <vil1/vil1_memory_image_of.h>
00731 static
00732 void fsm_dump(char const *file)
00733 {
00734   // get viewport size
00735   GLint vp[4]; // x,y,w,h
00736   glGetIntegerv(GL_VIEWPORT, vp);
00737   unsigned x = vp[0];
00738   unsigned y = vp[1];
00739   unsigned w = vp[2];
00740   unsigned h = vp[3];
00741 
00742   // It's easier to get the buffer in vil1_rgba format and then convert to
00743   // RGB, because that avoids alignment problems with glReadPixels.
00744   static vil1_rgba<GLubyte> *pixels = 0;
00745   if (! pixels)
00746     pixels = new vil1_rgba<GLubyte>[ w * h ];
00747 
00748   //
00749   glPixelZoom(1,1);
00750   glPixelTransferi(GL_MAP_COLOR,0);
00751   glPixelTransferi(GL_RED_SCALE,1);   glPixelTransferi(GL_RED_BIAS,0);
00752   glPixelTransferi(GL_GREEN_SCALE,1); glPixelTransferi(GL_GREEN_BIAS,0);
00753   glPixelTransferi(GL_BLUE_SCALE,1);  glPixelTransferi(GL_BLUE_BIAS,0);
00754 
00755   //
00756   glPixelStorei(GL_PACK_ALIGNMENT,1);   // byte alignment.
00757   glPixelStorei(GL_PACK_ROW_LENGTH,0);  // use default value (the arg to pixel routine).
00758   glPixelStorei(GL_PACK_SKIP_PIXELS,0); //
00759   glPixelStorei(GL_PACK_SKIP_ROWS,0);   //
00760 
00761   // read from the *back buffer*.
00762   glReadBuffer(GL_BACK);
00763 
00764   //
00765   glReadPixels(x, y,             //
00766                w, h,             //
00767                GL_RGBA,          // format
00768                GL_UNSIGNED_BYTE, // type
00769                pixels);
00770 
00771   // glReadPixels() reads the pixels from the bottom of the viewport up.
00772   // Copy them into a vil1_memory_image_of in the other order :
00773   static vil1_memory_image_of<vil1_rgb<GLubyte> > colour_buffer;
00774   colour_buffer.resize(w, h);
00775 
00776   for (unsigned yy=0; yy<h; ++yy)
00777     for (unsigned xx=0; xx<w; ++xx) {
00778       colour_buffer(xx, h-1-yy).r = pixels[xx + w*yy].r;
00779       colour_buffer(xx, h-1-yy).g = pixels[xx + w*yy].g;
00780       colour_buffer(xx, h-1-yy).b = pixels[xx + w*yy].b;
00781     }
00782 
00783   //
00784   vil1_save(colour_buffer, file, "pnm");
00785 }
00786 
00787 bool fsm_hook_flag = false;
00788 static
00789 void fsm_hook()
00790 {
00791   if (fsm_hook_flag) {
00792     static int frame_counter = 0;
00793     fsm_dump(vul_sprintf("/tmp/dump%03d.pnm", frame_counter++).c_str());
00794   }
00795 }
00796 #endif