summaryrefslogtreecommitdiffstats
path: root/Smoke/gtk.c
diff options
context:
space:
mode:
authorOliver Schinagl <oliver@schinagl.nl>2007-10-25 13:32:58 (GMT)
committerOliver Schinagl <oliver@schinagl.nl>2007-10-25 13:32:58 (GMT)
commit2f019eddfc78e7a03110ee52437aa4fb3e41c588 (patch)
tree13be4b850a3da9a5cedfe132d4c95aa980c0c7e8 /Smoke/gtk.c
parentd6d4a555d93bca7b0855144c28b591c1773aa9fe (diff)
download2iv35-2f019eddfc78e7a03110ee52437aa4fb3e41c588.zip
2iv35-2f019eddfc78e7a03110ee52437aa4fb3e41c588.tar.gz
2iv35-2f019eddfc78e7a03110ee52437aa4fb3e41c588.tar.bz2
tja ..
Diffstat (limited to 'Smoke/gtk.c')
-rw-r--r--Smoke/gtk.c797
1 files changed, 797 insertions, 0 deletions
diff --git a/Smoke/gtk.c b/Smoke/gtk.c
new file mode 100644
index 0000000..db4204a
--- /dev/null
+++ b/Smoke/gtk.c
@@ -0,0 +1,797 @@
+/**************************************************************************
+ * template.c
+ *
+ * Copyright (c) 2002 Alif Wahid <awah005@users.sourceforge.net>
+ *
+ * This is a template of the essential source code to write useful but
+ * simple programs using GtkGLExt and Gtk. It compiles into an executable
+ * but obviously the lack of any OpenGL functions in this demonstrates
+ * the generic nature. It's heavily commented to aid beginners (especially
+ * tertiary students like myself). So use/change it at will.
+ *
+ * This program is in the public domain and you are using it at
+ * your own risk.
+ *
+ **************************************************************************/
+
+/*
+ * Follow the GTK coding style.
+ * Changed idle function management codes.
+ * Added popup menu.
+ * Added quit button.
+ * Naofumi Yasufuku <naofumi@users.sourceforge.net>
+ */
+
+/**************************************************************************
+ * Header file inclusions.
+ **************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <gtk/gtkgl.h>
+/*** Use OpenGL extensions. ***/
+/* #include <gdk/gdkglglext.h> */
+
+#ifdef G_OS_WIN32
+#define WIN32_LEAN_AND_MEAN 1
+#include <windows.h>
+#endif
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+
+#include <rfftw.h> //the numerical simulation FFTW library
+
+#include "fluids.h"
+
+/**************************************************************************
+ * The following section contains all the macro definitions.
+ **************************************************************************/
+
+/***
+ *** Change these three macros to customise the
+ *** default width and height of the drawing
+ *** area, plus the default title of the window.
+ ***/
+#define DEFAULT_WIDTH 800
+#define DEFAULT_HEIGHT 600
+#define DEFAULT_TITLE "2iv35 \"Smoke\" by Wilrik & Oliver"
+
+#define TIMEOUT_INTERVAL 10
+
+
+/**************************************************************************
+ * Global variable declarations.
+ **************************************************************************/
+
+static gboolean animate = TRUE;
+
+int winWidth, winHeight; //size of the graphics window, in pixels
+
+
+/**************************************************************************
+ * The following section contains the function prototype declarations.
+ **************************************************************************/
+
+static void timeout_add (GtkWidget *widget);
+static void timeout_remove (GtkWidget *widget);
+
+static void toggle_animation (GtkWidget *widget);
+
+static GdkGLConfig *configure_gl (void);
+
+static GtkWidget *create_popup_menu (GtkWidget *drawing_area);
+static GtkWidget *create_window (GdkGLConfig *glconfig);
+
+
+/**************************************************************************
+ * The following section contains all the callback function definitions.
+ **************************************************************************/
+
+/***
+ *** The "realize" signal handler. All the OpenGL initialization
+ *** should be performed here, such as default background colour,
+ *** certain states etc.
+ ***/
+static void
+realize (GtkWidget *widget,
+ gpointer data)
+{
+ GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
+ GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
+
+ g_print ("%s: \"realize\"\n", gtk_widget_get_name (widget));
+
+ /*** OpenGL BEGIN ***/
+ if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
+ return;
+
+ /*** Fill in the details here. ***/
+
+ gdk_gl_drawable_gl_end (gldrawable);
+ /*** OpenGL END ***/
+}
+
+/***
+ *** The "configure_event" signal handler. Any processing required when
+ *** the OpenGL-capable drawing area is re-configured should be done here.
+ *** Almost always it will be used to resize the OpenGL viewport when
+ *** the window is resized.
+ ***/
+static gboolean
+configure_event (GtkWidget *widget,
+ GdkEventConfigure *event,
+ gpointer data)
+{
+ GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
+ GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
+
+ GLfloat w = widget->allocation.width;
+ GLfloat h = widget->allocation.height;
+
+ g_print ("%s: \"configure_event\"\n", gtk_widget_get_name (widget));
+
+ /*** OpenGL BEGIN ***/
+ if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
+ return FALSE;
+
+ /*** Fill in the details here. ***/
+ glViewport (0, 0, w, h);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ gluOrtho2D(0.0, (GLdouble)w, 0.0, (GLdouble)h);
+ winWidth = w;
+ winHeight = h;
+
+ gdk_gl_drawable_gl_end (gldrawable);
+ /*** OpenGL END ***/
+
+ return TRUE;
+}
+
+/***
+ *** The "expose_event" signal handler. All the OpenGL re-drawing should
+ *** be done here. This is repeatedly called as the painting routine
+ *** every time the 'expose'/'draw' event is signalled.
+ ***/
+static gboolean
+expose_event (GtkWidget *widget,
+ GdkEventExpose *event,
+ gpointer data)
+{
+ GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
+ GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
+
+ //g_print ("%s: \"expose_event\"\n", gtk_widget_get_name (widget));
+
+ /*** OpenGL BEGIN ***/
+ if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
+ return FALSE;
+
+ glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ /*** Fill in the details here. ***/
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ set_forces();
+ solve(DIM, vx, vy, vx0, vy0, visc, dt);
+ diffuse_matter(DIM, vx, vy, rho, rho0, dt);
+ visualize();
+
+ /* Swap buffers */
+ if (gdk_gl_drawable_is_double_buffered (gldrawable))
+ gdk_gl_drawable_swap_buffers (gldrawable);
+ else
+ glFlush ();
+
+ gdk_gl_drawable_gl_end (gldrawable);
+ /*** OpenGL END ***/
+
+ return TRUE;
+}
+
+/***
+ *** The timeout function. Often in animations,
+ *** timeout functions are suitable for continous
+ *** frame updates.
+ ***/
+static gboolean
+timeout (GtkWidget *widget)
+{
+ //g_print (".");
+
+ /*** Fill in the details here ***/
+
+ /* Invalidate the whole window. */
+ gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE);
+
+ /* Update synchronously. */
+ gdk_window_process_updates (widget->window, FALSE);
+
+ return TRUE;
+}
+
+/***
+ *** The "unrealize" signal handler. Any processing required when
+ *** the OpenGL-capable window is unrealized should be done here.
+ ***/
+static void
+unrealize (GtkWidget *widget,
+ gpointer data)
+{
+ GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
+ GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
+
+ g_print ("%s: \"unrealize\"\n", gtk_widget_get_name (widget));
+
+ /*** OpenGL BEGIN ***/
+ if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
+ return;
+
+ /*** Fill in the details here. ***/
+
+ gdk_gl_drawable_gl_end (gldrawable);
+ /*** OpenGL END ***/
+}
+
+/***
+ *** The "motion_notify_event" signal handler. Any processing required when
+ *** the OpenGL-capable drawing area is under drag motion should be done here.
+ ***/
+static gboolean
+motion_notify_event (GtkWidget *widget,
+ GdkEventMotion *event,
+ gpointer data)
+{
+ /*** Fill in the details here. ***/
+ int mx, my, xi,yi,X,Y; double dx, dy, len;
+ int clamp_scaled_min, clamp_scaled_max;
+ static int lmx=0,lmy=0; //remembers last mouse location
+
+ mx = (int)event->x;
+ my = (int)event->y;
+
+ /* Density calculations etc are only computed on area's below the slider */
+ if (my >25) {
+ // Compute the array index that corresponds to the cursor location
+ xi = (int)clamp((double)(DIM + 1) * ((double)mx / (double)winWidth));
+ yi = (int)clamp((double)(DIM + 1) * ((double)(winHeight - my) / (double)winHeight));
+
+ X = xi; Y = yi;
+
+ if (X > (DIM - 1)) X = DIM - 1; if (Y > (DIM - 1)) Y = DIM - 1;
+ if (X < 0) X = 0; if (Y < 0) Y = 0;
+
+ // Add force at the cursor location
+ my = winHeight - my;
+ dx = mx - lmx; dy = my - lmy;
+ len = sqrt(dx * dx + dy * dy);
+ if (len != 0.0) { dx *= 0.1 / len; dy *= 0.1 / len; }
+ fx[Y * DIM + X] += dx;
+ fy[Y * DIM + X] += dy;
+ rho[Y * DIM + X] = 10.0f;
+ lmx = mx; lmy = my;
+ } else {
+ switch (active_slider) {
+ case MOUSE_SCALE_MIN:
+ scale_min = (float)mx /winWidth;
+ break;
+ case MOUSE_SCALE_MAX:
+ scale_max = (float)mx /winWidth;
+ break;
+ case MOUSE_CLAMP_MIN:
+ clamp_min = (float)mx /winWidth;
+ break;
+ case MOUSE_CLAMP_MAX:
+ clamp_max = (float)mx /winWidth;
+ break;
+ case MOUSE_SMOKE:
+ default:
+ break;
+ }
+ }
+
+ if (event->state & GDK_BUTTON1_MASK)
+ {
+ }
+
+ if (event->state & GDK_BUTTON2_MASK)
+ {
+ g_print (" 2");
+ }
+
+ if (event->state & GDK_BUTTON3_MASK)
+ {
+ g_print (" 3");
+ }
+
+ return FALSE;
+}
+
+/***
+ *** The "button_press_event" signal handler. Any processing required when
+ *** mouse buttons (only left and middle buttons) are pressed on the OpenGL-
+ *** capable drawing area should be done here.
+ ***/
+static gboolean
+button_press_event (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer data)
+{
+ g_print ("%s: \"button_press_event\": ", gtk_widget_get_name (widget));
+
+ if (event->button == 1)
+ {
+ /*** Fill in the details here. ***/
+
+ /* First check wether we are on the top half, or bottom half of the bar, if neither then
+ * the mouseinput is for the smoke
+ */
+ if (event->y <25) {
+ /* Click received on button bar */
+ if (event->y <13) {
+ /* Upper half */
+ /* check wether mx is min or max slider */
+ if (event->x <(rescale_to_winwidth(scale_min +((scale_max - scale_min) /2)))) {
+ active_slider = MOUSE_SCALE_MIN;
+ } else if (event->x >(rescale_to_winwidth(scale_max -((scale_max - scale_min) /2)))) {
+ active_slider = MOUSE_SCALE_MAX;
+ }
+ } else {
+ /* Bottom half */
+ /* check wether mx is min or max slider */
+ if (event->x <(rescale_to_winwidth(clamp_min +((clamp_max - clamp_min) /2)))) {
+ active_slider = MOUSE_CLAMP_MIN;
+ } else if (event->x >(rescale_to_winwidth(clamp_max -((clamp_max - clamp_min) /2)))) {
+ active_slider = MOUSE_CLAMP_MAX;
+ }
+ }
+ } else {
+ active_slider = MOUSE_SMOKE;
+ }
+
+ return TRUE;
+ }
+
+ if (event->button == 2)
+ {
+ /*** Fill in the details here. ***/
+ g_print ("button 2\n");
+
+ return TRUE;
+ }
+
+ g_print ("\n");
+
+ return FALSE;
+}
+
+/* For popup menu. */
+static gboolean
+button_press_event_popup_menu (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer data)
+{
+ g_print ("%s: \"button_press_event_popup\": ", gtk_widget_get_name (widget));
+
+ if (event->button == 3)
+ {
+ g_print ("button 3\n");
+
+ /* Popup menu. */
+ gtk_menu_popup (GTK_MENU (widget), NULL, NULL, NULL, NULL,
+ event->button, event->time);
+ return TRUE;
+ }
+
+ g_print ("\n");
+
+ return FALSE;
+}
+
+/***
+ *** The "key_press_event" signal handler. Any processing required when key
+ *** presses occur should be done here.
+ ***/
+static gboolean
+key_press_event (GtkWidget *widget,
+ GdkEventKey *event,
+ gpointer data)
+{
+ switch (event->keyval)
+ {
+ /*** Fill in the details here. ***/
+
+ case GDK_t:
+ dt -= 0.001;
+ break;
+
+ case GDK_T:
+ dt += 0.001;
+ break;
+
+ case GDK_c:
+ color_dir = (color_dir +1) %3;
+ break;
+
+ case GDK_s:
+ vec_scale *= 0.8;
+ break;
+
+ case GDK_S:
+ vec_scale *= 1.2;
+ break;
+
+ case GDK_v:
+ visc *= 0.2;
+ break;
+
+ case GDK_V:
+ visc *= 5;
+ break;
+
+ case GDK_x:
+ draw_smoke = 1 -draw_smoke;
+ if (!draw_smoke) { draw_smoke = 1; }
+ break;
+
+ case GDK_y:
+ draw_vecs = 1 -draw_vecs;
+ if (!draw_vecs) { draw_vecs = 1; }
+ break;
+
+ case GDK_m:
+ scalar_col++; if (scalar_col>COLOR_OLIVER) scalar_col=COLOR_BLACKWHITE;
+ break;
+
+ case GDK_a:
+ toggle_animation (widget);
+ break;
+
+ case GDK_Escape:
+ gtk_main_quit ();
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/**************************************************************************
+ * The following section contains the timeout function management routines.
+ **************************************************************************/
+
+/***
+ *** Helper functions to add or remove the timeout function.
+ ***/
+
+static guint timeout_id = 0;
+
+static void
+timeout_add (GtkWidget *widget)
+{
+ if (timeout_id == 0)
+ {
+ timeout_id = g_timeout_add (TIMEOUT_INTERVAL,
+ (GSourceFunc) timeout,
+ widget);
+ }
+}
+
+static void
+timeout_remove (GtkWidget *widget)
+{
+ if (timeout_id != 0)
+ {
+ g_source_remove (timeout_id);
+ timeout_id = 0;
+ }
+}
+
+/***
+ *** The "map_event" signal handler. Any processing required when the
+ *** OpenGL-capable drawing area is mapped should be done here.
+ ***/
+static gboolean
+map_event (GtkWidget *widget,
+ GdkEvent *event,
+ gpointer data)
+{
+ g_print ("%s: \"map_event\":\n", gtk_widget_get_name (widget));
+ if (animate)
+ timeout_add (widget);
+
+ return TRUE;
+}
+
+/***
+ *** The "unmap_event" signal handler. Any processing required when the
+ *** OpenGL-capable drawing area is unmapped should be done here.
+ ***/
+static gboolean
+unmap_event (GtkWidget *widget,
+ GdkEvent *event,
+ gpointer data)
+{
+ g_print ("%s: \"unmap_event\":\n", gtk_widget_get_name (widget));
+ timeout_remove (widget);
+
+ return TRUE;
+}
+
+/***
+ *** The "visibility_notify_event" signal handler. Any processing required
+ *** when the OpenGL-capable drawing area is visually obscured should be
+ *** done here.
+ ***/
+static gboolean
+visibility_notify_event (GtkWidget *widget,
+ GdkEventVisibility *event,
+ gpointer data)
+{
+ if (animate)
+ {
+ if (event->state == GDK_VISIBILITY_FULLY_OBSCURED)
+ timeout_remove (widget);
+ else
+ timeout_add (widget);
+ }
+
+ return TRUE;
+}
+
+
+/**************************************************************************
+ * The following section contains some miscellaneous utility functions.
+ **************************************************************************/
+
+/***
+ *** Toggle animation.
+ ***/
+static void
+toggle_animation (GtkWidget *widget)
+{
+ frozen = animate = !animate;
+
+ if (animate)
+ {
+ timeout_add (widget);
+ }
+ else
+ {
+ timeout_remove (widget);
+ gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE);
+ }
+}
+
+
+/**************************************************************************
+ * The following section contains the GUI building function definitions.
+ **************************************************************************/
+
+/***
+ *** Creates the popup menu to be displayed.
+ ***/
+static GtkWidget *
+create_popup_menu (GtkWidget *drawing_area)
+{
+ GtkWidget *menu;
+ GtkWidget *menu_item;
+
+ menu = gtk_menu_new ();
+
+ /* Toggle animation */
+ menu_item = gtk_menu_item_new_with_label ("Toggle Animation");
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
+ g_signal_connect_swapped (G_OBJECT (menu_item), "activate",
+ G_CALLBACK (toggle_animation), drawing_area);
+ gtk_widget_show (menu_item);
+
+ /* Toggle glyphs */
+ menu_item = gtk_menu_item_new_with_label ("Glyphs");
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
+ g_signal_connect_swapped (G_OBJECT (menu_item), "activate",
+ G_CALLBACK (set_glyph_usage), drawing_area);
+ gtk_widget_show (menu_item);
+
+ /* Quit */
+ menu_item = gtk_menu_item_new_with_label ("Quit");
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
+ g_signal_connect (G_OBJECT (menu_item), "activate",
+ G_CALLBACK (gtk_main_quit), NULL);
+ gtk_widget_show (menu_item);
+
+ return menu;
+}
+
+/***
+ *** Creates the simple application window with one
+ *** drawing area that has an OpenGL-capable visual.
+ ***/
+static GtkWidget *
+create_window (GdkGLConfig *glconfig)
+{
+ GtkWidget *window;
+ GtkWidget *hbox;
+ GtkWidget *drawing_area;
+ GtkWidget *menu;
+ GtkWidget *button;
+
+ /*
+ * Top-level window.
+ */
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title (GTK_WINDOW (window), DEFAULT_TITLE);
+
+ /* Get automatically redrawn if any of their children changed allocation. */
+ gtk_container_set_reallocate_redraws (GTK_CONTAINER (window), TRUE);
+
+ /* Connect signal handlers to the window */
+ g_signal_connect (G_OBJECT (window), "delete_event",
+ G_CALLBACK (gtk_main_quit), NULL);
+
+ /*
+ * hBox.
+ */
+
+ hbox = gtk_hbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (window), hbox);
+ gtk_widget_show (hbox);
+
+ /*
+ * Drawing area to draw OpenGL scene.
+ */
+
+ drawing_area = gtk_drawing_area_new ();
+ gtk_widget_set_size_request (drawing_area, DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ /* Set OpenGL-capability to the widget */
+ gtk_widget_set_gl_capability (drawing_area,
+ glconfig,
+ NULL,
+ TRUE,
+ GDK_GL_RGBA_TYPE);
+
+ gtk_widget_add_events (drawing_area,
+ GDK_BUTTON1_MOTION_MASK |
+ GDK_BUTTON2_MOTION_MASK |
+ GDK_BUTTON_PRESS_MASK |
+ GDK_VISIBILITY_NOTIFY_MASK);
+
+ /* Connect signal handlers to the drawing area */
+ g_signal_connect_after (G_OBJECT (drawing_area), "realize",
+ G_CALLBACK (realize), NULL);
+ g_signal_connect (G_OBJECT (drawing_area), "configure_event",
+ G_CALLBACK (configure_event), NULL);
+ g_signal_connect (G_OBJECT (drawing_area), "expose_event",
+ G_CALLBACK (expose_event), NULL);
+ g_signal_connect (G_OBJECT (drawing_area), "unrealize",
+ G_CALLBACK (unrealize), NULL);
+
+ g_signal_connect (G_OBJECT (drawing_area), "motion_notify_event",
+ G_CALLBACK (motion_notify_event), NULL);
+ g_signal_connect (G_OBJECT (drawing_area), "button_press_event",
+ G_CALLBACK (button_press_event), NULL);
+
+ /* key_press_event handler for top-level window */
+ g_signal_connect_swapped (G_OBJECT (window), "key_press_event",
+ G_CALLBACK (key_press_event), drawing_area);
+
+ /* For timeout function. */
+ g_signal_connect (G_OBJECT (drawing_area), "map_event",
+ G_CALLBACK (map_event), NULL);
+ g_signal_connect (G_OBJECT (drawing_area), "unmap_event",
+ G_CALLBACK (unmap_event), NULL);
+ g_signal_connect (G_OBJECT (drawing_area), "visibility_notify_event",
+ G_CALLBACK (visibility_notify_event), NULL);
+
+ gtk_box_pack_start (GTK_BOX (hbox), drawing_area, TRUE, TRUE, 0);
+
+ gtk_widget_show (drawing_area);
+
+ /*
+ * Popup menu.
+ */
+
+ menu = create_popup_menu (drawing_area);
+
+ g_signal_connect_swapped (G_OBJECT (drawing_area), "button_press_event",
+ G_CALLBACK (button_press_event_popup_menu), menu);
+
+ /*
+ * Simple quit button.
+ */
+
+ button = gtk_button_new_with_label ("Quit");
+
+ g_signal_connect (G_OBJECT (button), "clicked",
+ G_CALLBACK (gtk_main_quit), NULL);
+
+ gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+
+ gtk_widget_show (button);
+
+ return window;
+}
+
+
+/**************************************************************************
+ * The following section contains utility function definitions.
+ **************************************************************************/
+
+/***
+ *** Configure the OpenGL framebuffer.
+ ***/
+static GdkGLConfig *
+configure_gl (void)
+{
+ GdkGLConfig *glconfig;
+
+ /* Try double-buffered visual */
+ glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB |
+ GDK_GL_MODE_DEPTH |
+ GDK_GL_MODE_DOUBLE);
+ if (glconfig == NULL)
+ {
+ g_print ("\n*** Cannot find the double-buffered visual.\n");
+ g_print ("\n*** Trying single-buffered visual.\n");
+
+ /* Try single-buffered visual */
+ glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB |
+ GDK_GL_MODE_DEPTH);
+ if (glconfig == NULL)
+ {
+ g_print ("*** No appropriate OpenGL-capable visual found.\n");
+ exit (1);
+ }
+ }
+
+ return glconfig;
+}
+
+
+/**************************************************************************
+ * The main function is rather trivial.
+ **************************************************************************/
+
+int
+main (int argc,
+ char *argv[])
+{
+ GtkWidget *window;
+ GdkGLConfig *glconfig;
+
+ /* Initialize GTK. */
+ gtk_init (&argc, &argv);
+
+ /* Initialize GtkGLExt. */
+ gtk_gl_init (&argc, &argv);
+
+ /* Configure OpenGL framebuffer. */
+ glconfig = configure_gl ();
+
+ /* Create and show the application window. */
+ window = create_window (glconfig);
+ gtk_widget_show (window);
+
+ init_simulation(DIM);
+
+ gtk_main ();
+
+ return 0;
+}
+
+
+/**************************************************************************
+ * End of file.
+ **************************************************************************/