You are on page 1of 5

Alex Via

I blog about tech stuff.

Initializing OpenGL in X11 Pages


Home
 2021-11-13  opengl graphics x11  Archives

In the last post, we created a simple program to open an X11 window. Today, we will learn
Links
how to initialize and use OpenGL to clear the window with a color.
GitHub
Twitter
x11-opengl
Initialization of OpenGL using X11 and GLX Tags
C 1 alsa api
audio
beginner c
And the result: coding gitlab
graphics gui
javascript
linux nodejs
opengl
programming
rest x11

Table of
Contents
Linking with
OpenGL
Creating an
OpenGL
context
Using
OpenGL
Legacy
OpenGL
(fixed
function
pipeline)

Drawing a
triangle 
Linking with OpenGL
Cleanup
In order to use OpenGL we need to include the following headers:

#include <X11/Xutil.h> // Required to use XVisualInfo

#include <GL/gl.h> // OpenGL types and functions like GLuint or glClear


#include <GL/glx.h> // OpenGL X Window bindings like glXCreateContext

And we also need to tell the compiler to link with OpenGL:

# using pkg-config
gcc -o x11_opengl `pkg-config --libs x11 gl` x11_opengl.c

# on my system evaluates to:


gcc -o x11_opengl -lX11 -lGL x11_opengl.c

Creating an OpenGL context

Before creating an OpenGL context we need to select a visual by calling glXChooseVisual.


This function accepts the connection to the display, a screen number and a list of desired
attributes and returns the visual that matches best with the specified attributes.

In our case, we want to request a visual with support for TrueColor, double buffering and a
24-bit depth buffer.

XVisualInfo *visual = glXChooseVisual(display, 0, (int[]){


GLX_RGBA,
GLX_DEPTH_SIZE, 24,
GLX_DOUBLEBUFFER,
None
});
printf("Visual ID: %x\n", visual->visualid); // 2b4 in my environment

We can use the program glxinfo with the flag v glxinfo -v , to check what visuals are
supported in our system.

106 GLX Visuals


Visual ID: 20 depth=24 class=TrueColor, type=window,pixmap,pbuffer
bufferSize=32 level=0 renderType=rgba doubleBuffer=1 stereo=0
rgba: redSize=8 greenSize=8 blueSize=8 alphaSize=8 float=N sRGB=N
auxBuffers=0 depthSize=24 stencilSize=8
accum: redSize=0 greenSize=0 blueSize=0 alphaSize=0
multiSample=0 multiSampleBuffers=0
visualCaveat=None
Opaque.

...
Visual ID: 2b4 depth=24 class=TrueColor, type=window,pixmap,pbuffer
bufferSize=24 level=0 renderType=rgba doubleBuffer=1 stereo=0

rgba: redSize=8 greenSize=8 blueSize=8 alphaSize=0 float=N sRGB=N
auxBuffers=0 depthSize=24 stencilSize=8
accum: redSize=0 greenSize=0 blueSize=0 alphaSize=0
multiSample=0 multiSampleBuffers=0
visualCaveat=None
Opaque.
...

With the visual selected, we can create the GL context by calling glXCreateContext.

GLXContext gl_context = glXCreateContext(display, visual, 0, True);

Once we have a valid GL context and we’ve also created an X11 window, we can bind them
so that OpenGL will render to the window, from this point onward. This is achieved by calling
glXMakeCurrent.

glXMakeCurrent(display, window, gl_context);

Using OpenGL

After creating and setting the GL context, we can start making OpenGL calls. We can clear
the window background to a dark gray color by calling glClearColor inside our main loop,
specifying the red, green, blue and alpha components ranging from 0.0 to 1.0. Followed by
a call to glClear specifying that we want to clear the color buffer.

Finally, since we are using double-buffering we need to call glXSwapBuffers in order to


swap the front and back buffers.

while (!quit) {
...

glClearColor(0.15, 0.15, 0.15, 1.0);


glClear(GL_COLOR_BUFFER_BIT);

// render code goes here

glXSwapBuffers(display, window);
}

Legacy OpenGL (fixed function pipeline)

Starting from OpenGL 2.0, shaders were introduced, and from OpenGL 3 onwards many
features were marked as deprecated, effectively dividing OpenGL in 2 so called “profiles”.
The OpenGL core profile, with all the deprecated functionality removed, and the OpenGL 
compatibility profile, keeping the deprecated features.

We will be using the fixed function pipeline or “Legacy” OpenGL here, but we might explore
a more modern approach in a future post.

Drawing a triangle

In order to draw a triangle, we can specify the vertices inside a block starting with glBegin
and ending with glEnd. The color of the triangle can be specified via one of the variants of
glColor, which applies to all the vertices that follow, and vertex positions via glVertex. These
coordinates go from (-1.0, -1.0) on the lower left to (1.0, 1.0) on the top right.

glBegin(GL_TRIANGLES);
glColor3f(0.68, 0.84, 0.0);
glVertex2f(-0.5, -0.5);
glVertex2f( 0.5, -0.5);
glVertex2f( 0.0, 0.5);
glEnd();

Cleanup

Finally, when all the rendering is done, and the application is shutting down, it is good
practice to destroy the GL context via glXDestroyContext.

glXDestroyContext(display, gl_context);

© 2020-2021 Alex Via


You might also like