What is OpenGL, GLUT and PyOpenGL?

OpenGL (Open Graphics Library) is a cross-language, cross-platform application programming interface (API) for rendering 2D and 3D vector graphics. And GLUT is the OpenGL Utility Toolkit, a window system independent toolkit for writing OpenGL programs. It implements a simple windowing API for OpenGL. GLUT makes it considerably easier to learn about and explore OpenGL Programming. And finally, PyOpenGL is the most common cross platform Python binding to OpenGL and related APIs. (Definitions from OpenGL docs)

Installation

Create a new directory and open it.
mkdir opengl-learn  && cd opengl-learn

Create a virtual environment. (Just to be safe!)
python3 -m venv opengl-tut

Activate the virtual environment.
source opengl-tut/bin/activate

Install the libraries.
pip install PyOpenGL PyOpenGL_accelerate

What we are gonna do?

  1. First we are gonna create a window with following properties.
  • Height: 500px , Width: 500px
  • Background Color: RGB(1,1,0)
  • Window Position: (100, 100)
  • Objects Color: RGB (0.2, 0.5, 0.4)
  • Title: 'My OpenGL Code'
  1. Create two points in following coordinates.
  • P1 (100,100)
  • P2 (300, 200)
  • Point Size: 10px
  1. Draw a Rectangle.
  • Height: 100px
  • Width: 200px
  • Starting point; (100, 100)
  1. Draw a triangle 10px above the given rectangle.

Lets Code

Step 1
First open an empty file and name it as drawing.py (use any name you want). Then you have to import the libraries.

from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *

Step 2
First we need to initiate GLUT.

glutInit()

Then you can see in our windows properties, the colors are given in RGB format. So we need to initiate the display mode with RGB.

glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB)

Here, GLUT_SINGLE refers to the buffer context. SINGLE means there is only one frame buffer that is used to draw and display the content. Simply, that you draw more or less directly to the screen .

Step 3
Next we need to set the window size and window position. This is pretty much a straight forward. The command itself explains what is it.

glutInitWindowSize(500, 500)  #(height, width)
glutInitWindowPosition(100, 100) #(x pos, y pos)

Step 4
Now with the given basic configuration, we can create the window with any name we want.

glutCreateWindow("My OpenGL Code") #Use any name you want

Step 5
Next we need to add some extra settings for the window we just created. First we need to create a new function. I'm calling it myInit(). Inside this function, Im setting up the background color and foreground color. Define this function before glutInit().

def myInit():
   glClearColor(1.0, 1.0, 0.0, 1.0); #RGBA
   glColor3f(0.2, 0.5, 0.4); #RGB

glClearColor sets the background color in RGBA (Red, Green, Blue, Alpha) format and glColor3f sets the color for our objects in RGB format.

And then we can go ahead and call this function and initiate.

So that's it for the basic setup. Now we can see our code like this.

from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *

def myInit():
    glClearColor(1.0, 1.0, 0.0, 1.0)
    glColor3f(0.2, 0.5, 0.4)


glutInit()
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB)  

glutInitWindowSize(500, 500)
glutInitWindowPosition(100, 100) 

glutCreateWindow("My OpenGL Code") 

myInit()

Now we will create the two points. OpenGL draws objects using coordinates. Just like you drew shapes in Cartesian plane (කාටිසීය තලය, ඛණ්ඩාංක තලය in Sinhala) when you were a kid.
Before doing anything, we need to define a projection matrix.
Here, we are using an Orthographic projection matrix. Orthographic projection means representing three-dimensional objects in two dimensions. For more info on Orthographic projections, refer John White's Video on YouTube.

Goto your myInit function and define your matrix like this.

gluOrtho2D(0, 500, 0, 500) // left, right, bottom, top

This will create a projection matrix, which maps 0 to the left border of the frame, 500 to the right, 0 to the bottom and 500 to the top.

Then it says the point size is 10px. Let's define that as well. Again inside your myInit function, define the point size as 10px. Make sure you pass a float value!

glPointSize(10.0)

Now that the setup is done, we can draw out points on the matrix. To do that, I'm going to create a new function called display. This display function will hold the code that is used to draw anything inside our frame.

def display():

We will start by clearing the current color buffer.

glClear(GL_COLOR_BUFFER_BIT)

Then we define the start point of what we are going to draw by

glBegin(GL_POINTS)

GL_POINTS means that we are going to draw points in this section.
Now we can draw out first coordinate (vertex). In the above properties list, it says that the first coordinate is P1(100,100). We'll draw that one first.

glVertex2f(100, 100)

The second coordinate P2 (300, 200) goes in the same way.

glVertex2f(300, 300)

Then at last, mark the end by

glEnd()
glFlush()

glFlush() will clean the buffer. Now we need to call this display() function in order to draw the points on our frame. To do this, we have a function named glutDisplayFunc() in GLUT library.

glutDisplayFunc(display) 

And right after that, we need to set the loop for the program to run. This function loops within itself, processing events and triggering your callback functions when necessary.

glutMainLoop()

So the complete code as of now will look like this.

from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *

def myInit():
    glClearColor(1.0, 1.0, 0.0, 1.0) 
    glColor3f(0.2, 0.5, 0.4)
    glPointSize(10.0)
    gluOrtho2D(0, 500, 0, 500)

def display():
    glClear(GL_COLOR_BUFFER_BIT)
    
    glBegin(GL_POINTS)
    glVertex2f(100, 100)
    glVertex2f(300, 200)
    glEnd()
    
    glFlush()


glutInit()
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB)   
glutInitWindowSize(500, 500)  
glutInitWindowPosition(100, 100)  
glutCreateWindow("My OpenGL Code")
myInit()
glutDisplayFunc(display) 
glutMainLoop()

You can run the file by executing python drawing.py on your command line.

Now let's move onto the second object. The rectangle.
Goto the display() function and after glEnd() function, we have to write the code for the rectangle.

Before writing any code, I drew my rectangle with the given starting coordinate and the measurements for the width and height on a paper. So starting point is (100,100) and height is 100px and width is 200px. It will give you something like this.

So now let's set this coordinates in the code.

glBegin( GL_QUADS ) 
glVertex2f( 100.0, 100.0 ) 
glVertex2f( 300.0, 100.0 ) 
glVertex2f( 300.0, 200.0 ) 
glVertex2f( 100.0, 200.0 ) 
glEnd()

Here you have to define GL_QUADS as a parameter to glBegin(). GL_QUADS will treat each group of four vertices(coordinates) as an independent quadrilateral.

Then we'll move onto the Triangle part. In the properties section, it says that the triangle will have to position 10px above the rectangle. So like the previous time, I drew this on a paper.

Now the code. Here you have to pass GL_TRIANGLE_STRIP into glBegin() so that it will group 3 vertices as a triangle.

glBegin(GL_TRIANGLE_STRIP) 
glVertex2f(100.0, 210.0) 
glVertex2f(300.0, 210.0) 
glVertex2f(300.0, 310.0) 
glEnd()

That's it! Now you can run the code and see the following output.

Complete Code:

Drawing objects with Python and OpenGL.
Drawing objects with Python and OpenGL. . GitHub Gist: instantly share code, notes, and snippets.

If you have any questions, feel free to ask in the comments section.
Thanks!