[Python] Pyopengl program throws "Attempt to retrieve context when no valid context"

Discussão em 'Python' iniciado por Stack, Julho 4, 2025.

  1. Stack

    Stack Membro Participativo

    I'm attempting to make a rudimentary real time Rasterizing engine in Python. My program was working fine until I realized that my VBOs didn't seem to be working, and changed vertex, texture and normal coordinates to None. I'm on linux and I'm mostly in over my head with this, I'm brand new to opengl. Error:

    File "/home/calcyte/.local/lib/python3.13/site-packages/OpenGL/latebind.py", line 43, in __call__
    return self._finalCall( *args, **named )
    ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^
    TypeError: 'NoneType' object is not callable

    During handling of the above exception, another exception occurred:

    Traceback (most recent call last):
    File "/home/calcyte/OneDrive_171848@lrgs.org.uk/compsci/Practical/Proj/ras1/ras1.py", line 248, in <module>
    main()
    ~~~~^^
    File "/home/calcyte/OneDrive_171848@lrgs.org.uk/compsci/Practical/Proj/ras1/ras1.py", line 242, in main
    render_vbo(vbo_obj)
    ~~~~~~~~~~^^^^^^^^^
    File "/home/calcyte/OneDrive_171848@lrgs.org.uk/compsci/Practical/Proj/ras1/ras1.py", line 181, in render_vbo
    glVertexPointer(3, GL_FLOAT, 0, None)
    ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
    File "/home/calcyte/.local/lib/python3.13/site-packages/OpenGL/latebind.py", line 47, in __call__
    return self._finalCall( *args, **named )
    ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^
    File "/home/calcyte/.local/lib/python3.13/site-packages/OpenGL/wrapper.py", line 923, in wrapperCall
    storeValues(
    ~~~~~~~~~~~^
    result,
    ^^^^^^^
    ...<2 lines>...
    cArguments,
    ^^^^^^^^^^^
    )
    ^
    File "/home/calcyte/.local/lib/python3.13/site-packages/OpenGL/arrays/arrayhelpers.py", line 189, in __call__
    contextdata.setValue(self.constant, pyArgs[self.pointerIndex])
    ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/home/calcyte/.local/lib/python3.13/site-packages/OpenGL/contextdata.py", line 58, in setValue
    context = getContext( context )
    File "/home/calcyte/.local/lib/python3.13/site-packages/OpenGL/contextdata.py", line 40, in getContext
    raise error.Error(
    """Attempt to retrieve context when no valid context"""
    )
    OpenGL.error.Error: Attempt to retrieve context when no valid context


    Code:

    import pygame
    from pygame.locals import *
    import numpy as np
    import os

    # OpenGL imports needed for VBO and rendering
    from OpenGL.GL import *
    from OpenGL.GLU import *

    def load_texture(filename):
    path = "/home/calcyte/OneDrive_171848@lrgs.org.uk/compsci/Practical/Proj/assets/bucket/" + filename
    if not os.path.exists(path):
    print(f"Texture file {filename} not found in the specified directory.")
    return None
    surface = pygame.image.load(path)
    width, height = surface.get_size()
    image_data = pygame.image.tostring(surface, "RGBA", True)
    texid = glGenTextures(1)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data)
    glGenerateMipmap(GL_TEXTURE_2D)
    return texid


    def collect_objvert(reqass="untitled"):
    filepath = f"/home/calcyte/OneDrive_171848@lrgs.org.uk/compsci/Practical/Proj/assets/{reqass}.obj"
    faces = []
    objverts = []
    mtllis = []
    mat = None
    texturecoords = []
    normals = []

    def new_material(name):
    return [name, [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], 1.0, 1.0, 1.0, 1, None, None, [None, None, None]]

    with open(filepath, "r") as assfil:
    for line in assfil:
    if line.startswith("mtllib "):
    line = line.strip()
    mtllib = open(f"/home/calcyte/OneDrive_171848@lrgs.org.uk/compsci/Practical/Proj/assets/{line[7:]}", "r")
    for mline in mtllib:
    if mline.startswith("newmtl "):
    mtllis.append(new_material(mline[7:].strip()))
    elif mline.startswith("Ka "):
    tmp = [float(x) for x in mline[3:].split()]
    mtllis[-1][1] = tmp
    elif mline.startswith("Kd "):
    tmp = [float(x) for x in mline[3:].split()]
    mtllis[-1][2] = tmp
    elif mline.startswith("Ks "):
    tmp = [float(x) for x in mline[3:].split()]
    mtllis[-1][3] = tmp
    elif mline.startswith("d "):
    mtllis[-1][4] = float(mline[2:].strip())
    elif mline.startswith("Tr "):
    mtllis[-1][5] = float(mline[3:].strip())
    elif mline.startswith("Ns "):
    ns_val = float(mline[3:].strip())
    mtllis[-1][6] = min(ns_val, 128.0)
    elif mline.startswith("illum "):
    mtllis[-1][7] = int(mline[6:].strip())
    elif mline.startswith("map_Kd "):
    mtllis[-1][8] = load_texture(mline[7:].strip()) if mline[7:].strip() != "" else 0
    mtllib.close()
    if line.startswith("usemtl "):
    if mat is not None and faces:
    mtllis[mat][9] = faces
    mat = None
    mat_name = line[7:].strip()
    for i, m in enumerate(mtllis):
    if m[0] == mat_name:
    mat = i
    faces = []
    if line.startswith("vt "):
    parts = [float(x) for x in line[3:].split()]
    parts[0] = min(max(parts[0], 0), 1)
    parts[1] = min(max(parts[1], 0), 1)
    texturecoords.append(parts)
    if line.startswith("vn "):
    parts = [float(x) for x in line[3:].split()]
    normals.append(parts)
    if line.startswith("v "):
    parts = [float(x) for x in line[2:].split()]
    objverts.append(parts)
    if line.startswith("f "):
    parts = line[2:].strip().split()
    if parts:
    face = []
    for p in parts:
    indices = p.split("/")
    vert_idx = int(indices[0]) - 1 if len(indices) > 0 and indices[0] != '' else None
    tex_idx = int(indices[1]) - 1 if len(indices) > 1 and indices[1] != '' else None
    norm_idx = int(indices[2]) - 1 if len(indices) > 2 and indices[2] != '' else None
    face.append([vert_idx, tex_idx, norm_idx])
    if len(face) > 3:
    for i in range(1, len(face) - 1):
    faces.append([face[0], face, face[i + 1]])
    else:
    faces.append(face)
    if mat is not None and faces:
    mtllis[mat][9] = faces
    return mtllis, objverts, texturecoords, normals


    def setup_vbo(mtllis, verts, texcoo, norms):
    for materials in mtllis:
    if materials[9] is None or len(materials[9]) == 0:
    continue
    texcor = []
    triangle = []
    norm = []
    # Ensure material colors are in the correct format
    if len(materials[1]) != 4:
    materials[1].append(float(materials[4]))
    materials[2].append(float(materials[4]))
    materials[3].append(float(materials[4]))

    for face in materials[9]:
    if len(face) == 3:
    sad = []
    texsad = []
    norsad = []
    for v in face:
    v_idx = v[0] if v[0] is not None else 0
    if texcoo and v[1] is not None and v[1] < len(texcoo):
    texsad.append(texcoo[v[1]])
    else:
    texsad.append([0.0, 0.0])
    if norms and v[2] is not None and v[2] < len(norms):
    norsad.append(norms[v[2]])
    else:
    norsad.append([0.0, 0.0, 1.0])
    sad.append(verts[v_idx])
    triangle.extend(sad)
    texcor.extend(texsad)
    norm.extend(norsad)

    # Create and bind VBOs for vertices, texture coordinates, and normals
    triangle_array = np.array(triangle, dtype=np.float32)
    texture_array = np.array(texcor, dtype=np.float32)
    normal_array = np.array(norm, dtype=np.float32)

    # Generate VBOs
    materials[10] = [None, None, None] # Reset VBO storage
    materials[10][0] = glGenBuffers(1) # Vertex VBO
    materials[10][1] = glGenBuffers(1) # Texture VBO
    materials[10][2] = glGenBuffers(1) # Normal VBO

    # Bind and upload vertex data
    glBindBuffer(GL_ARRAY_BUFFER, materials[10][0])
    glBufferData(GL_ARRAY_BUFFER, triangle_array.nbytes, triangle_array, GL_STATIC_DRAW)

    # Bind and upload texture data
    glBindBuffer(GL_ARRAY_BUFFER, materials[10][1])
    glBufferData(GL_ARRAY_BUFFER, texture_array.nbytes, texture_array, GL_STATIC_DRAW)

    # Bind and upload normal data
    glBindBuffer(GL_ARRAY_BUFFER, materials[10][2])
    glBufferData(GL_ARRAY_BUFFER, normal_array.nbytes, normal_array, GL_STATIC_DRAW)

    # Unbind the buffers
    glBindBuffer(GL_ARRAY_BUFFER, 0)

    return mtllis


    def render_vbo(mtllis):
    for materials in mtllis:
    if materials[10][0] is not None:
    # Set material properties
    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, materials[1])
    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, materials[2])
    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, materials[3])
    glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, materials[6])

    # Bind vertex VBO
    glEnableClientState(GL_VERTEX_ARRAY)
    glBindBuffer(GL_ARRAY_BUFFER, materials[10][0])
    glVertexPointer(3, GL_FLOAT, 0, None)

    # Bind texture VBO if it exists and texture is available
    if materials[10][1] is not None and materials[8]:
    glEnableClientState(GL_TEXTURE_COORD_ARRAY)
    glBindTexture(GL_TEXTURE_2D, materials[8]) # Bind the texture
    glBindBuffer(GL_ARRAY_BUFFER, materials[10][1]) # Bind texture VBO
    glTexCoordPointer(2, GL_FLOAT, 0, None)

    # Bind normal VBO if it exists
    if materials[10][2] is not None:
    glEnableClientState(GL_NORMAL_ARRAY)
    glBindBuffer(GL_ARRAY_BUFFER, materials[10][2]) # Bind normal VBO
    glNormalPointer(GL_FLOAT, 0, None)

    # Draw the arrays
    glDrawArrays(GL_TRIANGLES, 0, len(materials[10][0]) // 3) # Assuming each vertex has 3 components

    # Unbind and disable states
    if materials[10][2] is not None:
    glDisableClientState(GL_NORMAL_ARRAY)
    glBindBuffer(GL_ARRAY_BUFFER, 0) # Unbind normal VBO

    if materials[10][1] is not None and materials[8]:
    glDisableClientState(GL_TEXTURE_COORD_ARRAY)
    glBindBuffer(GL_ARRAY_BUFFER, 0) # Unbind texture VBO

    glDisableClientState(GL_VERTEX_ARRAY)
    glBindBuffer(GL_ARRAY_BUFFER, 0) # Unbind vertex VBO


    def main():
    pygame.init()
    displayinfo = pygame.display.Info()
    pygame.display.set_mode((displayinfo.current_w, displayinfo.current_h), DOUBLEBUF | OPENGL)
    pygame.display.set_caption("RAS1")

    gluPerspective(45, (displayinfo.current_w / displayinfo.current_h), 0.1, 100000)
    loc = [20, 40, 0]
    gluLookAt(loc[0], loc[1], loc[2], 0, 0, 0, 0, 1, 0)
    mtllis, vertices, texcoo, normals = collect_objvert()
    vbo_obj = setup_vbo(mtllis, vertices, texcoo, normals)
    clock = pygame.time.Clock()
    glClearColor(0.2, 0.2, 0.3, 1.0)
    glEnable(GL_DEPTH_TEST)
    glEnable(GL_LIGHTING)
    glEnable(GL_LIGHT0)
    glLightfv(GL_LIGHT0, GL_POSITION, (0, 20, 40, 0))
    glLightfv(GL_LIGHT0, GL_AMBIENT, (0.2, 0.2, 0.2, 1.0))
    glLightfv(GL_LIGHT0, GL_DIFFUSE, (0.7, 0.7, 0.7, 1.0))
    glLightfv(GL_LIGHT0, GL_SPECULAR, (1.0, 1.0, 1.0, 1.0))
    glEnable(GL_NORMALIZE)
    glShadeModel(GL_SMOOTH)
    glEnable(GL_TEXTURE_2D)
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)
    while True:
    for event in pygame.event.get():
    if event.type == pygame.QUIT:
    pygame.quit()
    quit()
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    render_vbo(vbo_obj)
    glRotatef(1, 0, 1, 0)
    pygame.display.flip()
    clock.tick(60)


    main()

    Continue reading...

Compartilhe esta Página