Voxel Engine in Python and OpenGL(Blog Post 10/4/24)

MAKING THE OPENGL WINDOW

To install OpenGL and other modules:

pip install PyOpenGL
pip install pygame moderngl PyGLM numba

First import the common modules for the program in “settings.py”.

from numba import njit
import numpy as np
import glm
import math

Put in the respective background color and window resolution in “settings.py”.

# Window resolution
WIN_RES = glm.vec2(1600, 900)

# Colors
BG_COLOR = glm.vec3(0.1, 0.16, 0.25)

Import modules in “main.py” and create a class of VoxelEngine.

from settings import *
import moderngl as mgl
import pygame as pg
import sys

class VoxelEngine:

class VoxelEngine:
    def __init__(self):
        pg.init()
        pg.display.gl_set_attribute(pg.GL_CONTEXT_MAJOR_VERSION, 3)
        pg.display.gl_set_attribute(pg.GL_CONTEXT_MINOR_VERSION, 3)
        pg.display.gl_set_attribute(pg.GL_CONTEXT_PROFILE_MASK, pg.GL_CONTEXT_PROFILE_CORE)
        pg.display.gl_set_attribute(pg.GL_DEPTH_SIZE, 24)

        pg.display.set_mode(WIN_RES, flags=pg.OPENGL | pg.DOUBLEBUF)
        self.ctx = mgl.create_context()

        self.ctx.enable(flags=mgl.DEPTH_TEST | mgl.CULL_FACE | mgl.BLEND)
        self.ctx.gc_mode = 'auto'

        self.clock = pg.time.Clock()
        self.delta_time = 0
        self.time = 0

        self.is_running = True

    def update(self):
        self.delta_time = self.clock.tick()
        self.time = pg.time.get_ticks() * 0.001
        pg.display.set_caption(f'{self.clock.get_fps() :.0f}')

    def render(self):
        self.ctx.clear(color=BG_COLOR)
        pg.display.flip()

    def handle_events(self):
        for event in pg.event.get():
            if event.type == pg.QUIT or (event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE):
                self.is_running = False

    def run(self):
        while self.is_running:
            self.handle_events()
            self.update()
            self.render()
        pg.quit()
        sys.exit()

if __name__ == '__main__':
    app = VoxelEngine()
    app.run()

(this will get larger overtime)

Define the attributes for the program (in “def __init__”).

pg.init()
        pg.display.gl_set_attribute(pg.GL_CONTEXT_MAJOR_VERSION, 3)
        pg.display.gl_set_attribute(pg.GL_CONTEXT_MINOR_VERSION, 3)
        pg.display.gl_set_attribute(pg.GL_CONTEXT_PROFILE_MASK, pg.GL_CONTEXT_PROFILE_CORE)

Set the window resolution and create OpenGL context

  pg.display.set_mode(WIN_RES, flags=pg.OPENGL | pg.DOUBLEBUF)
        self.ctx = mgl.create_context()

Enable the context and set the garbage collection mode(gc_mode) to ‘auto’

self.ctx.enable(flags=mgl.DEPTH_TEST | mgl.CULL_FACE | mgl.BLEND)
        self.ctx.gc_mode = 'auto'

After that, set a time variable to keep the window on the screen a variable to run things in the main function

self.clock = pg.time.Clock()
        self.delta_time = 0
        self.time = 0

        self.is_running = True

In “def update()”, set the delta time and update its tick for every frame, then put it as a caption on the top left-hand corner of the screen.

self.delta_time = self.clock.tick()
        self.time = pg.time.get_ticks() * 0.001
        pg.display.set_caption(f'{self.clock.get_fps() :.0f}')

Plaster the background color from “settings.py” and update it to the screen in “def render()”

 self.ctx.clear(color=BG_COLOR)
        pg.display.flip()

In “def handle_events()”, make a for loop that checks if the player has clicked the “x” on the window or the down arrow key and the “escape” key (Esc) and will turn “is_running” to be false, which closes the window.

def handle_events(self):
        for event in pg.event.get():
            if event.type == pg.QUIT or (event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE):
                self.is_running = False

Initialize all functions in “def run()”.

def run(self):
        while self.is_running:
            self.handle_events()
            self.update()
            self.render()
        pg.quit()
        sys.exit()

and this too for the code to actually work 🙂

if __name__ == '__main__':
    app = VoxelEngine()
    app.run()

RESULT:

W/O the background color:

WITH the background:

I’m now working on the initial setup 😀

Author: Zende_

From PA. EHS 2025. Does computer programming and such. That's really it.

Leave a Reply

Your email address will not be published. Required fields are marked *