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...