nullprogram.com/blog/2015/06/06/
When I was first attempting to learn OpenGL years ago, what I really
wanted was a complete, minimal example program. OpenGL has enormous
flexibility and I wanted to fully understand the fundamentals
in isolation before moving on to more advanced features. I had been
advised to specifically learn core profile, which drops nearly all
the legacy parts of the API.
However, since much of the OpenGL-related content to be found online,
even today, is outdated — and, worse, it’s not marked as
such — good, modern core profile examples have been hard to come by.
The relevant examples I could find at the time were more complicated
than necessary, due to the common problem that full 3D graphics are
too closely conflated with OpenGL. The examples would include matrix
libraries, texture loading, etc. This is a big reason I ended up
settling on WebGL: a clean slate in a completely different
community. (The good news is that this situation has already improved
dramatically over the last few years!)
Until recently, all of my OpenGL experience had been WebGL.
Wanting to break out of that, earlier this year I set up a minimal
OpenGL 3.3 core profile demo in C, using GLFW and
gl3w. You can find it here:
No 3D graphics, no matrix library, no textures. It’s just a spinning
red square.
It supports both Linux and Windows. The Windows’ build is static, so
it compiles to a single, easily distributable, standalone binary. With
some minor tweaking it would probably support the BSDs as well. For
simplicity’s sake, the shaders are baked right into the source as
strings, but if you’re extending the demo for your own use, you may
want to move them out into their own source files.
Why OpenGL 3.3?
I chose OpenGL 3.3 in particular for three reasons:
- Core and compatibility profiles were introduced in OpenGL 3.2
(2009). Obviously anything that focuses on core profile is going to
be 3.2 and up.
- OpenGL 3.3 (2010) introduced version 3.30 of the shading
language. This was a big deal and there’s little reason not to take
advantage of it. I specifically wanted to use the new
layout
keyword.
- Mesa 10.0 (2013) supports up to OpenGL 3.3. Mesa is the
prominent 3D graphics library for open source operating systems.
It’s what applications use for both hardware-accelerated and
software OpenGL rendering. This means the demo will work on any
modern Linux installation. (Note: when running on older hardware
without OpenGL 3.3 support, you may have to force software rendering
with the environment variable
LIBGL_ALWAYS_SOFTWARE=1
. The
software renderer will take advantage of your CPU’s SIMD features.)
As far as “desktop” OpenGL goes, 3.3 is currently the prime target.
Why GLFW?
Until EGL someday fills this role, the process for obtaining an
OpenGL context is specific to each operating system, where it’s
generally a pain in the butt. GLUT, the OpenGL Utility Toolkit, was a
library to make this process uniform across the different platforms.
It also normalized user input (keyboard and mouse) and provided some
basic (and outdated) utility functions.
The original GLUT isn’t quite open source (licensing issues) and it’s
no longer maintained. The open source replacement for GLUT is
FreeGLUT. It’s what you’d typically find on a Linux
system in place of the original GLUT.
I just need a portable library that creates a window, handles keyboard
and mouse events in that window, and gives me an OpenGL 3.3 core
profile context. FreeGLUT does this well, but we can do better. One
problem is that it includes a whole bunch of legacy cruft from GLUT:
immediate mode rendering utilities, menus, spaceball support, lots of
global state, and only one OpenGL context per process.
One of the biggest problems is that FreeGLUT doesn’t have a swap
interval function. This is used to lock the application’s redraw
rate to the system’s screen refresh rate, preventing screen tearing
and excessive resource consumption. I originally used FreeGLUT for the
demo, and, as a workaround, had added my own macro work around this by
finding the system’s swap interval function, but it was a total hack.
The demo was initially written with FreeGLUT, but I switched over to
GLFW since it’s smaller, simpler, cleaner, and more modern.
GLFW also has portable joystick handling. With the plethora of modern
context+window creation libraries out there, it seems there’s not much
reason to use FreeGLUT anymore.
SDL 2.0 would also be an excellent choice. It goes beyond GLFW
with threading, audio, networking, image loading, and timers:
basically all the stuff you’d need when writing a game.
I’m sure there are some other good alternatives, especially when
you’re not sticking to plain C, but these are the libraries I’m
familiar with at the time of this article.
Why gl3w?
If you didn’t think the interface between OpenGL and the operating
system was messy enough, I have good news for you. Neither the
operating system nor the video card drivers are going to provide any
of the correct headers, nor will you have anything meaningful to link
against! For these, you’re on your own.
The OpenGL Extension Wrangler Library (GLEW) was invented solve this
problem. It dynamically loads the system’s OpenGL libraries and finds
all the relevant functions at run time. That way your application
avoids linking to anything too specific. At compile time, it provides
the headers defining all of the OpenGL functions.
Over the years, GLEW has become outdated, to this day having no
support for core profile. So instead I used a replacement called
gl3w. It’s just like GLEW, but, as the name suggests, oriented
around core profile … exactly what I needed. Unlike GLEW, it is
generated directly from Kronos’ documentation by a script. In
practice, you drop the generated code directly into your project
(embedded) rather than rely on the system to provide it as a library.
A great (and probably better) alternative to gl3w is
glLoadgen. It’s the same idea — an automatically
generated OpenGL loader — but allows for full customization of the
output, such as the inclusion of select OpenGL extensions.
Conclusion
While I hope it serves an educational resources for others, I
primarily have it for my own record-keeping, pedagogical, and
reference purposes, born out of a weekend’s worth of research. It’s a
starting point for future projects, and it’s somewhere easy to start
when I want to experiment with an idea.
Plus, someday I want to write a sweet, standalone game with fancy
OpenGL graphics.