1 //
2 // "$Id: glut_compatability.cxx 7818 2010-11-11 18:22:43Z engelsman $"
3 //
4 // GLUT emulation routines for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2010 by Bill Spitzak and others.
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // Library General Public License for more details.
17 //
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 // USA.
22 //
23 // Please report all bugs and problems on the following page:
24 //
25 //     http://www.fltk.org/str.php
26 //
27 
28 // Emulation of Glut using fltk.
29 
30 // GLUT is Copyright (c) Mark J. Kilgard, 1994, 1995, 1996.
31 // "This program is freely distributable without licensing fees  and is
32 // provided without guarantee or warrantee expressed or  implied. This
33 // program is -not- in the public domain."
34 
35 // Although I have copied the GLUT API, none of my code is based on
36 // any Glut implementation details and is therefore covered by the LGPL.
37 
38 #include "flstring.h"
39 #if HAVE_GL
40 
41 #  include <FL/glut.H>
42 #  ifdef HAVE_GLXGETPROCADDRESSARB
43 #    define GLX_GLXEXT_LEGACY
44 #    include <GL/glx.h>
45 #  endif // HAVE_GLXGETPROCADDRESSARB
46 #  ifdef HAVE_DLFCN_H
47 #    include <dlfcn.h>
48 #  endif // HAVE_DLFCN_H
49 #  define MAXWINDOWS 32
50 static Fl_Glut_Window *windows[MAXWINDOWS+1];
51 
52 static void (*glut_idle_func)() = 0; // global glut idle function
53 
54 Fl_Glut_Window *glut_window;
55 int glut_menu;
56 void (*glut_menustate_function)(int);
57 void (*glut_menustatus_function)(int,int,int);
58 
default_reshape(int w,int h)59 static void default_reshape(int w, int h) {glViewport(0,0,w,h);}
default_display()60 static void default_display() {}
61 
make_current()62 void Fl_Glut_Window::make_current() {
63   glut_window = this;
64   if (shown()) Fl_Gl_Window::make_current();
65 }
66 
67 static int indraw;
draw()68 void Fl_Glut_Window::draw() {
69   glut_window = this;
70   indraw = 1;
71   if (!valid()) {reshape(w(),h()); valid(1);}
72   display();
73   indraw = 0;
74 }
75 
glutSwapBuffers()76 void glutSwapBuffers() {
77   if (!indraw) glut_window->swap_buffers();
78 }
79 
draw_overlay()80 void Fl_Glut_Window::draw_overlay() {
81   glut_window = this;
82   if (!valid()) {reshape(w(),h()); valid(1);}
83   overlaydisplay();
84 }
85 
86 static void domenu(int, int, int);
87 
handle(int event)88 int Fl_Glut_Window::handle(int event) {
89   make_current();
90   int ex = Fl::event_x();
91   int ey = Fl::event_y();
92   int button;
93   switch (event) {
94 
95   case FL_PUSH:
96     if (keyboard || special) Fl::focus(this);
97     button = Fl::event_button()-1;
98     if (button<0) button = 0;
99     if (button>2) button = 2;
100     if (menu[button]) {domenu(menu[button],ex,ey); return 1;}
101     mouse_down |= 1<<button;
102     if (mouse) {mouse(button,GLUT_DOWN,ex,ey); return 1;}
103     if (motion) return 1;
104     break;
105 
106   case FL_MOUSEWHEEL:
107     button = Fl::event_dy();
108     while (button < 0) {if (mouse) mouse(3,GLUT_DOWN,ex,ey); ++button;}
109     while (button > 0) {if (mouse) mouse(4,GLUT_DOWN,ex,ey); --button;}
110     return 1;
111 
112   case FL_RELEASE:
113     for (button = 0; button < 3; button++) if (mouse_down & (1<<button)) {
114       if (mouse) mouse(button,GLUT_UP,ex,ey);
115     }
116     mouse_down = 0;
117     return 1;
118 
119   case FL_ENTER:
120     if (entry) {entry(GLUT_ENTERED); return 1;}
121     if (passivemotion) return 1;
122     break;
123 
124   case FL_LEAVE:
125     if (entry) {entry(GLUT_LEFT); return 1;}
126     if (passivemotion) return 1;
127     break;
128 
129   case FL_DRAG:
130     if (motion) {motion(ex, ey); return 1;}
131     break;
132 
133   case FL_MOVE:
134     if (passivemotion) {passivemotion(ex, ey); return 1;}
135     break;
136 
137   case FL_FOCUS:
138     if (keyboard || special) return 1;
139     break;
140 
141   case FL_SHORTCUT:
142     if (!keyboard && !special) break;
143 
144   case FL_KEYBOARD:
145     if (Fl::event_text()[0]) {
146       if (keyboard) {keyboard(Fl::event_text()[0],ex,ey); return 1;}
147       break;
148     } else {
149       if (special) {
150 	int k = Fl::event_key();
151 	if (k > FL_F && k <= FL_F_Last) k -= FL_F;
152 	special(k,ex,ey);
153 	return 1;
154       }
155       break;
156     }
157 
158   case FL_HIDE:
159     if (visibility) visibility(GLUT_NOT_VISIBLE);
160     break;
161 
162   case FL_SHOW:
163     if (visibility) visibility(GLUT_VISIBLE);
164     break;
165   }
166 
167   return Fl_Gl_Window::handle(event);
168 }
169 
170 static int glut_mode = GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH;
171 
_init()172 void Fl_Glut_Window::_init() {
173   for (number=1; number<MAXWINDOWS; number++) if (!windows[number]) break;
174   windows[number] = this;
175   menu[0] = menu[1] = menu[2] = 0;
176   reshape = default_reshape;
177   display = default_display;
178   overlaydisplay = default_display;
179   keyboard = 0;
180   mouse = 0;
181   motion = 0;
182   passivemotion = 0;
183   entry = 0;
184   visibility = 0;
185   special = 0;
186   mouse_down = 0;
187   mode(glut_mode);
188 }
189 
190 /** Creates a glut window, registers to the glut windows list.*/
Fl_Glut_Window(int W,int H,const char * t)191 Fl_Glut_Window::Fl_Glut_Window(int W, int H, const char *t) :
192   Fl_Gl_Window(W,H,t) {_init();}
193 
194 /** Creates a glut window, registers to the glut windows list.*/
Fl_Glut_Window(int X,int Y,int W,int H,const char * t)195 Fl_Glut_Window::Fl_Glut_Window(int X,int Y,int W,int H, const char *t) :
196   Fl_Gl_Window(X,Y,W,H,t) {_init();}
197 
198 static int initargc;
199 static char **initargv;
200 
glutInit(int * argc,char ** argv)201 void glutInit(int *argc, char **argv) {
202   initargc = *argc;
203   initargv = new char*[*argc+1];
204   int i,j;
205   for (i=0; i<=*argc; i++) initargv[i] = argv[i];
206   for (i=j=1; i<*argc; ) {
207     if (Fl::arg(*argc,argv,i));
208     else argv[j++] = argv[i++];
209   }
210   argv[j] = 0;
211   *argc = j;
212 }
213 
glutInitDisplayMode(unsigned int mode)214 void glutInitDisplayMode(unsigned int mode) {
215   glut_mode = mode;
216 }
217 
glutMainLoop()218 void glutMainLoop() {Fl::run();}
219 
220 ////////////////////////////////////////////////////////////////
221 
222 static int initx=0, inity=0, initw=300, inith=300, initpos=0;
223 
glutInitWindowPosition(int x,int y)224 void glutInitWindowPosition(int x, int y) {
225   initx = x; inity = y; initpos = 1;
226 }
227 
glutInitWindowSize(int w,int h)228 void glutInitWindowSize(int w, int h) {
229   initw = w; inith = h;
230 }
231 
glutCreateWindow(char * title)232 int glutCreateWindow(char *title) {
233   return glutCreateWindow((const char*)title);
234 }
235 
glutCreateWindow(const char * title)236 int glutCreateWindow(const char *title) {
237   Fl_Glut_Window *W;
238   if (initpos) {
239     W = new Fl_Glut_Window(initx,inity,initw,inith,title);
240     initpos = 0;
241   } else {
242     W = new Fl_Glut_Window(initw,inith,title);
243   }
244   W->resizable(W);
245   if (initargc) {
246     W->show(initargc,initargv);
247     initargc = 0;
248   } else {
249     W->show();
250   }
251   W->valid(0);
252   W->context_valid(0);
253   W->make_current();
254   return W->number;
255 }
256 
glutCreateSubWindow(int win,int x,int y,int w,int h)257 int glutCreateSubWindow(int win, int x, int y, int w, int h) {
258   Fl_Glut_Window *W = new Fl_Glut_Window(x,y,w,h,0);
259   windows[win]->add(W);
260   if (windows[win]->shown()) W->show();
261   W->make_current();
262   return W->number;
263 }
264 /** Destroys the glut window, first unregister it from the glut windows list */
~Fl_Glut_Window()265 Fl_Glut_Window::~Fl_Glut_Window() {
266   if (glut_window == this) glut_window = 0;
267   windows[number] = 0;
268 }
269 
glutDestroyWindow(int win)270 void glutDestroyWindow(int win) {
271   // should destroy children!!!
272   delete windows[win];
273 }
274 
glutPostWindowRedisplay(int win)275 void glutPostWindowRedisplay(int win) {
276   windows[win]->redraw();
277 }
278 
glutSetWindow(int win)279 void glutSetWindow(int win) {
280   windows[win]->make_current();
281 }
282 
283 ////////////////////////////////////////////////////////////////
284 #include <FL/Fl_Menu_Item.H>
285 
286 struct menu {
287   void (*cb)(int);
288   Fl_Menu_Item *m;
289   int size;
290   int alloc;
291 };
292 
293 #define MAXMENUS 32
294 static menu menus[MAXMENUS+1];
295 
domenu(int n,int ex,int ey)296 static void domenu(int n, int ex, int ey) {
297   glut_menu = n;
298   menu *m = &menus[n];
299   if (glut_menustate_function) glut_menustate_function(1);
300   if (glut_menustatus_function) glut_menustatus_function(1,ex,ey);
301   const Fl_Menu_Item* g = m->m->popup(Fl::event_x(), Fl::event_y(), 0);
302   if (g && g->callback_) ((void (*)(int))(g->callback_))(int(g->argument()));
303   if (glut_menustatus_function) glut_menustatus_function(0,ex,ey);
304   if (glut_menustate_function) glut_menustate_function(0);
305 }
306 
glutCreateMenu(void (* cb)(int))307 int glutCreateMenu(void (*cb)(int)) {
308   int i;
309   for (i=1; i<MAXMENUS; i++) if (!menus[i].cb) break;
310   menu *m = &menus[i];
311   m->cb = cb;
312   return glut_menu = i;
313 }
314 
glutDestroyMenu(int n)315 void glutDestroyMenu(int n) {
316   menu *m = &menus[n];
317   delete[] m->m;
318   m->m = 0;
319   m->cb = 0;
320   m->size = m->alloc = 0;
321 }
322 
additem(menu * m)323 static Fl_Menu_Item* additem(menu *m) {
324   if (m->size+1 >= m->alloc) {
325     m->alloc = m->size*2+10;
326     Fl_Menu_Item* nm = new Fl_Menu_Item[m->alloc];
327     for (int i=0; i<m->size; i++) nm[i] = m->m[i];
328     delete[] m->m;
329     m->m = nm;
330   }
331   int n = m->size++;
332   m->m[n+1].text = 0;
333   Fl_Menu_Item* i = &(m->m[n]);
334   i->shortcut_ = 0;
335   i->flags = 0;
336   i->labeltype_ = i->labelfont_ = i->labelsize_ = i->labelcolor_ = 0;
337   return i;
338 }
339 
glutAddMenuEntry(char * label,int value)340 void glutAddMenuEntry(char *label, int value) {
341   menu *m = &menus[glut_menu];
342   Fl_Menu_Item* i = additem(m);
343   i->text = label;
344   i->callback_ = (Fl_Callback*)(m->cb);
345   i->user_data_ = (void *)value;
346 }
347 
glutAddSubMenu(char * label,int submenu)348 void glutAddSubMenu(char *label, int submenu) {
349   menu *m = &menus[glut_menu];
350   Fl_Menu_Item* i = additem(m);
351   i->text = label;
352   i->callback_ = 0;
353   i->user_data_ = (void *)(menus[submenu].m);
354   i->flags = FL_PUP_SUBMENU;
355 }
356 
glutChangeToMenuEntry(int item,char * label,int value)357 void glutChangeToMenuEntry(int item, char *label, int value) {
358   menu *m = &menus[glut_menu];
359   Fl_Menu_Item* i = &m->m[item-1];
360   i->text = label;
361   i->callback_ = (Fl_Callback*)(m->cb);
362   i->user_data_ = (void *)value;
363   i->flags = 0;
364 }
365 
glutChangeToSubMenu(int item,char * label,int submenu)366 void glutChangeToSubMenu(int item, char *label, int submenu) {
367   menu *m = &menus[glut_menu];
368   Fl_Menu_Item* i = &m->m[item-1];
369   i->text = label;
370   i->callback_ = 0;
371   i->user_data_ = (void *)(menus[submenu].m);
372   i->flags = FL_PUP_SUBMENU;
373 }
374 
glutRemoveMenuItem(int item)375 void glutRemoveMenuItem(int item) {
376   menu *m = &menus[glut_menu];
377   if (item > m->size || item < 1) return;
378   for (int i = item-1; i <= m->size; i++) m->m[i] = m->m[i+1];
379   m->size--;
380 }
381 
382 ////////////////////////////////////////////////////////////////
383 
glutGet(GLenum type)384 int glutGet(GLenum type) {
385   switch (type) {
386   case GLUT_RETURN_ZERO: return 0;
387   case GLUT_WINDOW_X: return glut_window->x();
388   case GLUT_WINDOW_Y: return glut_window->y();
389   case GLUT_WINDOW_WIDTH: return glut_window->w();
390   case GLUT_WINDOW_HEIGHT: return glut_window->h();
391   case GLUT_WINDOW_PARENT:
392     if (glut_window->parent())
393       return ((Fl_Glut_Window *)(glut_window->parent()))->number;
394     else
395       return 0;
396 //case GLUT_WINDOW_NUM_CHILDREN:
397 //case GLUT_WINDOW_CURSOR: return
398   case GLUT_SCREEN_WIDTH: return Fl::w();
399   case GLUT_SCREEN_HEIGHT: return Fl::h();
400 //case GLUT_SCREEN_WIDTH_MM:
401 //case GLUT_SCREEN_HEIGHT_MM:
402   case GLUT_MENU_NUM_ITEMS: return menus[glut_menu].size;
403   case GLUT_DISPLAY_MODE_POSSIBLE: return Fl_Gl_Window::can_do(glut_mode);
404   case GLUT_INIT_WINDOW_X: return initx;
405   case GLUT_INIT_WINDOW_Y: return inity;
406   case GLUT_INIT_WINDOW_WIDTH: return initw;
407   case GLUT_INIT_WINDOW_HEIGHT: return inith;
408   case GLUT_INIT_DISPLAY_MODE: return glut_mode;
409 //case GLUT_ELAPSED_TIME:
410   case GLUT_WINDOW_BUFFER_SIZE:
411     if (glutGet(GLUT_WINDOW_RGBA))
412       return glutGet(GLUT_WINDOW_RED_SIZE)+
413 	glutGet(GLUT_WINDOW_GREEN_SIZE)+
414 	glutGet(GLUT_WINDOW_BLUE_SIZE)+
415 	glutGet(GLUT_WINDOW_ALPHA_SIZE);
416     else
417       return glutGet(GLUT_WINDOW_COLORMAP_SIZE);
418   case GLUT_VERSION: return 20400;
419   default: {GLint p; glGetIntegerv(type, &p); return p;}
420   }
421 }
422 
glutLayerGet(GLenum type)423 int glutLayerGet(GLenum type) {
424   switch (type) {
425   case GLUT_OVERLAY_POSSIBLE: return glut_window->can_do_overlay();
426 //case GLUT_LAYER_IN_USE:
427 //case GLUT_HAS_OVERLAY:
428   case GLUT_TRANSPARENT_INDEX: return 0; // true for SGI
429   case GLUT_NORMAL_DAMAGED: return glut_window->damage();
430   case GLUT_OVERLAY_DAMAGED: return 1; // kind of works...
431   default: return 0;
432   }
433 }
434 
glutDeviceGet(GLenum type)435 int glutDeviceGet(GLenum type) {
436   switch (type) {
437     case GLUT_HAS_KEYBOARD : return 1;
438     case GLUT_HAS_MOUSE : return 1;
439     case GLUT_NUM_MOUSE_BUTTONS : return 3;
440     default : return 0;
441   }
442 }
443 
444 // Get extension function address...
glutGetProcAddress(const char * procName)445 GLUTproc glutGetProcAddress(const char *procName) {
446 #  ifdef WIN32
447   return (GLUTproc)wglGetProcAddress((LPCSTR)procName);
448 
449 #  elif defined(HAVE_DLSYM) && defined(HAVE_DLFCN_H)
450   char symbol[1024];
451 
452   snprintf(symbol, sizeof(symbol), "_%s", procName);
453 
454 #    ifdef RTLD_DEFAULT
455   return (GLUTproc)dlsym(RTLD_DEFAULT, symbol);
456 
457 #    else // No RTLD_DEFAULT support, so open the current a.out symbols...
458   static void *rtld_default = 0;
459 
460   if (!rtld_default) rtld_default = dlopen(0, RTLD_LAZY);
461 
462   if (rtld_default) return (GLUTproc)dlsym(rtld_default, symbol);
463   else return 0;
464 
465 #    endif // RTLD_DEFAULT
466 
467 #  elif defined(HAVE_GLXGETPROCADDRESSARB)
468   return (GLUTproc)glXGetProcAddressARB((const GLubyte *)procName);
469 
470 #  else
471   return (GLUTproc)0;
472 #  endif // WIN32
473 }
474 
475 // Parse the GL_EXTENSIONS string to see if the named extension is
476 // supported.
477 //
478 // This code was copied from FreeGLUT 2.4.0 which carries the
479 // following notice:
480 //
481 //     Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
glutExtensionSupported(const char * extension)482 int glutExtensionSupported( const char* extension )
483 {
484   if (!extension || strchr(extension, ' ')) return 0;
485 
486   const char *extensions, *start;
487   const int len = strlen( extension );
488 
489   start = extensions = (const char *) glGetString(GL_EXTENSIONS);
490 
491   if (!extensions) return 0;
492 
493   for (;;) {
494     const char *p = strstr(extensions, extension);
495     if (!p) return 0;  /* not found */
496     /* check that the match isn't a super string */
497     if ((p == start || p[-1] == ' ') &&
498         (p[len] == ' ' || p[len] == 0)) return 1;
499     /* skip the false match and continue */
500     extensions = p + len;
501   }
502 }
503 
504 // Add a mechanism to handle adding/removing the glut idle function
505 // without depending on the (deprecated) set_idle method.
glutIdleFunc(void (* f)())506 void glutIdleFunc(void (*f)())
507 {
508   // no change
509   if(glut_idle_func == f) return;
510   // remove current idle
511   if(glut_idle_func) Fl::remove_idle((void (*)(void *))glut_idle_func);
512   // install new idle func - if one was passed
513   if(f) Fl::add_idle((void (*)(void *))f);
514   // record new idle func - even if it is NULL
515   glut_idle_func = f;
516 } // glutIdleFunc
517 
518 #endif // HAVE_GL
519 
520 //
521 // End of "$Id: glut_compatability.cxx 7818 2010-11-11 18:22:43Z engelsman $".
522 //
523