Monday, October 27, 2008

OpenGL and Gtk+ with GtkGlExt

UPDATE: source files now on gitorious

Lately I've been really impressed with the performance and simplicity of Gtk+. After using it to get fullscreen video with Gstreamer, I thought I would check out using Gtk+ in place of GLUT to write OpenGL programs.

The program teapot.c is a heavily commented example that creates a window and draws a mesh teapot. The accompanying Makefile will compile it under GNU/Linux provided the following packages (in Ubuntu) are installed:
gtk+-2.0 gtkglext-1.0 gtkglext-x11-1.0

GtkGlExt is an API extension to the Gtk+ API that allows developers to use OpenGL calls on standard Gtk+ widgets or on new custom widgets. There is also a C++ API,
gtkglextmm, for Gtk+'s C++ counterpart, gtkmm.

The program is broken down into initialization functions to set up the window and OpenGL context, as well as callbacks that are used to do the heavy-lifting. The callbacks are registered in the initialization functions, which means they are attached to specific events (or signals) and are triggered when these events are fired off asynchronously.

The expose callback (expose_cb) is where we do our OpenGL drawing. It will be called in response to "expose-event" signals, fired whenever the window needs to be redrawn, i.e. if it is resized, exposed (where regions become visible that previously were not), or moved.

The idle callback (idle_cb) is the only callback that is not attached to an event. It is registered using g_timeout_add, meaning that it will be called at a fixed interval. Its job is to flag the drawable area of our GtkWindow as needing to be redrawn. It is also where we would update any control or data parameters that the expose callback needs to take into account. For example, say we were stretching our teapot, we could have the scaling factor incremented in our idle callback. It's important to note, however, that g_timeout_add does not guarantee that the timeout interval will be respected, as explained in the GLib documentation:

Note that timeout functions may be delayed, due to the processing of other event sources. Thus they should not be relied on for precise timing. After each call to the timeout function, the time of the next timeout is recalculated based on the current time and the given interval (it does not try to 'catch up' time lost in delays).
The constraints of real-time computing are beyond the scope of this entry, but the animation subsection in Chapter 1 of the OpenGL Red Book offers a good overview.

But lo and behold, the wonder of the Utah Teapot:

13 comments:

noether said...

Thx very much about this example, i was looking for one :P

Tristan Matthews said...

No problem, gtkglext is really cool but I had trouble finding sample code when I wrote this.

سامح said...

Nice example, keep up the good work

Anonymous said...

Very useful example however the Makefile link is busted...

Tristan Matthews said...

Sorry about that, the Makefile link should be fixed now. Thanks for the feedback!

Anonymous said...

Thanks, got me started.

Anonymous said...

Thanks, got me started.

Undecided said...

hey..I am not able to download the teapot.c file..please provide it ..so that I can get idea how to use gtkglext.

Thanks

Undecided said...

Hey.. Please attach your teapot.c file and makefile..I am doing a project wherein I need an example of how to use gtkglext

Thank you

Anonymous said...

Sources are not working.

Chris_A said...

cant access teapot.c and Makefile links!! ERROR: "Internal Server Error

TracError: IOError: [Errno 2] No such file or directory: '/var/lib/trac/miville/VERSION'"

Tristan Matthews said...

Source file is now available on gitorious. You can also find a lot more gtkglext examples here:

http://git.gnome.org/browse/gtkglext/tree/examples

Anonymous said...

When compiling (with the provided Makefile, or with a command line) I get:

teapot.c:(.text+0x108): undefined reference to `gdk_gl_draw_teapot'

gdk_gl_draw_teapot is defined in the include file, but does not seem to be in the actual lib.

BTW gtkglext-1.0 is version 1.2

Thanks for the post though!