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