A simple example of how to use OpenGL and the GtkGLArea widget available since GTK+ 3.16.
See also: https://www.bassi.io/articles/2015/02/17/using-opengl-with-gtk/
NOTE: This example is meant to be used with GTK+ 3.x only. GTK 4 has a similar API, and it allows more flexibility when it comes to selecting the version of GL to use, as well as supporting OpenGL and OpenGLES.
A binary build of this example is available as a Flatpak. Make sure you have Flatpak installed on your system, and then use:
$ flatpak install --from http://ebassi.github.io/glarea-example/glarea-example.flatpakref
To install the binary build. A launcher should appear in the list of your applications; if it doesn't, you can use:
$ flatpak run io.bassi.Glarea
To run the example.
You will need GTK+ 3.16 or later to build this example.
Clone the repository, as usual:
$ git clone https://github.com/ebassi/glarea-example
Then run make
inside the cloned repository:
$ cd glarea-example
$ make
Finally, run the example:
$ ./glarea
If everything worked as it should, you should see this:
Use the range widgets to control the rotation of the triangle, and feel free to play around with the source.
This is a simple example, but it's been broken down in a way that allows easy reuse of the parts.
glarea-app.[ch]
- This is the main application singleton; just a thin wrapper around GtkApplication which creates an application window of theGlareaAppWindow
class on activation, unless one is already present, in which case it just brings up into focus the existing instanceglarea-app-menu.ui
- TheGMenu
XML description of the application menu, loaded by the application singleton instanceglarea-app-window.[ch]
- This is the main application window, and where the real magic happensglarea-app-window.ui
- TheGtkBuilder
XML description of theGlareaAppWindow
classglarea-error.[ch]
- A GError error domain, for our internal useglarea-fragment.glsl
- The GLSL fragment shader source, which we embed into the executable binary by way ofGResource
glarea-vertex.glsl
- The GLSL vertex shader source, which we embed into the executable binary by way ofGResource
glarea.gresource.xml
- The list of resources we want to embed into the executable binarymain.c
- The main entry point, which creates the application singletong and spins the main loop
The whole application logic can be broken down into roughly four separate parts:
- Initialization
- State updates
- Drawing
- Deinitialization
We use the GtkWidget::realize
signal to know when the GtkGLArea
widget
has created the windowing system resources associated with the GL context;
in order to use the signal, we connect the gl_init
function to it inside
the UI description.
The basic step is to make the GL context current, so we can use the GL API:
gtk_gl_area_make_current (GTK_GL_AREA (self->gl_drawing_area));
if (gtk_gl_area_get_error (GTK_GL_AREA (self->gl_drawing_area)) != NULL)
return;
We check if the GtkGLArea
widget is in an error state to decide whether
to bail out and not use GL API on an invalid context.
After that, we initialize our vertex and fragment shaders, as well as the buffer objects.
Every time the user changes the value of the three GtkRange
widgets, the
corresponding GtkAdjustment
is also updated; we catch the value change
in the adjustment_changed
signal handler, which we connected using the
UI description.
The adjustment_changed
signal recomputes the modelview-projection matrix
using a rotation transformation, and calls gtk_widget_queue_draw()
on
the GtkGLArea
widget, signalling that the contents of the widget should
be updated, i.e. redrawn.