1 // This is core/vgui/impl/glut/vgui_glut_adaptor.cxx
2 #include <cstdlib>
3 #include <iostream>
4 #include <algorithm>
5 #include <utility>
6 #include <list>
7 #include "vgui_glut_adaptor.h"
8
9 //:
10 // \file
11 // \author fsm
12
13 #include "vgui_glut_window.h"
14 #include "vgui_glut_popup_impl.h"
15 #include "menu_hack.h"
16
17 #include <cassert>
18 #ifdef _MSC_VER
19 # include "vcl_msvc_warnings.h"
20 #endif
21
22 #include "vgui/vgui_glut.h"
23 #include "vgui/vgui_utils.h"
24 #include "vgui/vgui_macro.h"
25 #include "vgui/vgui_popup_params.h"
26 #include <vgui/internals/vgui_overlay_helper.h>
27
28 //--------------------------------------------------------------------------------
29
vgui_glut_adaptor(vgui_window * win_,int id_)30 vgui_glut_adaptor::vgui_glut_adaptor(vgui_window * win_, int id_)
31 : vgui_adaptor()
32 //
33 , id(id_)
34 , win(win_)
35 //
36 , popup_modifier(vgui_MODIFIER_NULL)
37 , popup_button(vgui_BUTTON_NULL)
38 //, popup_button(vgui_RIGHT)
39 //
40 , ovl_established(false)
41 , ovl_helper(nullptr)
42 //
43 , super(nullptr)
44 //
45 , popup(nullptr)
46 {
47 all().push_back(this); // register
48 register_static_callbacks();
49 }
50
~vgui_glut_adaptor()51 vgui_glut_adaptor::~vgui_glut_adaptor()
52 {
53 // destroy the overlay helper, if necessary.
54 if (ovl_helper)
55 delete ovl_helper;
56 ovl_helper = nullptr;
57
58 // destroy the GLUT window through its handle.
59 glutDestroyWindow(id);
60 id = 0;
61 win = nullptr;
62
63 // deallocate popup.
64 if (popup)
65 delete popup;
66 popup = nullptr;
67
68 // destroy GLUT sub-contexts.
69 for (unsigned i = 0; i < sub_contexts.size(); ++i)
70 delete sub_contexts[i];
71 sub_contexts.clear();
72
73 // remove `this' from `all()'.
74 std::vector<vgui_glut_adaptor *>::iterator it = std::find(all().begin(), all().end(), this);
75 assert(it != all().end());
76 all().erase(it);
77 }
78
79 //--------------------------------------------------------------------------------
80
81 void
swap_buffers()82 vgui_glut_adaptor::swap_buffers()
83 {
84 // vgui_macro_warning << "glutSwapBuffers()\n";
85 int old = glutGetWindow();
86 glutSetWindow(id);
87 glutSwapBuffers();
88 glutSetWindow(old);
89 }
90
91 void
make_current()92 vgui_glut_adaptor::make_current()
93 {
94 glutSetWindow(id);
95 }
96
97 unsigned
get_width() const98 vgui_glut_adaptor::get_width() const
99 {
100 int old = glutGetWindow();
101 glutSetWindow(id);
102 unsigned val = glutGet(GLenum(GLUT_WINDOW_WIDTH));
103 glutSetWindow(old);
104 return val;
105 }
106
107 unsigned
get_height() const108 vgui_glut_adaptor::get_height() const
109 {
110 int old = glutGetWindow();
111 glutSetWindow(id);
112 unsigned val = glutGet(GLenum(GLUT_WINDOW_HEIGHT));
113 glutSetWindow(old);
114 return val;
115 }
116
117 void
post_redraw()118 vgui_glut_adaptor::post_redraw()
119 {
120 int old = glutGetWindow();
121 glutSetWindow(id);
122 glutPostRedisplay();
123 glutSetWindow(old);
124 }
125
126 void
post_overlay_redraw()127 vgui_glut_adaptor::post_overlay_redraw()
128 {
129 int old = glutGetWindow();
130 glutSetWindow(id);
131 establish_overlays();
132 if (ovl_helper)
133 ovl_helper->post_overlay_redraw();
134 else
135 glutPostOverlayRedisplay();
136 glutSetWindow(old);
137 }
138
139 extern void
140 vgui_glut_impl_quit();
141
142 void
post_destroy()143 vgui_glut_adaptor::post_destroy()
144 {
145 // vgui_macro_warning << "calling exit()\n";
146 // exit(1);
147 vgui_glut_impl_quit();
148 }
149
150 //--------------------------------------------------------------------------------
151
152 extern bool vgui_emulate_overlays;
153
154 // This function is designed to be called multiple times, but only the first
155 // invocation does something. That way, the caller doesn't need to check a
156 // first-time flag all the time (the routine does it).
157 void
establish_overlays()158 vgui_glut_adaptor::establish_overlays()
159 {
160 // make this function idempotent.
161 if (ovl_established)
162 return;
163
164 // determine whether to use hardware or emulation overlays.
165 make_current();
166 bool use_hardware;
167 if (vgui_emulate_overlays || getenv("vgui_emulate_overlays") != nullptr)
168 use_hardware = false;
169 else
170 {
171 glutInitDisplayMode(GLUT_RGBA | GLUT_SINGLE);
172 use_hardware = glutLayerGet(GLenum(GLUT_OVERLAY_POSSIBLE)) != 0;
173 if (!use_hardware)
174 {
175 // It could just be that GLUT does not (yet) support RGBA overlays, so
176 // let's try asking for a colour indexed overlay plane instead :
177 glutInitDisplayMode(GLUT_INDEX | GLUT_SINGLE);
178 use_hardware = glutLayerGet(GLenum(GLUT_OVERLAY_POSSIBLE)) != 0;
179 }
180 }
181
182 // now do it.
183 if (use_hardware)
184 {
185 glutEstablishOverlay();
186 // The callback must be registered after the overlay has been established.
187 glutOverlayDisplayFunc(overlay_display_callback);
188 // Establishing the layer implicitly makes it the current layer.
189 glutUseLayer(GLenum(GLUT_NORMAL));
190 std::cerr << "GLUT hardware overlay established\n";
191 }
192 else
193 {
194 assert(!ovl_helper);
195 ovl_helper = new vgui_overlay_helper(this);
196 std::cerr << "emulation overlay helper established\n";
197 }
198
199 // done.
200 ovl_established = true;
201 }
202
203 bool
glut_dispatch(vgui_event & e)204 vgui_glut_adaptor::glut_dispatch(vgui_event & e)
205 {
206 if (win)
207 static_cast<vgui_glut_window *>(win)->hello_from_adaptor();
208
209 // convert from window to viewport coordinates :
210 e.wy = get_height() - 1 - e.wy;
211
212 // do not establish the overlay/helper until it is needed.
213 if (e.type == vgui_DRAW_OVERLAY)
214 establish_overlays();
215
216 // -------------------- using emulation overlays --------------------
217 if (ovl_helper)
218 return ovl_helper->dispatch(e);
219
220 // -------------------- using glut overlays --------------------
221 else
222 {
223 // normal draw
224 if (e.type == vgui_DRAW)
225 {
226 // vgui_macro_warning << "hardware normal redisplay\n";
227 // glutUseLayer(GLenum(GLUT_NORMAL));
228
229 bool f = dispatch_to_tableau(e);
230 #ifdef DUMP_FRAME
231 fsm_hook();
232 #endif
233 swap_buffers();
234 return f;
235 }
236
237 // overlay draw
238 else if (e.type == vgui_DRAW_OVERLAY)
239 {
240 // vgui_macro_warning << "hardware overlay redisplay\n";
241 // glutUseLayer(GLenum(GLUT_OVERLAY));
242
243 // set clear index or color :
244 GLboolean is_index_mode;
245 glGetBooleanv(GL_INDEX_MODE, &is_index_mode);
246 if (is_index_mode)
247 {
248 // color index mode
249 int index = glutLayerGet(GLenum(GLUT_TRANSPARENT_INDEX));
250 {
251 static bool once = false;
252 if (!once)
253 {
254 GLint bits;
255 glGetIntegerv(GL_INDEX_BITS, &bits);
256 std::cerr << __FILE__ ": color index information:\n";
257 int cmapsize = glutGet(GLenum(GLUT_WINDOW_COLORMAP_SIZE));
258 std::cerr << " color map size is " << cmapsize << std::endl
259 << " transparent color index is " << index << std::endl
260 << " # color index bits is " << bits << std::endl;
261 // The default color index values appear to be all transparent
262 // which is not very helpful, so let's set some more useful
263 // values here.
264 // - fsm
265 // i r g b
266 glutSetColor(0, 0, 0, 0);
267 glutSetColor(1, 0, 0, 1); // b
268 glutSetColor(2, 0, 1, 0); // g
269 glutSetColor(3, 0, 1, 1);
270 glutSetColor(4, 1, 0, 0);
271 glutSetColor(5, 1, 0, 1); // r
272 glutSetColor(6, 1, 1, 0);
273 glutSetColor(7, 1, 1, 1);
274 int tmp = cmapsize;
275 tmp = 8;
276 ++tmp;
277 #if 1
278 for (int cell = 0; cell < tmp; ++cell)
279 std::cerr << cell << ':' << glutGetColor(cell, GLUT_RED) << ' ' << glutGetColor(cell, GLUT_GREEN) << ' '
280 << glutGetColor(cell, GLUT_BLUE) << std::endl;
281 #endif
282 once = true;
283 }
284 }
285 glClearIndex(index);
286 }
287 else // RGBA mode
288 glClearColor(0, 0, 0, 0);
289
290 // it's probably sufficient to clear the colour buffer
291 // in the overlay plane.
292 glClear(GL_COLOR_BUFFER_BIT);
293
294 //
295 return dispatch_to_tableau(e);
296 }
297
298 // all others
299 else
300 return dispatch_to_tableau(e);
301 }
302 }
303
304 //--------------------------------------------------------------------------------
305
306 void
register_static_callbacks()307 vgui_glut_adaptor::register_static_callbacks()
308 {
309 make_current();
310 glutDisplayFunc(display_callback);
311 // glutOverlayDisplayFunc(overlay_display_callback);
312 glutReshapeFunc(reshape_callback);
313 glutKeyboardFunc(keyboard_callback);
314 glutMouseFunc(mouse_callback);
315 glutMotionFunc(motion_callback);
316 glutPassiveMotionFunc(passive_motion_callback);
317 glutEntryFunc(entry_callback);
318 glutVisibilityFunc(visibility_callback);
319 // these two are global callbacks:
320 // glutIdleFunc(idle_callback);
321 // glutTimerFunc(10,timer_callback,314159);
322 glutSpecialFunc(special_callback);
323 #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13) // wrong
324 glutKeyboardUpFunc(keyboard_up_callback);
325 glutSpecialUpFunc(special_up_callback);
326 #endif
327 // this is also a global callback.
328 glutMenuStatusFunc(menustatus_callback);
329 }
330
331 // returns a std::list of glut adaptors. having a static data member can cause
332 // a segfault at module initialization time (linux-egcs).
333 std::vector<vgui_glut_adaptor *> &
all()334 vgui_glut_adaptor::all()
335 {
336 static std::vector<vgui_glut_adaptor *> * the_vector = nullptr;
337 if (!the_vector)
338 the_vector = new std::vector<vgui_glut_adaptor *>;
339 return *the_vector;
340 }
341
342 vgui_glut_adaptor *
get_adaptor(int window_id)343 vgui_glut_adaptor::get_adaptor(int window_id)
344 {
345 std::vector<vgui_glut_adaptor *> & all = vgui_glut_adaptor::all();
346 for (unsigned i = 0; i < all.size(); ++i)
347 if (all[i]->id == window_id)
348 return all[i];
349 vgui_macro_warning << "window id " << window_id << " is not a glut context\n";
350 return nullptr; // not one of our glut contexts.
351 }
352
353 //--------------------------------------------------------------------------------
354 //
355 // per-object (dynamic) callbacks
356 //
357
358 void
display()359 vgui_glut_adaptor::display()
360 {
361 if (glutLayerGet(GLenum(GLUT_LAYER_IN_USE)) != GLUT_NORMAL)
362 vgui_macro_warning << "*** current layer is overlay\n";
363
364 // normal draw.
365 vgui_event e(vgui_DRAW);
366 glut_dispatch(e);
367 }
368
369 void
overlay_display()370 vgui_glut_adaptor::overlay_display()
371 {
372 if (glutLayerGet(GLenum(GLUT_LAYER_IN_USE)) != GLUT_OVERLAY)
373 vgui_macro_warning << "*** current layer is normal\n";
374
375 {
376 GLint isdouble = 0;
377 glGetIntegerv(GL_DOUBLEBUFFER, &isdouble);
378 if (isdouble) // looks suspicious.....
379 vgui_macro_warning << "overlay plane is double buffered\n";
380 }
381
382 // overlay draw.
383 vgui_event e(vgui_DRAW_OVERLAY);
384 glut_dispatch(e);
385 }
386
387 // do_modifiers sets the modifier bit flags in a vgui_event.
388 static void
do_modifiers(vgui_event & e)389 do_modifiers(vgui_event & e)
390 {
391 static vgui_modifier last_mods = vgui_MODIFIER_NULL;
392
393 if (e.type == vgui_KEY_PRESS || e.type == vgui_KEY_RELEASE || e.type == vgui_BUTTON_DOWN || e.type == vgui_BUTTON_UP)
394 {
395 int mods = glutGetModifiers();
396 int modifier = 0;
397 if (mods & GLUT_ACTIVE_CTRL)
398 modifier |= vgui_CTRL;
399 if (mods & GLUT_ACTIVE_SHIFT)
400 modifier |= vgui_SHIFT;
401 if (mods & GLUT_ACTIVE_ALT)
402 modifier |= vgui_META;
403 last_mods = vgui_modifier(modifier);
404 }
405
406 //
407 e.modifier = last_mods;
408 }
409 #if 0
410 static void do_modifiers(vgui_event &e)
411 {
412 int mods=glutGetModifiers(); // can't call this during the motion() callback.
413 int modifier = 0;
414 if (mods & GLUT_ACTIVE_CTRL)
415 modifier |= vgui_CTRL;
416 if (mods & GLUT_ACTIVE_SHIFT)
417 modifier |= vgui_SHIFT;
418 if (mods & GLUT_ACTIVE_ALT)
419 modifier |= vgui_META;
420 e.modifier = vgui_modifier(modifier);
421 }
422 #endif
423 #if 0
424 # include <X11/X.h>
425 extern unsigned __glutModifierMask;
426 static void do_modifiers(vgui_event &e) // can call this at any time, though.
427 {
428 int modifier = 0;
429 if (__glutModifierMask & ControlMask)
430 modifier |= vgui_CTRL;
431 if (__glutModifierMask & (ShiftMask|LockMask))
432 modifier |= vgui_SHIFT;
433 if (__glutModifierMask & Mod1Mask)
434 modifier |= vgui_META;
435 e.modifier = vgui_modifier(modifier);
436 }
437 #endif
438
439 static vgui_key
xlate_key_code(unsigned char key)440 xlate_key_code(unsigned char key)
441 {
442 switch (key)
443 {
444 case 127:
445 return vgui_DELETE; // works for me -- fsm
446 default:
447 return vgui_key(key);
448 }
449 }
450
451 void
keyboard(unsigned char key,int x,int y)452 vgui_glut_adaptor::keyboard(unsigned char key, int x, int y)
453 {
454 vgui_event e(vgui_KEY_PRESS);
455 do_modifiers(e);
456 e.key = xlate_key_code(key);
457 e.wx = x;
458 e.wy = y;
459 glut_dispatch(e);
460 }
461
462 void
keyboard_up(unsigned char key,int x,int y)463 vgui_glut_adaptor::keyboard_up(unsigned char key, int x, int y)
464 {
465 vgui_event e(vgui_KEY_RELEASE);
466 do_modifiers(e);
467 e.key = xlate_key_code(key);
468 e.wx = x;
469 e.wy = y;
470 glut_dispatch(e);
471 }
472
473 void
mouse(int button,int state,int x,int y)474 vgui_glut_adaptor::mouse(int button, int state, int x, int y)
475 {
476 vgui_event e((state == GLUT_DOWN) ? vgui_BUTTON_DOWN : vgui_BUTTON_UP);
477 do_modifiers(e);
478
479 if (vgui_glut_menu_hack::mouse(button, state, x, y))
480 return;
481
482 if (button == GLUT_LEFT_BUTTON)
483 e.button = vgui_LEFT;
484 else if (button == GLUT_MIDDLE_BUTTON)
485 e.button = vgui_MIDDLE;
486 else if (button == GLUT_RIGHT_BUTTON)
487 e.button = vgui_RIGHT;
488 else
489 e.button = vgui_BUTTON_NULL;
490 e.wx = x;
491 e.wy = y;
492 glut_dispatch(e);
493 }
494
495 void
reshape(int width,int height)496 vgui_glut_adaptor::reshape(int width, int height)
497 {
498 vgui_event e;
499 e.type = vgui_RESHAPE;
500 bool f = glut_dispatch(e);
501 if (!f)
502 {
503 vgui_utils::set_glViewport(0, 0, width, height);
504 vgui_utils::set_glScissor(0, 0, width, height);
505 }
506
507 // call reshape on the sub-contexts :
508 for (unsigned i = 0; i < sub_contexts.size(); i++)
509 {
510 // FIXME
511 vgui_macro_warning << "subcontext reshape not implemented\n";
512 }
513 }
514
515 void
passive_motion(int x,int y)516 vgui_glut_adaptor::passive_motion(int x, int y)
517 {
518 vgui_event e(vgui_MOTION);
519 do_modifiers(e);
520 e.wx = x;
521 e.wy = y;
522 glut_dispatch(e);
523 }
524
525 void
motion(int x,int y)526 vgui_glut_adaptor::motion(int x, int y)
527 {
528 vgui_event e(vgui_MOTION);
529 do_modifiers(e);
530 e.wx = x;
531 e.wy = y;
532 glut_dispatch(e);
533 }
534
535 void
timer(int value)536 vgui_glut_adaptor::timer(int value)
537 {
538 vgui_event e(vgui_TIMER);
539 e.timer_id = value;
540 glut_dispatch(e);
541 }
542
543 void
entry(int state)544 vgui_glut_adaptor::entry(int state)
545 {
546 vgui_event e((state == GLUT_ENTERED) ? vgui_ENTER : vgui_LEAVE);
547 glut_dispatch(e);
548 }
549
550 void
visibility(int)551 vgui_glut_adaptor::visibility(int /*state*/)
552 {}
553
554 static void
xlate_special_key(int key,vgui_event & e)555 xlate_special_key(int key, vgui_event & e)
556 {
557 switch (key)
558 {
559 case GLUT_KEY_LEFT:
560 e.key = vgui_CURSOR_LEFT;
561 break;
562 case GLUT_KEY_UP:
563 e.key = vgui_CURSOR_UP;
564 break;
565 case GLUT_KEY_RIGHT:
566 e.key = vgui_CURSOR_RIGHT;
567 break;
568 case GLUT_KEY_DOWN:
569 e.key = vgui_CURSOR_DOWN;
570 break;
571 case GLUT_KEY_PAGE_UP:
572 e.key = vgui_PAGE_UP;
573 break;
574 case GLUT_KEY_PAGE_DOWN:
575 e.key = vgui_PAGE_DOWN;
576 break;
577 case GLUT_KEY_HOME:
578 e.key = vgui_HOME;
579 break;
580 case GLUT_KEY_END:
581 e.key = vgui_END;
582 break;
583 case GLUT_KEY_INSERT:
584 e.key = vgui_INSERT;
585 break;
586 case GLUT_KEY_F1:
587 case GLUT_KEY_F2:
588 case GLUT_KEY_F3:
589 case GLUT_KEY_F4:
590 case GLUT_KEY_F5:
591 case GLUT_KEY_F6:
592 case GLUT_KEY_F7:
593 case GLUT_KEY_F8:
594 case GLUT_KEY_F9:
595 case GLUT_KEY_F10:
596 case GLUT_KEY_F11:
597 case GLUT_KEY_F12:
598 e.key = vgui_key(vgui_F1 + key - GLUT_KEY_F1);
599 break;
600 default:
601 e.key = vgui_key(key);
602 break;
603 }
604 }
605
606 void
special(int key,int x,int y)607 vgui_glut_adaptor::special(int key, int x, int y)
608 {
609 vgui_event e(vgui_KEY_PRESS);
610 do_modifiers(e);
611 xlate_special_key(key, e);
612 e.wx = x;
613 e.wy = y;
614 glut_dispatch(e);
615 }
616
617 void
special_up(int key,int x,int y)618 vgui_glut_adaptor::special_up(int key, int x, int y)
619 {
620 vgui_event e(vgui_KEY_RELEASE);
621 do_modifiers(e);
622 xlate_special_key(key, e);
623 e.wx = x;
624 e.wy = y;
625 glut_dispatch(e);
626 }
627
628 //--------------------------------------------------------------------------------
629
630 // This is a the 'last_minute_change_callback' pass to menu_hack. It is called
631 // just before glut starts popping up the menu with the given id. See menu_hack
632 // for more details.
633 void
pre_menu_hook(int menu_id)634 vgui_glut_adaptor::pre_menu_hook(int menu_id)
635 {
636 // Find out which glut adaptor is using the given menu id.
637 // Then ask it to update the glut menu.
638 for (unsigned i = 0; i < all().size(); ++i)
639 {
640 vgui_glut_adaptor * ct = all()[i];
641 if (ct->popup && ct->popup->menu_id == menu_id)
642 {
643 ct->make_popup();
644 return;
645 }
646 }
647 vgui_macro_warning << "unrecognised menu id " << menu_id << std::endl;
648 }
649
650 void
make_popup()651 vgui_glut_adaptor::make_popup()
652 {
653 make_current();
654
655 // make a glut version of the menu :
656 if (popup)
657 popup->clear();
658 else
659 popup = new vgui_glut_popup_impl;
660 {
661 vgui_popup_params params;
662 params.x = 0; // FIXME
663 params.y = 0; // FIXME
664 params.recurse = true;
665 vgui_menu menu;
666 if (win)
667 menu.include(static_cast<vgui_glut_window *>(win)->menubar);
668 menu.include(get_total_popup(params));
669 popup->build(menu);
670 }
671
672 // translate vgui button to GLUT button :
673 int button = 0;
674 switch (popup_button)
675 {
676 case vgui_LEFT:
677 button = GLUT_LEFT_BUTTON;
678 break;
679 case vgui_MIDDLE:
680 button = GLUT_MIDDLE_BUTTON;
681 break;
682 default:
683 vgui_macro_warning << "unknown vgui_button - assuming right button\n";
684 case vgui_RIGHT:
685 button = GLUT_RIGHT_BUTTON;
686 break;
687 }
688 #ifdef DEBUG
689 std::cerr << "button = " << button << '\n';
690 #endif
691
692 // translate vgui modifiers to GLUT modifiers :
693 int mods = 0;
694 if (popup_modifier & vgui_CTRL)
695 mods |= GLUT_ACTIVE_CTRL;
696 if (popup_modifier & vgui_SHIFT)
697 mods |= GLUT_ACTIVE_SHIFT;
698 if (popup_modifier & vgui_ALT)
699 mods |= GLUT_ACTIVE_ALT;
700 #ifdef DEBUG
701 std::cerr << "mods = " << mods << '\n';
702 #endif
703
704 // bind buttons and set the menu_hack callback.
705 vgui_glut_menu_hack::bind(button, mods, popup->menu_id);
706 vgui_glut_menu_hack::last_minute_change_callback = pre_menu_hook;
707 }
708
709 void
bind_popups(vgui_modifier mod,vgui_button but)710 vgui_glut_adaptor::bind_popups(vgui_modifier mod, vgui_button but)
711 {
712 popup_button = but;
713 popup_modifier = mod;
714 this->make_popup();
715 }
716
717 //--------------------------------------------------------------------------------
718
719 // Static callbacks. First the special cases :
720
721 //: post timeout events
722 struct vgui_glut_adaptor_callback_data
723 {
724 vgui_glut_adaptor * org;
725 int val;
726 };
727
728 typedef std::pair<void *, int> pair_Pv_i;
729 typedef std::list<pair_Pv_i> list_Pv_i;
730 static list_Pv_i * timer_posts = nullptr;
731
732 //: timeout is in milliseconds
733 void
post_timer(float timeout,int name)734 vgui_glut_adaptor::post_timer(float timeout, int name)
735 {
736 vgui_glut_adaptor_callback_data * ff = new vgui_glut_adaptor_callback_data; // <*> acquire resource
737 ff->org = this;
738 ff->val = name;
739
740 // convert the pointer 'ff' to an int 'value'.
741 int value = 0;
742 if (!timer_posts)
743 timer_posts = new list_Pv_i;
744 for (list_Pv_i::iterator i = timer_posts->begin(); i != timer_posts->end(); ++i)
745 if (value <= (*i).second)
746 value = (*i).second + 1;
747 timer_posts->push_front(pair_Pv_i(ff, value));
748
749 // pass 'value' to the GLUT api.
750 glutTimerFunc(int(timeout), vgui_glut_adaptor::timer_callback, value);
751 }
752
753 void
timer_callback(int value)754 vgui_glut_adaptor::timer_callback(int value)
755 {
756 // convert 'value' back to a pointer 'ff'.
757 vgui_glut_adaptor_callback_data * ff = nullptr;
758 assert(timer_posts);
759 for (list_Pv_i::iterator i = timer_posts->begin(); i != timer_posts->end(); ++i)
760 if (value == (*i).second)
761 {
762 ff = static_cast<vgui_glut_adaptor_callback_data *>((*i).first);
763 timer_posts->erase(i);
764 break;
765 }
766 assert(ff);
767
768 ff->org->timer(ff->val);
769 delete ff; // <*> release resource
770 }
771
772 //------------------------------------------------------------
773
774 //: called when the menu status changes
775 void
menustatus_callback(int status,int x,int y)776 vgui_glut_adaptor::menustatus_callback(int status, int x, int y)
777 {
778 vgui_glut_menu_hack::menustatus(status, x, y);
779 }
780
781 // dispatch macro which works in all other cases :
782 #define implement_static_callback(name, proto, args) \
783 void vgui_glut_adaptor::name##_callback proto \
784 { \
785 vgui_glut_adaptor * v = get_adaptor(glutGetWindow()); \
786 if (v) \
787 v->name args; \
788 else \
789 std::abort(); \
790 }
791
792 implement_static_callback(display, (), ());
793 implement_static_callback(overlay_display, (), ());
794 implement_static_callback(reshape, (int width, int height), (width, height));
795 implement_static_callback(keyboard, (unsigned char key, int x, int y), (key, x, y));
796 implement_static_callback(keyboard_up, (unsigned char key, int x, int y), (key, x, y));
797 implement_static_callback(mouse, (int button, int state, int x, int y), (button, state, x, y));
798 implement_static_callback(visibility, (int state), (state));
799 implement_static_callback(motion, (int x, int y), (x, y));
800 implement_static_callback(entry, (int state), (state));
801 implement_static_callback(passive_motion, (int x, int y), (x, y));
802 implement_static_callback(special, (int key, int x, int y), (key, x, y));
803 implement_static_callback(special_up, (int key, int x, int y), (key, x, y));
804
805 //--------------------------------------------------------------------------------
806
807 #ifdef DUMP_FRAME
808 # include "vgui/vgui_utils.h"
809 # include "vul/vul_sprintf.h"
810 # include "vil1/vil1_save.h"
811 # include "vil1/vil1_rgb.h"
812 # include "vil1/vil1_rgba.h"
813 # include "vil1/vil1_memory_image_of.h"
814 static void
fsm_dump(char const * file)815 fsm_dump(char const * file)
816 {
817 vil1_memory_image_of<vil1_rgb<GLubyte>> colour_buffer = vgui_utils::get_image();
818
819 vil1_save(colour_buffer, file, "pnm");
820 }
821
822 bool fsm_hook_flag = false;
823 static void
fsm_hook()824 fsm_hook()
825 {
826 if (fsm_hook_flag)
827 {
828 static int frame_counter = 0;
829 fsm_dump(vul_sprintf("/tmp/dump%03d.pnm", frame_counter++).c_str());
830 }
831 }
832 #endif
833