Graphic designing using OpenGL and Python [Beginners]
Tags: python, opengl, graphic, beginners
Published: 2020-05-28 12:26:31

## 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 <a href="https://www.opengl.org/resources/libraries/">OpenGL docs</a>)


## Installation

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

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

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

4. Install the libraries.
`` pip install PyOpenGL PyOpenGL_accelerate ``

<br>

## 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'

2. Create two points in following coordinates.
 - P1 (100,100)
 - P2 (300, 200)
 - Point Size: 10px

3. Draw a Rectangle.
 - Height: 100px
 - Width: 200px
 - Starting point; (100, 100)

4. Draw a triangle 10px above the given rectangle.


## Lets Code

<b>Step 1</b>
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 *
```

<b>Step 2</b>
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 . 

<b>Step 3</b>
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)
```

<b>Step 4</b>
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
```

<b>Step 5</b>
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 <a href="https://www.youtube.com/watch?v=VhdFGUHb0us">John White's Video</a> 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.

<img src="https://i.imgur.com/5RQzbGW.png">

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. <i>Make sure you pass a float value!</i>
```
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.

<img src="https://i.imgur.com/ovjK7A2.png">

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.

<img src="https://i.imgur.com/vdG9PgJ.png">

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.

<img src="https://i.imgur.com/WMEAStA.png">

Complete Code: 
https://gist.github.com/Suvink/fe5837701c62761d2e9661dfaaae7b84

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