Using cairo with OpenGL

These are my humble beginnings of writing up a tutorial on using cairo with OpenGL. The general view-point of this document is that of a Linux-developer. Please feel free to add your examples and experience from other use-cases (preferably with sourcecode) gained on other platforms. This document assumes some familiarity with the APIs of cairo and OpenGL, the typical development tool-chain under Linux and some graphics-programming in general. Furthermore I want to point out, that I am not an native english speaker and cannot guarantee this text to be error-free.

Typical benefits

So why would you want to mix vector-graphics rendering, provided by cairo, with OpenGL in the first place? Well, there are a few obvious advantages that come to mind...

General approach

Which steps should one usually take in order to get cairo-drawn vector-graphics into an OpenGL-rendered scene...

Our version of "Hello, world!"

This example program tries to be as simple as possible, without being too boring. It is written in plain ANSI C and uses cairo, OpenGL and SDL. Thus it should "translate" to other platforms or languages without much effort. Download the sources with this command...

bzr branch lp:gl-cairo-simple

... or just head over to the project page here

If you have all needed libraries and header-files in place a simple make will compile the program. The result will look something like this...

gl-cairo-simple screenshot

The above image is actually a link to an ogg/theora video, which is about 734 KBytes large. You can see that the graphics adapt to the window-size (due to the screen-capture a bit jerky in response) and during the demonstration the line-thickness is changed with the scroll-wheel of the mouse. The frame-dumps shown after each run are triggered with the d-key.

To avoid blowing up this tutorial, I did not copy&paste the whole sourcecode into this document. The sourcecode is thoroughly commented to help you understand what goes on. Should you have questions, suggestions or patches, feel free to send them to me (macslow@bangang.de).

Beef it up a little

Here is an example-program, that shows off a bit more than the previous "Hello, world!"-variant. It creates three cairo-surfaces (and contexts) and a corresponding OpenGL-texture-object for each of them. In the animation-loop each cairo-surface is refreshed with different contents, that is then copied to an OpenGL-texture and finally mapped on one side of a cube. It addition to cairo and OpenGL it makes use of GTK+ and GtkGlExt for the typical windowing-system boilerplate-code. You can grab the up-to-date version of this with...

bzr branch lp:gl-cairo-cube

... or just head over to the project page here

Once successfully compiled it will look like this...

gl-cairo-cube screenshot

The above image is also a link to an ogg/theora video, which is about 2.9 MBytes in size, so you can see if it's worth trying out getting cairo and OpenGL do their stuff together. You can quit the program with the q- or esc-key, change the overall transparency with the mouse-wheel, rotate the object with LMB-drag and zoom it with RMB-drag. To move the object around on the desktop you'll have to setup your window-manager to trigger window-movement on Alt-LMB-drag. Again, if you have questions, suggestions or patches regarding this program, feel free to send them to me (macslow@bangang.de).

Something with a bit more glitz

This used to be an example using the glitz-backend of cairo. But since glitz has been deprecated and removed from cairo I changed this example to ignore glitz completely. The new cairo-gl backend, which is still experimental, sort of takes over at this point. But I've not been able to update the example (cairo-gimmicks) to use this new backend. Right now only the image-backend is used and should therefore run nearly on every system. To throttle the framerate you can pass -r and the program will try to match that frame-rate. The default is to try to render with 30 Hz. Be sure to read the supplied README. You can grab the up-to-date version of this with...

bzr branch lp:cairo-gimmicks

... or just head over to the project page here

Once successfully compiled it will look like this (depending wether you have a composited environment or not)...

twirling farsi screenshot

composited twirling farsi screenshot

The above images are links to ogg/theora videos, which are 1.6 MBytes and 1.3 MBytes in size. You can quit the program with the q- or esc-key, change the demos with the F1..F4 keys, or mouse-wheel or cursor keys, or PageUp/PageDown keys. Space toggles between pause and animation. If you have questions, suggestions or patches regarding this program, feel free to send them to me (macslow@bangang.de).

Use cairo for an anti-aliasing trick

Here a clever method is demonstrated to get edge-anti-aliasing for textured single quads or rectangles. The computational costs are negligible compared to usual multi- or super-sample based anti-aliasing. The demonstrated technique needs OpenGL-hardware, which is capable of texture-mapping, multi-texturing and executing fragment-shaders. The main idea is to leverage the texture-filtering functions available on OpenGL-cards to do some filtering for us on a cleverly modified texture-image trimmed with a second texture-image acting as a mask or stencil. The cairo-API offers the right means to easily create this trimming mask texture. Thanks to cairo it is also very simple to add nicely rounded corners to the texture image to further improve the smooth look of the final object on screen. The fragment-shader is used to do the actual masking out operation of the two texture-images.

The additional filters implemented as fragment-shaders do not play any role regarding this example. I just added them for fun and to see what one can do image-filter-wise without using FBOs (note: I am well aware that doing gaussian blurring without FBOs is anything but fast).

You can check it out the sources via bazaar, like this...

bzr branch lp:gl-cairo-aatrick

Once successfully compiled it will look like this when running...

The above image is a link to an ogg/theora video, which is 10.4 MBytes in size. You can quit the program with the q- or esc-key and space toggles between pause and animation. The scroll-wheel on the mouse controls a parameter feed to the image-filter shaders in realtime. If you have questions, suggestions or patches regarding this program, feel free to send them to me (macslow@bangang.de).

The simplest example

You can find another simplest example here (no glut, only one source file) (Juan Manuel Mouriz jmouriz@gmail.com).

Further reading