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...
Create pristine texture-maps, which are resolution-independent and combine those with your custom mip-mapping.
Get access to gradient-rendering functions not provided by OpenGL.
Get crisp unicode-based font-rendering for "free" (needs pango in addition to cairo).
Easily integrate features like PS-, PDF-, SVG-support to your OpenGL-application (may need additional libraries).
Have animated vector-graphics as head-up-displays or overlays in your OpenGL-program.
Get your good looking graphics-application ported to other systems, without having to worry about API-availability.
Just be ultra trendy and the coolest kid on the block ;)
General approach
Which steps should one usually take in order to get cairo-drawn vector-graphics into an OpenGL-rendered scene...
Create your cairo-surface/context (maybe even glitz-based) you want to use as a source for later texture-map generation.
Render into the cairo-context with normal cairo-calls.
Copy the cairo-surface into an OpenGL-texture with
glTexImage2D().Use this texture to map your OpenGL-primitives with.
Rendering to the cairo-surface and copying that to the OpenGL-texture afterwards, can also be done in your rendering-loop, if you want to animate the cairo-graphics themselves from frame to frame.
For the time being disregard the idea of drawing into the same surface or texture with cairo- and OpenGL-calls. This is possible, but not in a very straight forward fashion. Also threadding-issues are not covered here at the moment. Everything happens in one thread right now.
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...
git clone git://people.freedesktop.org/~macslow/gl-cairo-simple
... or grab the automatically generated tarball gl-cairo-simple.tar.bz2 (SHA1SUM)
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...
The above image is actually a link to an ogg/theora video, which is about 2 MBytes 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...
git clone git://people.freedesktop.org/~macslow/gl-cairo-cube
... or grab the automatically generated tarball gl-cairo-cube.tar.bz2 (SHA1SUM)
Once successfully compiled it will look like this...
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 is an example demonstrating how to setup a glitz-backend and use that for rendering cairo via OpenGL. You can pass -n on the commandline to avoid using glitz and fallback to the image-backend, which should 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 from the git-repository or tarball.
git clone git://people.freedesktop.org/~macslow/glitz-test
... or grab the automatically generated tarball glitz-test.tar.bz2 (SHA1SUM)
Once successfully compiled it will look like this (depending wether you have a composited environment or not)...
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 though. 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. The edges of an image have to be trimmed slightly for this to take effect. The cairo-API offers the right means to easily trim an image in advance before uploading it to the OpenGL-card as texture-object. 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 visual improvement can be clearly seen in this screenshot...
You can check it out the sources via git, like this...
git clone git://people.freedesktop.org/~macslow/gl-cairo-aatrick
... or grab the automatically generated tarball gl-cairo-aatrick.tar.bz2 (SHA1SUM)
Once successfully compiled it will look like this when running...
The above image is a link to an ogg/theora video, which is 1.4 MBytes in size. You can quit the program with the q- or esc-key and 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).
Further reading
OpenGL, the main resource for OpenGL on the web
MacSlow's site with several example programs using cairo, OpenGL, glitz and librsvg
librsvg, a library for adding SVG-support to your application
gtk+, the native UI-toolkit of Gnome, used by many Linux-programs, cross-platform
pigment, library for fast, visually rich graphical user interfaces (currently geared towards Elisa)
clutter, another library for fast, visually rich graphical user interfaces
GtkGlExt, a very good OpenGL-widget/binding for gtk+
SDL, a handy and ultra-thin "convenience" library for platform-abstraction
Amanith, the "competition", good, but not as free and versatile
