0d4dbb7a5e638c192e21f0704aaf07ad68ef903f
[freeglut] / progs / demos / CallbackMaker / CallbackMaker.c
1 /* CallbackMaker.c */
2 /*
3  * Program to invoke all the callbacks that "freeglut" supports
4  */
5
6
7 #include <GL/freeglut.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <stdarg.h>
11
12 static int sequence_number = 0 ;
13
14 #define CALLBACKMAKER_N_WINDOWS 4
15 int windows[CALLBACKMAKER_N_WINDOWS] = {0};
16
17 /* define status vars showing whether given callback has been called for given window */
18 #define CALLBACK_CALLED_VAR(name)                            int name##_called[CALLBACKMAKER_N_WINDOWS]   = {0};
19 #define CALLBACK_0V(name)                                    int name##_seq[CALLBACKMAKER_N_WINDOWS]      = {-1}; CALLBACK_CALLED_VAR(name); 
20 #define CALLBACK_1V(name,field)                              int name##_##field[CALLBACKMAKER_N_WINDOWS]  = {-1}; CALLBACK_0V(name);
21 #define CALLBACK_2V(name,field1,field2)                      int name##_##field2[CALLBACKMAKER_N_WINDOWS] = {-1}; CALLBACK_1V(name,field1);
22 #define CALLBACK_3V(name,field1,field2,field3)               int name##_##field3[CALLBACKMAKER_N_WINDOWS] = {-1}; CALLBACK_2V(name,field1,field2);
23 #define CALLBACK_4V(name,field1,field2,field3,field4)        int name##_##field4[CALLBACKMAKER_N_WINDOWS] = {-1}; CALLBACK_3V(name,field1,field2,field3);
24 #define CALLBACK_5V(name,field1,field2,field3,field4,field5) int name##_##field5[CALLBACKMAKER_N_WINDOWS] = {-1}; CALLBACK_4V(name,field1,field2,field3,field4);
25 CALLBACK_2V(reshape,width,height);
26 CALLBACK_2V(position,top,left);
27 CALLBACK_1V(visibility,vis);
28 CALLBACK_1V(windowStatus,state);
29 CALLBACK_4V(key,key,x,y,mod);
30 CALLBACK_4V(keyup,key,x,y,mod);
31 CALLBACK_4V(special,key,x,y,mod);
32 CALLBACK_4V(specialup,key,x,y,mod);
33 CALLBACK_4V(joystick,a,b,c,d);
34 CALLBACK_5V(mouse,button,updown,x,y,mod);
35 CALLBACK_5V(mousewheel,number,direction,x,y,mod);
36 CALLBACK_3V(motion,x,y,mod);
37 CALLBACK_3V(passivemotion,x,y,mod);
38 CALLBACK_1V(entry,state);
39 CALLBACK_0V(close);
40 /* menudestroy is registered on each menu, not a window */
41 int menudestroy_called = 0 ;
42 /* menustatus and menustate are global callbacks, set for all menus at the same time */
43 int menustatus_called = 0;
44 int menustate_called = 0;
45
46 #define STRING_LENGTH   10
47
48 static void
49 bitmapPrintf (const char *fmt, ...)
50 {
51     static char buf[256];
52     va_list args;
53
54     va_start(args, fmt);
55 #if defined(WIN32) && !defined(__CYGWIN__)
56     (void) _vsnprintf (buf, sizeof(buf), fmt, args);
57 #else
58     (void) vsnprintf (buf, sizeof(buf), fmt, args);
59 #endif
60     va_end(args);
61     glutBitmapString ( GLUT_BITMAP_HELVETICA_12, (unsigned char*)buf ) ;
62 }
63
64 static int
65 getWindowAndIdx(int *winIdx)
66 {
67     int window = glutGetWindow();
68
69     if (winIdx)
70         (*winIdx) = window==windows[0] ? 0 :
71                     window==windows[1] ? 1 :
72                     window==windows[2] ? 2 : 3;
73
74     return window;
75 }
76
77 static void
78 Mod2Text(int mods, char *text)
79 {
80     if (mods&GLUT_ACTIVE_CTRL)
81         strcat(text,"CTRL");
82     if (mods&GLUT_ACTIVE_SHIFT)
83         if (text[0])
84             strcat(text,"+SHIFT");
85         else
86             strcat(text,"SHIFT");
87     if (mods&GLUT_ACTIVE_ALT)
88         if (text[0])
89             strcat(text,"+ALT");
90         else
91             strcat(text,"ALT");
92
93     if (!text[0])
94         strcat(text,"none");
95 }
96
97 static void 
98 Display(void)
99 {
100   int winIdx;
101   int window = getWindowAndIdx(&winIdx);
102   glClear ( GL_COLOR_BUFFER_BIT );
103
104   glDisable ( GL_DEPTH_TEST );
105   glMatrixMode ( GL_PROJECTION );
106   glPushMatrix();
107   glLoadIdentity();
108   glOrtho(0, glutGet ( GLUT_WINDOW_WIDTH ), 
109           0, glutGet ( GLUT_WINDOW_HEIGHT ), -1, 1 );
110   glMatrixMode ( GL_MODELVIEW );
111   glPushMatrix ();
112   glLoadIdentity ();
113   glColor3ub ( 0, 0, 0 );
114   glRasterPos2i ( 10, glutGet ( GLUT_WINDOW_HEIGHT ) - 20 );    /* 10pt margin above 10pt letters */
115
116   if ( entry_called[winIdx] )
117   {
118     bitmapPrintf ( "Entry %d:  %d\n", entry_seq[winIdx], entry_state[winIdx] );
119   }
120   
121   if ( visibility_called[winIdx] )
122   {
123     bitmapPrintf ( "Visibility %d:  %d\n", visibility_seq[winIdx], visibility_vis[winIdx] );
124   }
125
126   if ( windowStatus_called[winIdx] )
127   {
128     bitmapPrintf ( "WindowStatus %d:  %d\n", windowStatus_seq[winIdx], windowStatus_state[winIdx] );
129   }
130
131   if ( reshape_called[winIdx] )
132   {
133     bitmapPrintf ( "Reshape %d:  %d %d\n", reshape_seq[winIdx], reshape_width[winIdx], reshape_height[winIdx] );
134   }
135
136   if ( position_called[winIdx] )
137   {
138     bitmapPrintf ( "Position %d:  %d %d\n", position_seq[winIdx], position_left[winIdx], position_top[winIdx] );
139   }
140
141   if ( key_called[winIdx] )
142   {
143     char mods[50] = {0};
144     Mod2Text(key_mod[winIdx],mods);
145     bitmapPrintf ( "Key %d:  %d(%c) %d %d (mod: %s)\n", key_seq[winIdx], key_key[winIdx], key_key[winIdx], key_x[winIdx], key_y[winIdx], mods );
146   }
147
148   if ( keyup_called[winIdx] )
149   {
150     char mods[50] = {0};
151     Mod2Text(keyup_mod[winIdx],mods);
152     bitmapPrintf ( "Key Up %d:  %d(%c) %d %d (mod: %s)\n", keyup_seq[winIdx], keyup_key[winIdx], keyup_key[winIdx], keyup_x[winIdx], keyup_y[winIdx], mods );
153   }
154
155   if ( special_called[winIdx] )
156   {
157     char mods[50] = {0};
158     Mod2Text(special_mod[winIdx],mods);
159     bitmapPrintf ( "Special %d:  %d(%c) %d %d (mod: %s)\n", special_seq[winIdx], special_key[winIdx], special_key[winIdx], special_x[winIdx], special_y[winIdx], mods );
160   }
161
162   if ( specialup_called[winIdx] )
163   {
164     char mods[50] = {0};
165     Mod2Text(specialup_mod[winIdx],mods);
166     bitmapPrintf ( "Special Up %d:  %d(%c) %d %d (mod: %s)\n", specialup_seq[winIdx], specialup_key[winIdx], specialup_key[winIdx], specialup_x[winIdx], specialup_y[winIdx], mods );
167   }
168
169   if ( joystick_called[winIdx] )
170   {
171     bitmapPrintf ( "Joystick %d:  %d %d %d %d\n", joystick_seq[winIdx], joystick_a[winIdx], joystick_b[winIdx], joystick_c[winIdx], joystick_d[winIdx] );
172   }
173
174   if ( mouse_called[winIdx] )
175   {
176     char mods[50] = {0};
177     Mod2Text(mouse_mod[winIdx],mods);
178     bitmapPrintf ( "Mouse %d:  %d %d %d %d (mod: %s)\n", mouse_seq[winIdx], mouse_button[winIdx], mouse_updown[winIdx], mouse_x[winIdx], mouse_y[winIdx], mods );
179   }
180
181   if ( mousewheel_called[winIdx] )
182   {
183     char mods[50] = {0};
184     Mod2Text(mousewheel_mod[winIdx],mods);
185     bitmapPrintf ( "Mouse Wheel %d:  %d %d %d %d (mod: %s)\n", mousewheel_seq[winIdx], mousewheel_number[winIdx], mousewheel_direction[winIdx], mousewheel_x[winIdx], mousewheel_y[winIdx], mods );
186   }
187
188   if ( motion_called[winIdx] )
189   {
190     char mods[50] = {0};
191     Mod2Text(motion_mod[winIdx],mods);
192     bitmapPrintf ( "Motion %d:  %d %d (mod: %s)\n", motion_seq[winIdx], motion_x[winIdx], motion_y[winIdx], mods );
193   }
194
195   if ( passivemotion_called[winIdx] )
196   {
197     char mods[50] = {0};
198     Mod2Text(passivemotion_mod[winIdx],mods);
199     bitmapPrintf ( "Passive Motion %d:  %d %d (mod: %s)\n", passivemotion_seq[winIdx], passivemotion_x[winIdx], passivemotion_y[winIdx], mods );
200   }
201
202   glMatrixMode ( GL_PROJECTION );
203   glPopMatrix ();
204   glMatrixMode ( GL_MODELVIEW );
205   glPopMatrix ();
206   glEnable ( GL_DEPTH_TEST );
207
208   printf ( "%6d Window %d Display Callback\n",
209             ++sequence_number, window ) ;
210   glutSwapBuffers();
211 }
212
213 static void
214 Warning(const char *fmt, va_list ap)
215 {
216     printf("%6d Warning callback:\n");
217
218     /* print warning message */
219     vprintf(fmt, ap);
220 }
221
222 static void
223 Error(const char *fmt, va_list ap)
224 {
225     char dummy_string[STRING_LENGTH];
226     printf("%6d Error callback:\n");
227
228     /* print warning message */
229     vprintf(fmt, ap);
230     printf("\n");
231
232     /* terminate program, after pause for input so user can see */
233     printf ( "Please enter something to exit: " );
234     fgets ( dummy_string, STRING_LENGTH, stdin );
235
236     /* Call exit directly as freeglut is messed
237      * up internally when an error is called. 
238      */
239     exit(1);
240 }
241
242 static void 
243 Reshape(int width, int height)
244 {
245   int winIdx;
246   int window = getWindowAndIdx(&winIdx);
247   printf ( "%6d Window %d Reshape Callback:  %d %d\n",
248             ++sequence_number, window, width, height ) ;
249   reshape_called[winIdx] = 1 ;
250   reshape_width[winIdx] = width ;
251   reshape_height[winIdx] = height ;
252   reshape_seq[winIdx] = sequence_number ;
253   glViewport(0,0,width,height);
254   glutPostRedisplay () ;
255 }
256
257 static void 
258 Position(int left, int top)
259 {
260   int winIdx;
261   int window = getWindowAndIdx(&winIdx);
262   printf ( "%6d Window %d Position Callback:  %d %d\n",
263             ++sequence_number, window, left, top ) ;
264   position_called[winIdx] = 1 ;
265   position_left[winIdx] = left ;
266   position_top[winIdx] = top ;
267   position_seq[winIdx] = sequence_number ;
268   glutPostRedisplay () ;
269 }
270
271 static void 
272 Key(unsigned char key, int x, int y)
273 {
274   int winIdx;
275   int window = getWindowAndIdx(&winIdx);
276   printf ( "%6d Window %d Keyboard Callback:  %d %d %d\n",
277             ++sequence_number, window, key, x, y ) ;
278   key_called[winIdx] = 1 ;
279   key_key[winIdx] = key ;
280   key_x[winIdx] = x ;
281   key_y[winIdx] = y ;
282   key_seq[winIdx] = sequence_number ;
283   key_mod[winIdx] = glutGetModifiers() ;
284   glutPostRedisplay () ;
285 }
286
287 static void 
288 KeyUp(unsigned char key, int x, int y)
289 {
290   int winIdx;
291   int window = getWindowAndIdx(&winIdx);
292   printf ( "%6d Window %d Key Release Callback:  %d %d %d\n",
293             ++sequence_number, window, key, x, y ) ;
294   keyup_called[winIdx] = 1 ;
295   keyup_key[winIdx] = key ;
296   keyup_x[winIdx] = x ;
297   keyup_y[winIdx] = y ;
298   keyup_seq[winIdx] = sequence_number ;
299   keyup_mod[winIdx] = glutGetModifiers() ;
300   glutPostRedisplay () ;
301 }
302
303 static void 
304 Special(int key, int x, int y)
305 {
306   int winIdx;
307   int window = getWindowAndIdx(&winIdx);
308   printf ( "%6d Window %d Special Key Callback:  %d %d %d\n",
309             ++sequence_number, window, key, x, y ) ;
310   special_called[winIdx] = 1 ;
311   special_key[winIdx] = key ;
312   special_x[winIdx] = x ;
313   special_y[winIdx] = y ;
314   special_seq[winIdx] = sequence_number ;
315   special_mod[winIdx] = glutGetModifiers() ;
316   glutPostRedisplay () ;
317 }
318
319 static void 
320 SpecialUp(int key, int x, int y)
321 {
322   int winIdx;
323   int window = getWindowAndIdx(&winIdx);
324   printf ( "%6d Window %d Special Key Release Callback:  %d %d %d\n",
325             ++sequence_number, window, key, x, y ) ;
326   specialup_called[winIdx] = 1 ;
327   specialup_key[winIdx] = key ;
328   specialup_x[winIdx] = x ;
329   specialup_y[winIdx] = y ;
330   specialup_seq[winIdx] = sequence_number ;
331   specialup_mod[winIdx] = glutGetModifiers() ;
332   glutPostRedisplay () ;
333 }
334
335 static void 
336 Joystick( unsigned int a, int b, int c, int d)  /* Need meaningful names */
337 {
338   int winIdx;
339   int window = getWindowAndIdx(&winIdx);
340   printf ( "%6d Window %d Joystick Callback:  %d %d %d %d\n",
341             ++sequence_number, window, a, b, c, d ) ;
342   joystick_called[winIdx] = 1 ;
343   joystick_a[winIdx] = a ;
344   joystick_b[winIdx] = b ;
345   joystick_c[winIdx] = c ;
346   joystick_d[winIdx] = d ;
347   joystick_seq[winIdx] = sequence_number ;
348   glutPostRedisplay () ;
349 }
350
351 static void 
352 Mouse(int button, int updown, int x, int y)
353 {
354   int winIdx;
355   int window = getWindowAndIdx(&winIdx);
356   printf ( "%6d Window %d Mouse Click Callback:  %d %d %d %d\n",
357             ++sequence_number, window, button, updown, x, y ) ;
358   mouse_called[winIdx] = 1 ;
359   mouse_button[winIdx] = button ;
360   mouse_updown[winIdx] = updown ;
361   mouse_x[winIdx] = x ;
362   mouse_y[winIdx] = y ;
363   mouse_seq[winIdx] = sequence_number ;
364   mouse_mod[winIdx] = glutGetModifiers() ;
365   glutPostRedisplay () ;
366 }
367
368 static void 
369 MouseWheel(int wheel_number, int direction, int x, int y)
370 {
371   int winIdx;
372   int window = getWindowAndIdx(&winIdx);
373   printf ( "%6d Window %d Mouse Wheel Callback:  %d %d %d %d\n",
374             ++sequence_number, window, wheel_number, direction, x, y ) ;
375   mousewheel_called[winIdx] = 1 ;
376   mousewheel_number[winIdx] = wheel_number ;
377   mousewheel_direction[winIdx] = direction ;
378   mousewheel_x[winIdx] = x ;
379   mousewheel_y[winIdx] = y ;
380   mousewheel_seq[winIdx] = sequence_number ;
381   mousewheel_mod[winIdx] = glutGetModifiers() ;
382   glutPostRedisplay () ;
383 }
384
385 static void 
386 Motion(int x, int y)
387 {
388   int winIdx;
389   int window = getWindowAndIdx(&winIdx);
390   printf ( "%6d Window %d Mouse Motion Callback:  %d %d\n",
391             ++sequence_number, window, x, y ) ;
392   motion_called[winIdx] = 1 ;
393   motion_x[winIdx] = x ;
394   motion_y[winIdx] = y ;
395   motion_seq[winIdx] = sequence_number ;
396   motion_mod[winIdx] = glutGetModifiers() ;
397   glutPostRedisplay () ;
398 }
399
400 static void 
401 PassiveMotion(int x, int y)
402 {
403   int winIdx;
404   int window = getWindowAndIdx(&winIdx);
405   printf ( "%6d Window %d Mouse Passive Motion Callback:  %d %d\n",
406             ++sequence_number, window, x, y ) ;
407   passivemotion_called[winIdx] = 1 ;
408   passivemotion_x[winIdx] = x ;
409   passivemotion_y[winIdx] = y ;
410   passivemotion_seq[winIdx] = sequence_number ;
411   passivemotion_mod[winIdx] = glutGetModifiers() ;
412   glutPostRedisplay () ;
413 }
414
415 static void 
416 Entry(int state)
417 {
418   int winIdx;
419   int window = getWindowAndIdx(&winIdx);
420   printf ( "%6d Window %d Entry Callback:  %d\n",
421             ++sequence_number, window, state ) ;
422   entry_called[winIdx] = 1 ;
423   entry_seq[winIdx] = sequence_number;
424   entry_state[winIdx] = state;
425   glutPostRedisplay () ;
426 }
427
428 static void 
429 Close(void)
430 {
431   int window = getWindowAndIdx(NULL);
432   printf ( "%6d Window %d Close Callback\n",
433             ++sequence_number, window ) ;
434 }
435
436 static void 
437 OverlayDisplay(void)
438 {
439   int window = getWindowAndIdx(NULL);
440   printf ( "%6d Window %d OverlayDisplay Callback\n",
441             ++sequence_number, window ) ;
442   glutPostRedisplay () ;
443 }
444
445 static void 
446 Visibility(int vis)
447 {
448   int winIdx;
449   int window = getWindowAndIdx(&winIdx);
450   printf ( "%6d Window %d Visibility Callback:  %d\n",
451             ++sequence_number, window, vis ) ;
452   visibility_called[winIdx] = 1 ;
453   visibility_vis[winIdx] = vis ;
454   visibility_seq[winIdx] = sequence_number ;
455   glutPostRedisplay () ;
456 }
457
458 static void 
459 WindowStatus(int state)
460 {
461   int winIdx;
462   int window = getWindowAndIdx(&winIdx);
463   printf ( "%6d Window %d WindowStatus Callback:  %d\n",
464             ++sequence_number, window, state ) ;
465   windowStatus_called[winIdx] = 1 ;
466   windowStatus_state[winIdx] = state ;
467   windowStatus_seq[winIdx] = sequence_number ;
468   glutPostRedisplay () ;
469 }
470
471 static void 
472 SpaceMotion(int x, int y, int z)
473 {
474   int window = getWindowAndIdx(NULL);
475   printf ( "%6d Window %d SpaceMotion Callback:  %d %d %d\n",
476             ++sequence_number, window, x, y, z ) ;
477   glutPostRedisplay () ;
478 }
479
480 static void 
481 SpaceRotation(int x, int y, int z)
482 {
483   int window = getWindowAndIdx(NULL);
484   printf ( "%6d Window %d SpaceRotation Callback:  %d %d %d\n",
485             ++sequence_number, window, x, y, z ) ;
486   glutPostRedisplay () ;
487 }
488
489 static void 
490 SpaceButton(int button, int updown)
491 {
492   int window = getWindowAndIdx(NULL);
493   printf ( "%6d Window %d SpaceButton Callback:  %d %d\n",
494             ++sequence_number, window, button, updown ) ;
495   glutPostRedisplay () ;
496 }
497
498 static void 
499 Dials(int x, int y)
500 {
501   int window = getWindowAndIdx(NULL);
502   printf ( "%6d Window %d Dials Callback:  %d %d\n",
503             ++sequence_number, window, x, y ) ;
504   glutPostRedisplay () ;
505 }
506
507 static void 
508 ButtonBox(int button, int updown)
509 {
510   int window = getWindowAndIdx(NULL);
511   printf ( "%6d Window %d ButtonBox Callback:  %d %d\n",
512             ++sequence_number, window, button, updown ) ;
513   glutPostRedisplay () ;
514 }
515
516 static void 
517 TabletMotion(int x, int y)
518 {
519   int window = getWindowAndIdx(NULL);
520   printf ( "%6d Window %d TabletMotion Callback:  %d %d\n",
521             ++sequence_number, window, x, y ) ;
522   glutPostRedisplay () ;
523 }
524
525 static void 
526 TabletButton(int button, int updown, int x, int y)
527 {
528   int window = getWindowAndIdx(NULL);
529   printf ( "%6d Window %d TabletButton Callback:  %d %d %d %d\n",
530             ++sequence_number, window, button, updown, x, y ) ;
531   glutPostRedisplay () ;
532 }
533
534 static void
535 MenuCallback ( int value )
536 {
537   int menu = glutGetMenu();
538   int window = getWindowAndIdx(NULL);
539   printf( "%6d Menu %d MenuCallback for menu opened in Window %d - value is %d\n",
540           ++sequence_number, menu, window, value );
541 }
542
543 static void 
544 MenuDestroy( void )
545 {
546   int menu = glutGetMenu();
547   menudestroy_called = 1 ;
548   printf ( "%6d Menu %d MenuDestroy Callback\n",
549             ++sequence_number, menu ) ;
550 }
551
552 static void 
553 MenuStatus( int status, int x, int y )
554 {
555   /* Menu and window for which this event is triggered are current when the callback is called */
556   int menu = glutGetMenu();
557   int window = getWindowAndIdx(NULL);
558   menustatus_called = 1 ;
559   printf ( "%6d Menu %d MenuStatus Callback in Window %d:  %d %d %d\n",
560             ++sequence_number, menu, window, status, x, y ) ;
561   glutPostRedisplay () ;
562 }
563
564
565 static void 
566 MenuState( int status )
567 {
568   /* Menu and window for which this event is triggered are current when the callback is called */
569   int menu = glutGetMenu();
570   int window = getWindowAndIdx(NULL);
571   menustate_called = 1 ;
572   printf ( "%6d Menu %d MenuState Callback in Window %d:  %d\n",
573             ++sequence_number, menu, window, status) ;
574   glutPostRedisplay () ;
575 }
576
577 static void Idle ( void )
578 {
579   ++sequence_number ;
580 }
581
582 static void SetWindowCallbacks( int first )
583 {
584     /* All these callbacks are set for only the current window */
585     glutDisplayFunc( Display );
586     glutReshapeFunc( Reshape );
587     glutPositionFunc( Position );
588     glutKeyboardFunc( Key );
589     glutSpecialFunc( Special );
590     glutKeyboardUpFunc( KeyUp );
591     glutSpecialUpFunc( SpecialUp );
592     if (first)
593         glutJoystickFunc( Joystick, 100 );
594     glutMouseFunc ( Mouse ) ;
595     glutMouseWheelFunc ( MouseWheel ) ;
596     glutMotionFunc ( Motion ) ;
597     glutPassiveMotionFunc ( PassiveMotion ) ;
598     glutEntryFunc ( Entry ) ;
599     glutCloseFunc ( Close ) ;
600     glutOverlayDisplayFunc ( OverlayDisplay ) ;
601     glutSpaceballMotionFunc ( SpaceMotion ) ;
602     glutSpaceballRotateFunc ( SpaceRotation ) ;
603     glutSpaceballButtonFunc ( SpaceButton ) ;
604     glutButtonBoxFunc ( ButtonBox ) ;
605     glutDialsFunc ( Dials ) ;
606     glutTabletMotionFunc ( TabletMotion ) ;
607     glutTabletButtonFunc ( TabletButton ) ;
608     /* glutVisibilityFunc is deprecated in favor of glutWindowStatusFunc, which provides more detail.
609      * Setting one of these overwrites the other (see docs).
610      */
611     glutVisibilityFunc ( Visibility );  /* This will thus never be called, as glutWindowStatusFunc is set afterwards */
612     glutWindowStatusFunc ( WindowStatus ) ;
613 }
614
615 int 
616 main(int argc, char *argv[])
617 {
618   char dummy_string[STRING_LENGTH];
619
620   int menuID, subMenuA, subMenuB;
621
622   glutInitWarningFunc(Warning);
623   glutInitErrorFunc(Error);
624   glutInitWindowSize(500, 250);
625   glutInitWindowPosition ( 140, 140 );
626   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE );
627   glutInit(&argc, argv);
628   /* global setting: mainloop does not return when a window is closed, only returns when all windows are closed */
629   glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE,GLUT_ACTION_CONTINUE_EXECUTION);
630   /* global setting: repeated keys generating by keeping the key pressed down are passed on to the keyboard callback */
631   /* There are two functions to control this behavior, glutSetKeyRepeat to set it globally, and glutIgnoreKeyRepeat to set it per window.
632    * These two interact however. If key repeat is globally switched off (glutSetKeyRepeat(GLUT_KEY_REPEAT_OFF)), it cannot be overridden
633    * (switched back on) for a specific window with glutIgnoreKeyRepeat. However, if key repeat is globally switched on
634    * (glutSetKeyRepeat(GLUT_KEY_REPEAT_ON)), it can be overridden (switched off) with glutIgnoreKeyRepeat on a per-window basis. That is
635    * what we demonstrate here.
636    */
637   glutSetKeyRepeat(GLUT_KEY_REPEAT_ON);
638
639   /* Set other global callback (global as in not associated with any specific menu or window) */
640   glutIdleFunc ( Idle );
641   glutMenuStatusFunc ( MenuStatus );
642   glutMenuStateFunc  ( MenuState ); /* Note that glutMenuStatusFunc is an enhanced version of the deprecated glutMenuStateFunc. */
643
644
645   /* Open first window */
646   windows[0] = glutCreateWindow( "Callback Demo" );
647   printf ( "Creating window %d as 'Callback Demo'\n", windows[0] ) ;
648
649   glClearColor(1.0, 1.0, 1.0, 1.0);
650
651   /* callbacks, settings and menus for this window */
652   SetWindowCallbacks( 1 );
653   glutIgnoreKeyRepeat(GL_TRUE);
654   glutSetIconTitle("Icon Test - Callback Demo");
655
656   subMenuA = glutCreateMenu( MenuCallback );
657   glutAddMenuEntry( "Sub menu A1 (01)", 11 );
658   glutAddMenuEntry( "Sub menu A2 (02)", 12 );
659   glutAddMenuEntry( "Sub menu A3 (03)", 13 );
660   glutMenuDestroyFunc ( MenuDestroy );  /* callback specific to this menu */
661
662   subMenuB = glutCreateMenu( MenuCallback );
663   glutAddMenuEntry( "Sub menu B1 (04)", 14 );
664   glutAddMenuEntry( "Sub menu B2 (05)", 15 );
665   glutAddMenuEntry( "Sub menu B3 (06)", 16 );
666   glutAddSubMenu( "Going to sub menu A", subMenuA );
667   glutMenuDestroyFunc ( MenuDestroy );  /* callback specific to this menu */
668
669   menuID = glutCreateMenu( MenuCallback );
670   glutAddMenuEntry( "Entry one",   21 );
671   glutAddMenuEntry( "Entry two",   22 );
672   glutAddMenuEntry( "Entry three", 23 );
673   glutAddMenuEntry( "Entry four",  24 );
674   glutAddMenuEntry( "Entry five",  25 );
675   glutAddSubMenu( "Enter sub menu A", subMenuA );
676   glutAddSubMenu( "Enter sub menu B", subMenuB );
677   glutMenuDestroyFunc ( MenuDestroy );  /* callback specific to this menu */
678
679   glutAttachMenu( GLUT_LEFT_BUTTON );
680
681
682   /* Position second window right next to the first */
683   glutInitWindowPosition ( 140+500+2*glutGet(GLUT_WINDOW_BORDER_WIDTH), 140 );
684   glutInitWindowSize(600, 600);
685   windows[1] = glutCreateWindow( "Second Window" );
686   printf ( "Creating window %d as 'Second Window'\n", windows[1] ) ;
687
688   glClearColor(1.0, 1.0, 1.0, 1.0);
689
690   /* callbacks, settings and menus for this window */
691   SetWindowCallbacks( 0 );
692   glutIgnoreKeyRepeat(GL_TRUE);
693
694   glutSetMenu(subMenuB);
695   glutAttachMenu( GLUT_RIGHT_BUTTON );
696
697
698   /* position a third window as a subwindow of the second */
699   windows[2] = glutCreateSubWindow(windows[1],0,300,600,300);
700   printf ( "Creating window %d as subwindow to 'Second Window'\n", windows[2] ) ;
701
702   glClearColor(0.7f, 0.7f, 0.7f, 1.0);
703
704   /* callbacks, settings and menus for this window */
705   SetWindowCallbacks( 0 );
706   glutSetCursor(GLUT_CURSOR_CROSSHAIR); /* Cursors are per window */
707
708   glutSetMenu(subMenuA);
709   glutAttachMenu( GLUT_RIGHT_BUTTON );
710
711
712   /* position a fourth window as a subsubwindow (grandchild) of the second */
713   windows[3] = glutCreateSubWindow(windows[2],300,0,300,300);
714   printf ( "Creating window %d as subsubwindow to 'Second Window'\n", windows[3] ) ;
715
716   glClearColor(0.4f, 0.4f, 0.4f, 1.0);
717
718   /* callbacks and menus for this window */
719   SetWindowCallbacks( 0 );
720   glutSetCursor(GLUT_CURSOR_INHERIT);   /* Inherit cursor look from parent (this is default on window creation) - comment the below to see in action */
721   glutSetCursor(GLUT_CURSOR_CYCLE);
722
723
724   printf ( "Please enter something to continue: " );
725   fgets ( dummy_string, STRING_LENGTH, stdin );
726
727   glutMainLoop();
728
729   printf ( "Back from the 'freeglut' main loop\n" ) ;
730
731   return EXIT_SUCCESS;
732 }