Search code examples
pythonpointersopenglpyopengl

How to extract data for glVertexPointer() and glColorPointer() from a single array in PyOpenGL?


I'm starting to learn PyOpenGL, and I'm following this tutorial. At one point the instructor creates a single array from which he extracts the information to construct a triangle: vetices and their color (I added the Numpy line here):

#-----------|-Vertices pos--|---Colors----|-----------
vertices = [-0.5, -0.5, 0.0, 1.0, 0.0, 0.0,
             0.5, -0.5, 0.0, 0.0, 1.0, 0.0,
             0.0,  0.5, 0.0, 0.0, 0.0, 1.0]

vertices = np.array(vertices, dtype = np.float32)

The information of this array is passed to glVertexPointer() and glColorPointer() in the display function:

def display():

    glClear(GL_COLOR_BUFFER_BIT)      
    glEnableClientState(GL_VERTEX_ARRAY)
    glEnableClientState(GL_COLOR_ARRAY)

    glVertexPointer(3, GL_FLOAT, 12, vertices)
    glColorPointer(3, GLFLOAT, 12, vertices + 3)

    glDrawArrays(GL_TRIANGLES, 0, 3)

    glDisableClientState(GL_VERTEX_ARRAY)
    glDisableClientState(GL_COLOR_ARRAY)
    glutSwapBuffers()

My problem is with the last argument of those functions, in the tutorial (since he is using C++), he can write vertices + 3 in order to tell the program to start reading from the third position of the array, I cannot do this in python. Can some one guide me on how can I define this pointer? Or how can extract the information from my array.

Note: I'm aware that I can split the information of vertices and colors in differnt arrays, but I want to know if it is possible to do it using one array.

EDIT - Adding the complete code:

from OpenGL.GL import *
from OpenGL.GLUT import *
import numpy as np
import ctypes

#-----------|-Vertices pos--|---Colors----|-----------
vertices = [-0.5, -0.5, 0.0, 1.0, 0.0, 0.0,
             0.5, -0.5, 0.0, 0.0, 1.0, 0.0,
             0.0,  0.5, 0.0, 0.0, 0.0, 1.0]
vertices = np.array(vertices, dtype = np.float32)

buffer_offset = ctypes.c_void_p
float_size = ctypes.sizeof(ctypes.c_float)

#-----------------------------------------------------

def display():

    glClear(GL_COLOR_BUFFER_BIT)      
    glEnableClientState(GL_VERTEX_ARRAY)
    glEnableClientState(GL_COLOR_ARRAY)

    glVertexPointer(3, GL_FLOAT, 24, buffer_offset(vertices.ctypes.data))
    glColorPointer(3, GL_FLOAT, 24, buffer_offset(vertices.ctypes.data + float_size * 3))

    glDrawArrays(GL_TRIANGLES, 0, 3)

    glDisableClientState(GL_VERTEX_ARRAY)
    glDisableClientState(GL_COLOR_ARRAY)
    glutSwapBuffers()

def reshape(w,h):
    glViewport(0,0,w,h)

def initOpenGL():
    glClearColor(0,0,0,1)

#-----------------------------------------------------

glutInit()
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH)
glutInitWindowSize(500,500)
glutCreateWindow(b'Test')

glutDisplayFunc(display)
glutIdleFunc(display)
glutReshapeFunc(reshape)

initOpenGL()
glutMainLoop()

Solution

  • This depends on whether you have a vertex buffer bound or not. The last parameter pointer in gl*Pointer() is either.

    • No Vertex Buffer Bound: It's the address to the vertices
    • Vertex Buffer Bound: It's a relative offset in relation to the address of the buffer

    You can utilize ctypes for this.

    import ctypes
    
    buffer_offset = ctypes.c_void_p
    float_size = ctypes.sizeof(ctypes.c_float)
    

    Assuming you have a vertex buffer bound, then you'd simply do:

    glVertexPointer(3, GL_FLOAT, 12, buffer_offset(0))
    glColorPointer(3, GLFLOAT, 12, buffer_offset(float_size * 3))
    

    If you are just using that array and nothing else, then I would assume you could just get the address and equally offset it.

    glVertexPointer(3, GL_FLOAT, 12, buffer_offset(vertices.ctypes.data))
    glColorPointer(3, GLFLOAT, 12, buffer_offset(vertices.ctypes.data + float_size * 3))
    

    But I have to admit, I've never had the need for this in Python, so I can't confirm it.