Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

OpenGL for Py++

pypp-opengl is a Py++ library for OpenGL

Examples

Drawing a triangle

The canonical OpenGL starting-point program of drawing a triangle.

from pypp_opengl import (
    GL,
    np,
    gl_gen_buffer,
    gl_gen_vertex_array,
    gl_shader_source,
    gl_get_shader_iv,
    gl_get_program_iv,
    gl_get_shader_info_log,
    gl_get_program_info_log,
    gl_delete_buffer,
    gl_delete_vertex_array,
    glad_load_gl,
)
from pypp_glfw import GLFWwindowPtr, glfw
from pypp_python import to_c_string, NULL, float32
from pypp_python.stl import ctypes

# Vertex shader source
vertex_shader_src: str = """
#version 330 core
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 color;

out vec3 vertexColor;

void main()
{
    gl_Position = vec4(position, 1.0);
    vertexColor = color;
}
"""

# Fragment shader source
fragment_shader_src: str = """
#version 330 core
in vec3 vertexColor;
out vec4 FragColor;

void main()
{
    FragColor = vec4(vertexColor, 1.0);
}
"""


def compile_shader(source: str, shader_type: GL.GLenum) -> GL.GLuint:
    shader: GL.GLuint = GL.glCreateShader(shader_type)
    gl_shader_source(shader, source)
    GL.glCompileShader(shader)
    if not gl_get_shader_iv(shader, GL.GL_COMPILE_STATUS):
        raise RuntimeError(
            "Shader compilation failed: " + gl_get_shader_info_log(shader)
        )
    return shader


def create_shader_program() -> GL.GLuint:
    vertex_shader: GL.GLuint = compile_shader(vertex_shader_src, GL.GL_VERTEX_SHADER)
    fragment_shader: GL.GLuint = compile_shader(
        fragment_shader_src, GL.GL_FRAGMENT_SHADER
    )

    program: GL.GLuint = GL.glCreateProgram()
    GL.glAttachShader(program, vertex_shader)
    GL.glAttachShader(program, fragment_shader)
    GL.glLinkProgram(program)

    if not gl_get_program_iv(program, GL.GL_LINK_STATUS):
        raise RuntimeError(
            "Program linking failed: " + gl_get_program_info_log(program)
        )

    GL.glDeleteShader(vertex_shader)
    GL.glDeleteShader(fragment_shader)

    return program


def opengl_test():
    # Initialize GLFW
    if not glfw.init():
        raise Exception("Failed to initialize GLFW")

    glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 4)
    glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 6)
    glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)

    # Create window
    window: GLFWwindowPtr = glfw.create_window(
        800, 600, to_c_string("PyOpenGL Triangle"), NULL, NULL
    )
    if not window:
        glfw.terminate()
        raise Exception("Failed to create GLFW window")

    glfw.make_context_current(window)

    if not glad_load_gl():
        raise Exception("Failed to initialize GLAD")

    # Vertex data (positions + colors)
    # fmt: off
    vertices: list[float32] = [
        -0.5, -0.5, 0.0, 
        1.0, 0.0, 0.0,  # bottom left (red)
        0.5, -0.5, 0.0,
        0.0, 1.0, 0.0,  # bottom right (green)
        0.0, 0.5, 0.0,
        0.0, 0.0, 1.0,  # top (blue)
    ]
    # fmt: on

    # Create VAO and VBO
    vao: GL.GLuint = gl_gen_vertex_array()
    vbo: GL.GLuint = gl_gen_buffer()

    GL.glBindVertexArray(vao)

    GL.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo)
    GL.glBufferData(
        GL.GL_ARRAY_BUFFER,
        len(vertices) * GL.sizeof(GL.GLfloat),
        np.array(vertices, np.float32),
        GL.GL_STATIC_DRAW,
    )

    # Position attribute
    GL.glVertexAttribPointer(
        0, 3, GL.GL_FLOAT, GL.GL_FALSE, 6 * GL.sizeof(GL.GLfloat), ctypes.c_void_p(0)
    )
    GL.glEnableVertexAttribArray(0)

    # Color attribute
    GL.glVertexAttribPointer(
        1,
        3,
        GL.GL_FLOAT,
        GL.GL_FALSE,
        6 * GL.sizeof(GL.GLfloat),
        ctypes.c_void_p(3 * GL.sizeof(GL.GLfloat)),
    )
    GL.glEnableVertexAttribArray(1)

    # Build shader program
    shader_program: GL.GLuint = create_shader_program()

    # Main render loop
    while not glfw.window_should_close(window):
        glfw.poll_events()

        GL.glClearColor(0.2, 0.3, 0.3, 1.0)
        GL.glClear(GL.GL_COLOR_BUFFER_BIT)

        GL.glUseProgram(shader_program)
        GL.glBindVertexArray(vao)
        GL.glDrawArrays(GL.GL_TRIANGLES, 0, 3)

        glfw.swap_buffers(window)

    # Cleanup
    gl_delete_vertex_array(vao)
    gl_delete_buffer(vbo)
    glfw.terminate()


if __name__ == "__main__":
    opengl_test()

API

The API is mainly defined by the PyOpenGL project (i.e. you use GL.someName, like with PyOpenGL). However, there are a few special functions that pypp-opengl has a separate API for, to make them more compatiable with Py++ (since Py++ is statically typed and does not use pointers). These special functions are:

gl_gen_buffer
gl_gen_buffers
gl_delete_buffer
gl_gen_vertex_array
gl_gen_vertex_arrays
gl_delete_vertex_array
gl_delete_vertex_arrays
gl_shader_source
gl_shader_sources
gl_get_shader_iv
gl_get_program_iv
gl_get_shader_info_log
gl_get_program_info_log

Supported OpenGL attributes and functions

Only the attributes and functions which are shown in the above examples are tested. However, its very likely that others will work also, and you will most easily find out by trying them in your code.

When you find an attribute or function which does not work, it would be really helpful if you submit a feature request with title support for <some_name>. Thanks in advance for if you do that.

Bug reports

Report bugs to the Issues tab on this github repo using the bug label.

Feature requests

Submit feature requests to the Issues tab on this github repo using the feature request label.

Metadata

Release files for pypp-opengl 1.0.1a0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pypp-opengl 1.0.1a0
File Size Uploaded
pypp_opengl-1.0.1a0.tar.gz 6.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pypp-opengl 1.0.1a0
File Interpreter ABI Platform
pypp_opengl-1.0.1a0-py3-none-any.whl Python 3 none any Details

Total release size: 15.5 kB

Release files / pypp_opengl-1.0.1a0.tar.gz

Download URL pypp_opengl-1.0.1a0.tar.gz
Size 6.1 kB
Tags Source
SHA-256 checksum
How to use checksums
d3badaa5d9fb38af11d0b5f0a234b54a27454d2634e0ad58d4a1327fd7347003
BLAKE2b-256 checksum
How to use checksums
ce00b96a08626b4490b638a4ada2330be94704dfefb9fdabe07006fb3fda730c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.7

Release files / pypp_opengl-1.0.1a0-py3-none-any.whl

Download URL pypp_opengl-1.0.1a0-py3-none-any.whl
Size 9.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
546dda7a76397daa846f109eb53b5554f40df42584691c35220a3420a9ac3da6
BLAKE2b-256 checksum
How to use checksums
a3ac5c15530442f3bbef99c4dde8fabdd0a01b1d61a7ef4237f152ffe010e631
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.7

Release history Release notifications | RSS feed

This release

1.0.1a0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page