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