Calling some OpenGL functions from Python with pyglet can be a bit tricky due to fact that the functions are only thin wrappers around the C-API.
My sample program demonstrates some calls for using modern OpenGL with pyglet. The program is intentionally quite flat, without any classes. In a larger program I would manage the involved OpenGL objects with Python classes.
This is not a full tutorial, but some aspects of the sample program are explained below.
I used Pyglet because it includes an OpenGL binding and supports Python 3.
pyglet provides an object-oriented programming interface for developing games and other visually-rich applications for Windows, Mac OS X and Linux.
Call by Reference
Many OpenGL calls use a call by reference / pointer for returning values. These can be called using
The example first creates a GLuint initialized to zero and then passes a pointer to glGenBuffers.
from pyglet import gl
vertexbuffer = gl.GLuint(0)
Structs for Vertex Attributes
Using a struct for passing vertex attributes can take advantage of the meta-information provided by ctypes. It is also easier to manage than a flat array of float values. In the example the vertex shader takes a vec2 and a vec4 as attributes.
Note that as in the example above I use the type aliases provided by pyglet.gl in order to ensure compatible types with OpenGL.
In ctypes you create an array by multiplying the type object.
_fields_ = [
('position', gl.GLfloat * 2),
('color', gl.GLfloat * 4),
The structure fields are given an offset attribute which can be used for passing to glVertexAttribPointer
gl.glVertexAttribPointer(loc_position, 2, gl.GL_FLOAT, False,
gl.glVertexAttribPointer(loc_color, 4, gl.GL_FLOAT, False,
And the structure is initialized very easily; here I create an array of three vertices, each containing a 2D position and a 4D color.
data = (VERTEX * 3)(((-0.6, -0.5), (1.0, 0.0, 0.0, 1.0)),
(( 0.6, -0.5), (0.0, 1.0, 0.0, 1.0)),
(( 0.0, 0.5), (0.0, 0.0, 1.0, 1.0)))
OpenGL expects C-style strings, so it is easiest to use byte strings.
ctypes has string buffers which can tranlate between
bytes in Python and
char* in C.
loc_position = gl.glGetAttribLocation(program,
They can also be used for retrieving strings from OpenGL such as the log of a shader compilation.
length = gl.GLint(0)
gl.glGetShaderiv(shader_name, gl.GL_INFO_LOG_LENGTH, ctypes.byref(length))
log_buffer = ctypes.create_string_buffer(length.value)
gl.glGetShaderInfoLog(shader_name, length, None, log_buffer)
Finding out about getting the compilation log really helped me when writing my own shaders.
The code for passing the shader source to OpenGL is still somewhat messy with a ctypes cast. I would be glad if you can suggest a better alternative in the comments.
src_buffer = ctypes.create_string_buffer(shader_source)
buf_pointer = ctypes.cast(ctypes.pointer(ctypes.pointer(src_buffer)),
length = ctypes.c_int(len(shader_source) + 1)
gl.glShaderSource(shader_name, 1, buf_pointer, ctypes.byref(length))