1 /**************************************************************************
2 * coolwave2.c
3 *
4 * Copyright (c) 2002 Alif Wahid <awah005@users.sourceforge.net>
5 *
6 * A program to demonstrate GtkGLExt. It's a modified version
7 * of the old IrisGL demo 'newave', first ported to OpenGL and
8 * Glut by Erik Larsen. Now I have modified it to use Gtk and GtkGLExt
9 * comprehensively along with ofcourse OpenGL.
10 *
11 * This program is in the public domain and you are using it at
12 * your own risk.
13 *
14 **************************************************************************/
15
16 /*
17 * Modified by Naofumi Yasufuku <naofumi@users.sourceforge.net>
18 */
19
20 /* September, 2003.
21 *
22 * A slightly different version from the coolwave.c example program. Here
23 * the primary goal is to test how well GtkGLExt works with GTK's
24 * ability to display a window in fullscreen mode. It's quite nice to have
25 * a 3D animation displayed in fullscreen mode!
26 *
27 * So just use the menu items to change between the fullscreen and normal
28 * size mode.
29 *
30 * Alif Wahid.
31 */
32
33 /**************************************************************************
34 * Header file inclusions.
35 **************************************************************************/
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <math.h>
40
41 #include <gtk/gtk.h>
42 #include <gdk/gdkkeysyms.h>
43
44 #include <gtk/gtkgl.h>
45 /*** Use OpenGL extensions. ***/
46 #include <gdk/gdkglglext.h>
47
48 #ifdef G_OS_WIN32
49 #define WIN32_LEAN_AND_MEAN 1
50 #include <windows.h>
51 #endif
52
53 #include <GL/gl.h>
54 #include <GL/glu.h>
55
56
57 /**************************************************************************
58 * The following section contains all the macro definitions.
59 **************************************************************************/
60
61 #define DEFAULT_WIDTH 300
62 #define DEFAULT_HEIGHT 200
63 #define DEFAULT_TITLE "CoolWave2"
64
65 #define TIMEOUT_INTERVAL 10
66
67 #define MAXGRID 64
68 #define SQRTOFTWOINV (1.0 / 1.414213562)
69
70
71 /**************************************************************************
72 * Global variable declarations.
73 **************************************************************************/
74
75 static gboolean animate = TRUE;
76
77 static int grid = (MAXGRID/2);
78 static int beginX, beginY;
79
80 static float force[MAXGRID][MAXGRID];
81 static float veloc[MAXGRID][MAXGRID];
82 static float posit[MAXGRID][MAXGRID];
83
84 static float dt = 0.008;
85 static float sphi = 90.0;
86 static float stheta = 45.0;
87 static float sdepth = 5.0/4.0 * (MAXGRID/2);
88 static float zNear = (MAXGRID/2)/10.0;
89 static float zFar = (MAXGRID/2)*3.0;
90 static float aspect = 5.0/4.0;
91
92 static float lightPosition[4] = {0.0, 0.0, 1.0, 1.0};
93
94
95 /**************************************************************************
96 * The following section contains the function prototype declarations.
97 **************************************************************************/
98
99 static void timeout_add (GtkWidget *widget);
100 static void timeout_remove (GtkWidget *widget);
101
102 static void toggle_animation (GtkWidget *widget);
103 static void init_wireframe (GtkWidget *widget);
104
105 static GdkGLConfig *configure_gl (void);
106
107 static GtkWidget *create_popup_menu (GtkWidget *window, GtkWidget *drawing_area);
108 static GtkWidget *create_window (GdkGLConfig *glconfig);
109
110
111 /**************************************************************************
112 * The waving functions.
113 **************************************************************************/
114
getforce(void)115 void getforce (void)
116 {
117 int i=0, j=0;
118 float d;
119
120 for(i=0;i<grid;i++)
121 {
122 for(j=0;j<grid;j++)
123 {
124 force[i][j]=0.0;
125 }
126 }
127
128 for(i=2;i<grid-2;i++)
129 {
130 for(j=2;j<grid-2;j++)
131 {
132 d=posit[i][j]-posit[i][j-1];
133 force[i][j] -= d;
134 force[i][j-1] += d;
135
136 d=posit[i][j]-posit[i-1][j];
137 force[i][j] -= d;
138 force[i-1][j] += d;
139
140 d= (posit[i][j]-posit[i][j+1]);
141 force[i][j] -= d ;
142 force[i][j+1] += d;
143
144 d= (posit[i][j]-posit[i+1][j]);
145 force[i][j] -= d ;
146 force[i+1][j] += d;
147
148 d= (posit[i][j]-posit[i+1][j+1])*SQRTOFTWOINV;
149 force[i][j] -= d ;
150 force[i+1][j+1] += d;
151
152 d= (posit[i][j]-posit[i-1][j-1])*SQRTOFTWOINV;
153 force[i][j] -= d ;
154 force[i-1][j-1] += d;
155
156 d= (posit[i][j]-posit[i+1][j-1])*SQRTOFTWOINV;
157 force[i][j] -= d ;
158 force[i+1][j-1] += d;
159
160 d= (posit[i][j]-posit[i-1][j+1])*SQRTOFTWOINV;
161 force[i][j] -= d ;
162 force[i- 1][j+1] += d;
163 }
164 }
165 }
166
getvelocity(void)167 void getvelocity (void)
168 {
169 int i=0, j=0;
170
171 for(i=0;i<grid;i++)
172 {
173 for(j=0;j<grid;j++) veloc[i][j]+=force[i][j] * dt;
174 }
175 }
176
getposition(void)177 void getposition (void)
178 {
179 int i=0, j=0;
180
181 for(i=0;i<grid;i++)
182 {
183 for(j=0;j<grid;j++) posit[i][j]+=veloc[i][j];
184 }
185 }
186
drawWireframe(void)187 void drawWireframe (void)
188 {
189 int i=0, j=0;
190
191 glColor3f(1.0, 1.0, 1.0);
192
193 for(i=0;i<grid;i++)
194 {
195 glBegin(GL_LINE_STRIP);
196 for(j=0;j<grid;j++) glVertex3f((float)i,(float)j,(float)posit[i][j]);
197 glEnd();
198 }
199
200 for(i=0;i<grid;i++)
201 {
202 glBegin(GL_LINE_STRIP);
203 for(j=0;j<grid;j++) glVertex3f((float)j,(float)i,(float)posit[j][i]);
204 glEnd();
205 }
206 }
207
resetWireframe(void)208 void resetWireframe (void)
209 {
210 int i=0, j=0;
211
212 for(i=0;i<grid;i++)
213 {
214 for(j=0;j<grid;j++)
215 {
216 force[i][j]=0.0;
217 veloc[i][j]=0.0;
218
219 posit[i][j]= (sin(G_PI*2 * ((float)i/(float)grid)) +
220 sin(G_PI*2 * ((float)j/(float)grid)))* grid/6.0;
221
222 if (i==0||j==0||i==grid-1||j==grid-1) posit[i][j]=0.0;
223 }
224 }
225 }
226
227
228 /**************************************************************************
229 * The following section contains all the callback function definitions.
230 **************************************************************************/
231
232 /***
233 *** The "realize" signal handler. All the OpenGL initialization
234 *** should be performed here, such as default background colour,
235 *** certain states etc.
236 ***/
237 static void
realize(GtkWidget * widget,gpointer data)238 realize (GtkWidget *widget,
239 gpointer data)
240 {
241 GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
242 GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
243
244 GdkGLProc proc = NULL;
245
246 /*** OpenGL BEGIN ***/
247 if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
248 return;
249
250 /* glPolygonOffsetEXT */
251 proc = gdk_gl_get_glPolygonOffsetEXT ();
252 if (proc == NULL)
253 {
254 /* glPolygonOffset */
255 proc = gdk_gl_get_proc_address ("glPolygonOffset");
256 if (proc == NULL)
257 {
258 g_print ("Sorry, glPolygonOffset() is not supported by this renderer.\n");
259 exit (1);
260 }
261 }
262
263 glEnable (GL_DEPTH_TEST);
264 glDepthFunc (GL_LEQUAL);
265 glClearColor (0.0, 0.0, 0.0, 0.0);
266 gdk_gl_glPolygonOffsetEXT (proc, 1.0, 1.0);
267 glEnable (GL_CULL_FACE);
268 glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
269 glHint (GL_POLYGON_SMOOTH_HINT, GL_NICEST);
270 glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
271 glEnable (GL_COLOR_MATERIAL);
272 glColorMaterial (GL_FRONT, GL_DIFFUSE);
273 glLightfv (GL_LIGHT0, GL_POSITION, lightPosition);
274 glEnable (GL_LIGHT0);
275 glShadeModel (GL_FLAT);
276 glDisable (GL_LIGHTING);
277
278 resetWireframe ();
279
280 gdk_gl_drawable_gl_end (gldrawable);
281 /*** OpenGL END ***/
282
283 return;
284 }
285
286 /***
287 *** The "configure_event" signal handler. Any processing required when
288 *** the OpenGL-capable drawing area is re-configured should be done here.
289 *** Almost always it will be used to resize the OpenGL viewport when
290 *** the window is resized.
291 ***/
292 static gboolean
configure_event(GtkWidget * widget,GdkEventConfigure * event,gpointer data)293 configure_event (GtkWidget *widget,
294 GdkEventConfigure *event,
295 gpointer data)
296 {
297 GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
298 GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
299
300 GLfloat w = widget->allocation.width;
301 GLfloat h = widget->allocation.height;
302
303 /*** OpenGL BEGIN ***/
304 if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
305 return FALSE;
306
307 aspect = (float)w/(float)h;
308 glViewport (0, 0, w, h);
309
310 gdk_gl_drawable_gl_end (gldrawable);
311 /*** OpenGL END ***/
312
313 return TRUE;
314 }
315
316 /***
317 *** The "expose_event" signal handler. All the OpenGL re-drawing should
318 *** be done here. This is repeatedly called as the painting routine
319 *** every time the 'expose'/'draw' event is signalled.
320 ***/
321 static gboolean
expose_event(GtkWidget * widget,GdkEventExpose * event,gpointer data)322 expose_event (GtkWidget *widget,
323 GdkEventExpose *event,
324 gpointer data)
325 {
326 GdkGLContext *glcontext = gtk_widget_get_gl_context(widget);
327 GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget);
328
329 /*** OpenGL BEGIN ***/
330 if (!gdk_gl_drawable_gl_begin(gldrawable, glcontext))
331 return FALSE;
332
333 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
334
335 glMatrixMode (GL_PROJECTION);
336 glLoadIdentity ();
337 gluPerspective (64.0, aspect, zNear, zFar);
338 glMatrixMode (GL_MODELVIEW);
339 glLoadIdentity ();
340
341 glTranslatef (0.0,0.0,-sdepth);
342 glRotatef (-stheta, 1.0, 0.0, 0.0);
343 glRotatef (sphi, 0.0, 0.0, 1.0);
344 glTranslatef (-(float)((grid+1)/2-1), -(float)((grid+1)/2-1), 0.0);
345
346 drawWireframe ();
347
348 /* Swap buffers */
349 if (gdk_gl_drawable_is_double_buffered (gldrawable))
350 gdk_gl_drawable_swap_buffers (gldrawable);
351 else
352 glFlush ();
353
354 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
355
356 gdk_gl_drawable_gl_end (gldrawable);
357 /*** OpenGL END ***/
358
359 return TRUE;
360 }
361
362 /***
363 *** The timeout function. Often in animations,
364 *** timeout functions are suitable for continous
365 *** frame updates.
366 ***/
367 static gboolean
timeout(GtkWidget * widget)368 timeout (GtkWidget *widget)
369 {
370 getforce ();
371 getvelocity ();
372 getposition ();
373
374 /* Invalidate the whole window. */
375 gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE);
376
377 /* Update synchronously (fast). */
378 gdk_window_process_updates (widget->window, FALSE);
379
380 return TRUE;
381 }
382
383 /***
384 *** The "motion_notify_event" signal handler. Any processing required when
385 *** the OpenGL-capable drawing area is under drag motion should be done here.
386 ***/
387 static gboolean
motion_notify_event(GtkWidget * widget,GdkEventMotion * event,gpointer data)388 motion_notify_event (GtkWidget *widget,
389 GdkEventMotion *event,
390 gpointer data)
391 {
392 gboolean redraw = FALSE;
393
394 if (event->state & GDK_BUTTON1_MASK)
395 {
396 sphi += (float)(event->x - beginX) / 4.0;
397 stheta += (float)(beginY - event->y) / 4.0;
398
399 redraw = TRUE;
400 }
401
402 if (event->state & GDK_BUTTON2_MASK)
403 {
404 sdepth -= ((event->y - beginY)/(widget->allocation.height))*(MAXGRID/2);
405
406 redraw = TRUE;
407 }
408
409 beginX = event->x;
410 beginY = event->y;
411
412 if (redraw && !animate)
413 gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE);
414
415 return TRUE;
416 }
417
418 /***
419 *** The "button_press_event" signal handler. Any processing required when
420 *** mouse buttons (only left and middle buttons) are pressed on the OpenGL-
421 *** capable drawing area should be done here.
422 ***/
423 static gboolean
button_press_event(GtkWidget * widget,GdkEventButton * event,gpointer data)424 button_press_event (GtkWidget *widget,
425 GdkEventButton *event,
426 gpointer data)
427 {
428 if (event->button == 1)
429 {
430 beginX = event->x;
431 beginY = event->y;
432 return TRUE;
433 }
434
435 if (event->button == 2)
436 {
437 beginX = event->x;
438 beginY = event->y;
439 return TRUE;
440 }
441
442 return FALSE;
443 }
444
445 /* For popup menu. */
446 static gboolean
button_press_event_popup_menu(GtkWidget * widget,GdkEventButton * event,gpointer data)447 button_press_event_popup_menu (GtkWidget *widget,
448 GdkEventButton *event,
449 gpointer data)
450 {
451 if (event->button == 3)
452 {
453 /* Popup menu. */
454 gtk_menu_popup (GTK_MENU(widget), NULL, NULL, NULL, NULL,
455 event->button, event->time);
456 return TRUE;
457 }
458
459 return FALSE;
460 }
461
462 /***
463 *** The "key_press_event" signal handler. Any processing required when key
464 *** presses occur should be done here.
465 ***/
466
467 static gboolean
key_press_event(GtkWidget * widget,GdkEventKey * event,gpointer data)468 key_press_event (GtkWidget *widget,
469 GdkEventKey *event,
470 gpointer data)
471 {
472 switch (event->keyval)
473 {
474 case GDK_r:
475 init_wireframe (widget);
476 break;
477
478 case GDK_a:
479 toggle_animation (widget);
480 break;
481
482 case GDK_w:
483 if (!animate)
484 timeout (widget);
485 break;
486
487 case GDK_plus:
488 sdepth -= 2.0;
489 break;
490
491 case GDK_minus:
492 sdepth += 2.0;
493 break;
494
495 case GDK_Escape:
496 gtk_main_quit ();
497 break;
498
499 default:
500 return FALSE;
501 }
502
503 if (!animate)
504 gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE);
505
506 return TRUE;
507 }
508
509 /***
510 *** The "unrealize" signal handler. Any processing required when
511 *** the OpenGL-capable window is unrealized should be done here.
512 ***/
513 static void
unrealize(GtkWidget * widget,gpointer data)514 unrealize (GtkWidget *widget,
515 gpointer data)
516 {
517 /*** Fill in the details here ***/
518
519 }
520
521
522 /**************************************************************************
523 * The following section contains the timeout function management routines.
524 **************************************************************************/
525
526 /***
527 *** Helper functions to add or remove the timeout function.
528 ***/
529
530 static guint timeout_id = 0;
531
532 static void
timeout_add(GtkWidget * widget)533 timeout_add (GtkWidget *widget)
534 {
535 if (timeout_id == 0)
536 {
537 timeout_id = g_timeout_add (TIMEOUT_INTERVAL,
538 (GSourceFunc) timeout,
539 widget);
540 }
541 }
542
543 static void
timeout_remove(GtkWidget * widget)544 timeout_remove (GtkWidget *widget)
545 {
546 if (timeout_id != 0)
547 {
548 g_source_remove (timeout_id);
549 timeout_id = 0;
550 }
551 }
552
553 /***
554 *** The "map_event" signal handler. Any processing required when the
555 *** OpenGL-capable drawing area is mapped should be done here.
556 ***/
557 static gboolean
map_event(GtkWidget * widget,GdkEvent * event,gpointer data)558 map_event (GtkWidget *widget,
559 GdkEvent *event,
560 gpointer data)
561 {
562 if (animate)
563 timeout_add (widget);
564
565 return TRUE;
566 }
567
568 /***
569 *** The "unmap_event" signal handler. Any processing required when the
570 *** OpenGL-capable drawing area is unmapped should be done here.
571 ***/
572 static gboolean
unmap_event(GtkWidget * widget,GdkEvent * event,gpointer data)573 unmap_event (GtkWidget *widget,
574 GdkEvent *event,
575 gpointer data)
576 {
577 timeout_remove (widget);
578
579 return TRUE;
580 }
581
582 /***
583 *** The "visibility_notify_event" signal handler. Any processing required
584 *** when the OpenGL-capable drawing area is visually obscured should be
585 *** done here.
586 ***/
587 static gboolean
visibility_notify_event(GtkWidget * widget,GdkEventVisibility * event,gpointer data)588 visibility_notify_event (GtkWidget *widget,
589 GdkEventVisibility *event,
590 gpointer data)
591 {
592 if (animate)
593 {
594 if (event->state == GDK_VISIBILITY_FULLY_OBSCURED)
595 timeout_remove (widget);
596 else
597 timeout_add (widget);
598 }
599
600 return TRUE;
601 }
602
603
604 /**************************************************************************
605 * The following section contains some miscellaneous utility functions.
606 **************************************************************************/
607
608 /***
609 *** Toggle animation.
610 ***/
611 static void
toggle_animation(GtkWidget * widget)612 toggle_animation (GtkWidget *widget)
613 {
614 animate = !animate;
615
616 if (animate)
617 {
618 timeout_add (widget);
619 }
620 else
621 {
622 timeout_remove (widget);
623 gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE);
624 }
625 }
626
627 /***
628 *** Init wireframe model.
629 ***/
630 static void
init_wireframe(GtkWidget * widget)631 init_wireframe (GtkWidget *widget)
632 {
633 resetWireframe ();
634 gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE);
635 }
636
637
638 /**************************************************************************
639 * The following section contains the GUI building function definitions.
640 **************************************************************************/
641
642 /* Two callbacks for the popup menu items Fullscreen and Unfullscreen.
643 * These are just making sure that the user can't select the same menu
644 * item among these, twice in a row by making the current item selected
645 * insensitive. GTK+-2.2.3 on my WinXP box seems to ignore any calls to
646 * unfullscreen if the user has selected fullscreen on a window that's
647 * already fullscreen.
648 */
fullscreen_window(GtkWidget * current,gpointer other)649 static void fullscreen_window (GtkWidget *current, gpointer other)
650 {
651 GtkWidget *window = g_object_get_data(G_OBJECT(current), "window");
652 if (window)
653 {
654 gtk_widget_set_sensitive(GTK_WIDGET(current), FALSE);
655 gtk_widget_set_sensitive(GTK_WIDGET(other), TRUE);
656 gtk_window_fullscreen(GTK_WINDOW(window));
657 }
658 }
659
unfullscreen_window(GtkWidget * current,gpointer other)660 static void unfullscreen_window (GtkWidget *current, gpointer other)
661 {
662 GtkWidget *window = g_object_get_data(G_OBJECT(current), "window");
663 if (window)
664 {
665 gtk_widget_set_sensitive(GTK_WIDGET(current), FALSE);
666 gtk_widget_set_sensitive(GTK_WIDGET(other), TRUE);
667 gtk_window_unfullscreen(GTK_WINDOW(window));
668 }
669 }
670
671 /***
672 *** Creates the popup menu to be displayed.
673 ***/
674 static GtkWidget *
create_popup_menu(GtkWidget * window,GtkWidget * drawing_area)675 create_popup_menu (GtkWidget *window, GtkWidget *drawing_area)
676 {
677 GtkWidget *menu;
678 GtkWidget *menu_item;
679 GtkWidget *full_item;
680 GtkWidget *unfull_item;
681
682 menu = gtk_menu_new ();
683
684 /* Toggle animation */
685 menu_item = gtk_menu_item_new_with_label ("Toggle Animation");
686 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
687 g_signal_connect_swapped (G_OBJECT (menu_item), "activate",
688 G_CALLBACK (toggle_animation), drawing_area);
689 gtk_widget_show (menu_item);
690
691 /* Init wireframe model */
692 menu_item = gtk_menu_item_new_with_label ("Initialize");
693 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
694 g_signal_connect_swapped (G_OBJECT (menu_item), "activate",
695 G_CALLBACK (init_wireframe), drawing_area);
696 gtk_widget_show (menu_item);
697
698 /* Fullscreen window. */
699 full_item = gtk_menu_item_new_with_label ("Fullscreen");
700 g_object_set_data(G_OBJECT(full_item), "window", window);
701 gtk_menu_shell_append (GTK_MENU_SHELL (menu), full_item);
702
703 /* Un-fullscreen window. */
704 unfull_item = gtk_menu_item_new_with_label ("Unfullscreen");
705 g_object_set_data(G_OBJECT(unfull_item), "window", window);
706 gtk_menu_shell_append (GTK_MENU_SHELL (menu), unfull_item);
707 gtk_widget_set_sensitive(unfull_item, FALSE);
708
709 /* Connect the fullscreen and unfullscreen callbacks. */
710 g_signal_connect (G_OBJECT (full_item), "activate",
711 G_CALLBACK (fullscreen_window), unfull_item);
712 g_signal_connect (G_OBJECT (unfull_item), "activate",
713 G_CALLBACK (unfullscreen_window), full_item);
714 gtk_widget_show (full_item);
715 gtk_widget_show (unfull_item);
716
717 /* Quit */
718 menu_item = gtk_menu_item_new_with_label ("Quit");
719 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
720 g_signal_connect (G_OBJECT (menu_item), "activate",
721 G_CALLBACK (gtk_main_quit), NULL);
722 gtk_widget_show (menu_item);
723
724 return menu;
725 }
726
727 /***
728 *** Creates the simple application window with one
729 *** drawing area that has an OpenGL-capable visual.
730 ***/
731 static GtkWidget *
create_window(GdkGLConfig * glconfig)732 create_window (GdkGLConfig *glconfig)
733 {
734 GtkWidget *window;
735 GtkWidget *drawing_area;
736 GtkWidget *menu;
737
738 /*
739 * Top-level window.
740 */
741
742 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
743 gtk_window_set_title (GTK_WINDOW (window), DEFAULT_TITLE);
744
745 /* Get automatically redrawn if any of their children changed allocation. */
746 gtk_container_set_reallocate_redraws (GTK_CONTAINER (window), TRUE);
747
748 /* Connect signal handlers to the window */
749 g_signal_connect (G_OBJECT (window), "delete_event",
750 G_CALLBACK (gtk_main_quit), NULL);
751
752 /*
753 * Drawing area to draw OpenGL scene.
754 */
755
756 drawing_area = gtk_drawing_area_new ();
757 gtk_widget_set_size_request (drawing_area, DEFAULT_WIDTH, DEFAULT_HEIGHT);
758
759 /* Set OpenGL-capability to the widget */
760 gtk_widget_set_gl_capability (drawing_area,
761 glconfig,
762 NULL,
763 TRUE,
764 GDK_GL_RGBA_TYPE);
765
766 gtk_widget_add_events (drawing_area,
767 GDK_BUTTON1_MOTION_MASK |
768 GDK_BUTTON2_MOTION_MASK |
769 GDK_BUTTON_PRESS_MASK |
770 GDK_VISIBILITY_NOTIFY_MASK);
771
772 /* Connect signal handlers to the drawing area */
773 g_signal_connect_after (G_OBJECT (drawing_area), "realize",
774 G_CALLBACK (realize), NULL);
775 g_signal_connect (G_OBJECT (drawing_area), "configure_event",
776 G_CALLBACK (configure_event), NULL);
777 g_signal_connect (G_OBJECT (drawing_area), "expose_event",
778 G_CALLBACK (expose_event), NULL);
779
780 g_signal_connect (G_OBJECT (drawing_area), "motion_notify_event",
781 G_CALLBACK (motion_notify_event), NULL);
782 g_signal_connect (G_OBJECT (drawing_area), "button_press_event",
783 G_CALLBACK (button_press_event), NULL);
784 g_signal_connect (G_OBJECT (drawing_area), "unrealize",
785 G_CALLBACK (unrealize), NULL);
786
787 /* key_press_event handler for top-level window */
788 g_signal_connect_swapped (G_OBJECT (window), "key_press_event",
789 G_CALLBACK (key_press_event), drawing_area);
790
791 /* For timeout function. */
792 g_signal_connect (G_OBJECT (drawing_area), "map_event",
793 G_CALLBACK (map_event), NULL);
794 g_signal_connect (G_OBJECT (drawing_area), "unmap_event",
795 G_CALLBACK (unmap_event), NULL);
796 g_signal_connect (G_OBJECT (drawing_area), "visibility_notify_event",
797 G_CALLBACK (visibility_notify_event), NULL);
798
799 gtk_container_add (GTK_CONTAINER (window), drawing_area);
800 gtk_widget_show (drawing_area);
801
802 /*
803 * Popup menu.
804 */
805
806 menu = create_popup_menu (window, drawing_area);
807
808 g_signal_connect_swapped (G_OBJECT (drawing_area), "button_press_event",
809 G_CALLBACK (button_press_event_popup_menu), menu);
810
811 return window;
812 }
813
814
815 /**************************************************************************
816 * The following section contains utility function definitions.
817 **************************************************************************/
818
819 /***
820 *** Configure the OpenGL framebuffer.
821 ***/
822 static GdkGLConfig *
configure_gl(void)823 configure_gl (void)
824 {
825 GdkGLConfig *glconfig;
826
827 /* Try double-buffered visual */
828 glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB |
829 GDK_GL_MODE_DEPTH |
830 GDK_GL_MODE_DOUBLE);
831 if (glconfig == NULL)
832 {
833 g_print ("\n*** Cannot find the double-buffered visual.\n");
834 g_print ("\n*** Trying single-buffered visual.\n");
835
836 /* Try single-buffered visual */
837 glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB |
838 GDK_GL_MODE_DEPTH);
839 if (glconfig == NULL)
840 {
841 g_print ("*** No appropriate OpenGL-capable visual found.\n");
842 exit (1);
843 }
844 }
845
846 return glconfig;
847 }
848
849
850 /**************************************************************************
851 * The main function is rather trivial.
852 **************************************************************************/
853
854 int
main(int argc,char * argv[])855 main (int argc,
856 char *argv[])
857 {
858 GtkWidget *window;
859 GdkGLConfig *glconfig;
860
861 /* Initialize GTK. */
862 gtk_init (&argc, &argv);
863
864 /* Initialize GtkGLExt. */
865 gtk_gl_init (&argc, &argv);
866
867 /* Configure OpenGL framebuffer. */
868 glconfig = configure_gl ();
869
870 /* Create and show the application window. */
871 window = create_window (glconfig);
872 gtk_widget_show (window);
873
874 gtk_main ();
875
876 return 0;
877 }
878
879
880 /**************************************************************************
881 * End of file.
882 **************************************************************************/
883