Getting started

Getting started with a new library or framework can be daunting, especially when presented with a large amount of reference material to read. This chapter gives a very quick introduction to glumpy without covering any of the details.

Content

Creating a window

Creating a new window is straightforward:

from glumpy import app
window = app.Window()
app.run()

You should see immediately a new window on your desktop with possibly some garbage on it. The reason for the garbage is that we do not clear the window. A better minimal version is thus:

from glumpy import app

window = app.Window()

@window.event
def on_draw(dt):
    window.clear()

app.run()

In this version, we use the on_draw() event that is dispatched every time a redraw is needed for the window. Within our on_draw handler, the window is cleared to the default background color (black).

The final call to the app.run() gives control to the glumpy application loop that will respond to application events such as the mouse and the keyboard.

Note

The run method only returns when all application windows have been closed unless the program has been launched in interactive mode. If you start the program using the --interactive switch, the app.run() is no longer blocking.

Displaying a quad

Modern OpenGL is very powerful but hard to understand and program. Any drawing operation requires a number of preparatory steps that make it cumbersome to use without additonal libraries. Glumpy offers an easier access through the gloo interface which is a kind of glue between numpy and OpenGL.

Let’s see how to draw a full-window colored quad using glumpy. First steps is to import the relevant modules and create the window.

from glumpy import app, gloo, gl

window = app.Window()

We then need to create a GLSL program that will be in charge of displaying a quad. To do this, we first have to write a vertex and a fragment shader that will tell OpenGL exactly what and how to draw things. No need to understand them yet but the important point here is that those program are just text strings.

vertex = """
         attribute vec2 position;
         void main()
         {
             gl_Position = vec4(position, 0.0, 1.0);
         } """

fragment = """
           uniform vec4 color;
           void main() {
               gl_FragColor = color;
           } """

quad = gloo.Program(vertex, fragment, count=4)

The nice thing with the gloo interface is that you can now directly upload some data to the GPU using convenient notation. The position index directly relates to the position attribute within the vertex shader and the color index relates to the color uniform within the fragment shader.

quad['position'] = [(-0.5, -0.5),
                    (-0.5, +0.5),
                    (+0.5, -0.5),
                    (+0.5, +0.5)]
quad['color'] = 1,0,0,1  # red

Last, we specify in the on_draw() method that the quad needs to be rendered using gl.GL_TRIANGLE_STRIP.

@window.event
def on_draw(dt):
    window.clear()
    quad.draw(gl.GL_TRIANGLE_STRIP)

app.run()

Animating shapes

Animation is just a matter of modifying what is drawn at each time step. We’ll use the example above in order to make the quad to grow and shrinks with time. First things is to keep track of time using the prodived dt parameter in the on_draw() function that give the elapsed time since last call. We’ll first add a new uniform in the vertex shader source code and adapt quad coordinates according to the sine of the time variable.

vertex = """
         uniform float time;
         attribute vec2 position;
         void main()
         {
             vec2 xy = vec2(sin(2.0*time));
             gl_Position = vec4(position*(0.25 + 0.75*xy*xy), 0.0, 1.0);
         } """

quad = gloo.Program(vertex, fragment, count=4)

We also need to initialize the time variable and to update it at each draw call.

@window.event
def on_draw(dt):
    window.clear()
    quad["time"] += dt
    quad.draw(gl.GL_TRIANGLE_STRIP)

quad["time"] = 0.0
quad['color'] = 1,0,0,1
quad['position'] = [(-1, -1), (-1, +1), (+1, -1), (+1, +1)]
app.run()

Note

If you want to record the animation you can use the --record filename switch when starting your application.