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