Basic usage (WindowConfig)

Note

This section is only relevant when using WindowConfig. Go to the Custom Usage section if you provide your own window and context or want more control.

Using the WindowConfig interface is the simplest way to start with moderngl-window. This can work for smaller projects and implies that this library provides the window and moderngl context.

The API docs for this class alone should cover a lot of ground, but we’ll go through the basics here.

Basic example

The WindowConfig is simply a class you extend to customize/implement initialization, window parameters, rendering code, keyboard input, mouse input and access simpler shortcut methods for loading resources.

import moderngl_window as mglw

class Test(mglw.WindowConfig):
    gl_version = (3, 3)
    window_size = (1920, 1080)

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        # Do initialization here
        self.prog = self.ctx.program(...)
        self.vao = self.ctx.vertex_array(...)
        self.texture = self.ctx.texture(self.wnd.size, 4)

    def render(self, time, frametime):
        # This method is called every frame
        self.vao.render()

# Blocking call entering rendering/event loop
mglw.run_window_config(Test)

The WindowConfig instance will by default receive three external instances in __init__ that can be accessed later with self.

  • self.ctx: The moderngl.Context created by the configured window type

  • self.wnd: The window instance

  • self.timer: The moderngl_window.timers.clock.Timer instance to control the current time (Values passed into render)

Resource loading

The WindowConfig class has built in shortcuts to the resource loading system.

self.load_texture('background.png')
self.load_texture_array('tiles.png', layers=16)
self.load_program('myprogram.glsl')
self.load_text('textfile.txt')
self.load_json('config.json')
self.load_binary('data.bin')
self.load_scene('cube.obj')
self.load_scene('city.gltf')

All paths used in resource loading are relative to an absolute path provided in the WindowConfig.

from pathlib import Path

class Test(mglw.WindowConfig):
    resource_dir = (Path(__file__).parent / 'resources').resolve()

If you need more than one search path for your resources, the moderngl_window.resources module has methods for this.

Generic events and window types

The WindowConfig interface depends on the built in window types or a self-provided window implementation of BaseWindow. These window implementations convert window, key and mouse events into a unified system so the user can switch between different window types without altering the code.

Window libraries are not perfect and may at times work sub-optimally on some platforms. They might also have different performance profiles. The ability to switch between window types by just changing a config value can be an advantage.

You can change what window class is used by passing in the --window option. Optionally you can modify the WINDOW attribute directly.

Command line arguments

The run_window_config() method also reads arguments from sys.argv making the user able to override config values in the class.

Example:

python test.py --window glfw --fullscreen --vsync --samples 16 --cursor false --size 800x600

See code for moderngl_window.parse_args() for more details.

Window events

def resize(self, width: int, height: int):
    print("Window was resized. buffer size is {} x {}".format(width, height))

def close(self):
    print("The window is closing")

def iconify(self, iconify: bool):
    print("Window was iconified:", iconify)

Keyboard input

Implement the key_event and unicode_char_entered method to handle key events.

def key_event(self, key, action, modifiers):
    # Key presses
    if action == self.wnd.keys.ACTION_PRESS:
        if key == self.wnd.keys.SPACE:
            print("SPACE key was pressed")

        # Using modifiers (shift and ctrl)

        if key == self.wnd.keys.Z and modifiers.shift:
            print("Shift + Z was pressed")

        if key == self.wnd.keys.Z and modifiers.ctrl:
            print("ctrl + Z was pressed")

    # Key releases
    elif action == self.wnd.keys.ACTION_RELEASE:
        if key == self.wnd.keys.SPACE:
            print("SPACE key was released")

def unicode_char_entered(self, char: str):
    print('character entered:', char)

Mouse input

Implement the mouse_* methods to handle mouse input.

def mouse_position_event(self, x, y, dx, dy):
    print("Mouse position:", x, y, dx, dy)

def mouse_drag_event(self, x, y, dx, dy):
    print("Mouse drag:", x, y, dx, dy)

def mouse_scroll_event(self, x_offset: float, y_offset: float):
    prtin("Mouse wheel:', x_offset, y_offset)

def mouse_press_event(self, x, y, button):
    print("Mouse button {} pressed at {}, {}".format(button, x, y))

def mouse_release_event(self, x: int, y: int, button: int):
    print("Mouse button {} released at {}, {}".format(button, x, y))