[Solved] Unable to draw triangle with OpenGL 3.3, SDL2 and Python. Invalid operation in glVertexAttribPointer

The program ends with an error: Invalid operation in glVertexAttribPointer

Log:

OpenGL Version: b'3.3.0 NVIDIA 391.35'
Traceback (most recent call last):
  File "E:\ProgramFiles\Python\Python38\lib\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 "E:\ProgramFiles\Python\Python38\lib\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 "main.py", line 106, in <module>
    main()
  File "main.py", line 91, in main
    glVertexAttribPointer(aPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, ctypes.c_void_p(0))
  File "E:\ProgramFiles\Python\Python38\lib\site-packages\OpenGL\latebind.py", line 47, in __call__
    return self._finalCall( *args, **named )
  File "E:\ProgramFiles\Python\Python38\lib\site-packages\OpenGL\latebind.py", line 63, in __call__
    return self.wrapperFunction( self.baseFunction, *args, **named )
  File "E:\ProgramFiles\Python\Python38\lib\site-packages\OpenGL\GL\VERSION\GL_2_0.py", line 470, in glVertexAttribPointer
    return baseOperation(
  File "E:\ProgramFiles\Python\Python38\lib\site-packages\OpenGL\latebind.py", line 47, in __call__
    return self._finalCall( *args, **named )
  File "E:\ProgramFiles\Python\Python38\lib\site-packages\OpenGL\wrapper.py", line 700, in wrapperCall
    raise err
  File "E:\ProgramFiles\Python\Python38\lib\site-packages\OpenGL\wrapper.py", line 693, in wrapperCall
    result = wrappedOperation( *cArguments )
  File "E:\ProgramFiles\Python\Python38\lib\site-packages\OpenGL\error.py", line 230, in glCheckError
    raise self._errorClass(
OpenGL.error.GLError: GLError(
        err = 1282,
        description = b'invalid operation',
        baseOperation = glVertexAttribPointer,
        pyArgs = (
                0,
                2,
                GL_FLOAT,
                GL_FALSE,
                0,
                c_void_p(None),
        ),
        cArgs = (
                0,
                2,
                GL_FLOAT,
                GL_FALSE,
                0,
                c_void_p(None),
        ),
        cArguments = (
                0,
                2,
                GL_FLOAT,
                GL_FALSE,
                0,
                c_void_p(None),
        )
)

main.py

import ctypes

import numpy as np
import pyrr
from OpenGL.GL import *
from OpenGL.GL.shaders import *
from sdl2 import *

window = None
maxFPS = 20

vertexShaderSource = """
    #version 330 core\n
    in vec2 aPosition;\n
    void main() {\n
        gl_Position = vec4(aPosition, 0.0, 1.0);\n
    }\n
"""

fragmentShaderSource = """
    #version 330 core\n
    out vec4 fragColor;\n
    void main() {\n
        fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n
    }\n
"""

def fatalError(message):
    print(message)
    if window:
        SDL_DestroyWindow(window)
    SDL_Quit()
    exit(-1)

def main():
    if SDL_Init(SDL_INIT_VIDEO) < 0:
        fatalError(SDL_GetError())

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3)
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3)
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
                        SDL_GL_CONTEXT_PROFILE_CORE)
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1)

    winW, winH = 250, 250
    window = SDL_CreateWindow(
        b"OpenGL1, SDL2, Python",
        SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
        winW, winH,
        SDL_WINDOW_OPENGL)
    if not window:
        fatalError(SDL_GetError())

    context = SDL_GL_CreateContext(window)
    if not context:
        fatalError(SDL_GetError())

    glClearColor(0.5, 0.5, 0, 1) # QColor(128, 128, 0)
    glViewport(0, 0, winW, winH)

    program = compileProgram(
        compileShader(vertexShaderSource, GL_VERTEX_SHADER),
        compileShader(fragmentShaderSource, GL_FRAGMENT_SHADER))
    glUseProgram(program)

    vertPositions = np.array([
        -0.5, -0.5,
        0.5, -0.5,
        0.0, 0.5
    ], dtype=np.float32)
    vertPosBuffer = glGenBuffers(1)
    glBindBuffer(GL_ARRAY_BUFFER, vertPosBuffer)
    glBufferData(GL_ARRAY_BUFFER, len(vertPositions) * 4,
        vertPositions, GL_STATIC_DRAW)
    aPositionLocation = glGetAttribLocation(program, "aPosition")

    print("OpenGL Version:", glGetString(GL_VERSION))

    event = SDL_Event()
    running = True
    while running:
        while SDL_PollEvent(ctypes.byref(event)) != 0:
            if event.type == SDL_QUIT:
                running = False
        startTicks = SDL_GetTicks()

        glClear(GL_COLOR_BUFFER_BIT);

        glUseProgram(program)
        glBindBuffer(GL_ARRAY_BUFFER, vertPosBuffer)
        glVertexAttribPointer(aPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, ctypes.c_void_p(0))
        glEnableVertexAttribArray(aPositionLocation)
        glDrawArrays(GL_TRIANGLES, 0, 3)

        SDL_GL_SwapWindow(window)

        # Limit the FPS to the max FPS
        frameTicks = SDL_GetTicks() - startTicks
        if 1000 / maxFPS > frameTicks:
            SDL_Delay(int(1000 / maxFPS - frameTicks))

    SDL_GL_DeleteContext(context)
    SDL_DestroyWindow(window)
    SDL_Quit()

main()

Solved:

Vertex_Array_Object

pip install pySDL2 PyOpenGL numpy pyrr

image

main.py

import ctypes

import numpy as np
import pyrr
from OpenGL.GL import *
from OpenGL.GL.shaders import *
from sdl2 import *

window = None
maxFPS = 20

vertexShaderSource = """
    #version 330 core\n
    in vec2 aPosition;\n
    void main() {\n
        gl_Position = vec4(aPosition, 0.0, 1.0);\n
    }\n
"""

fragmentShaderSource = """
    #version 330 core\n
    out vec4 fragColor;\n
    void main() {\n
        fragColor = vec4(0.2, 0.7, 0.3, 1.0);\n
    }\n
"""

def fatalError(message):
    print(message)
    if window:
        SDL_DestroyWindow(window)
    SDL_Quit()
    exit(-1)

def main():
    if SDL_Init(SDL_INIT_VIDEO) < 0:
        fatalError(SDL_GetError())

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3)
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3)
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
                        SDL_GL_CONTEXT_PROFILE_CORE)
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1)

    winW, winH = 300, 300
    window = SDL_CreateWindow(
        b"OpenGL1, SDL2, Python",
        SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
        winW, winH,
        SDL_WINDOW_OPENGL)
    if not window:
        fatalError(SDL_GetError())

    context = SDL_GL_CreateContext(window)
    if not context:
        fatalError(SDL_GetError())

    glClearColor(0.2, 0.2, 0.2, 1)
    glViewport(0, 0, winW, winH)

    program = compileProgram(
        compileShader(vertexShaderSource, GL_VERTEX_SHADER),
        compileShader(fragmentShaderSource, GL_FRAGMENT_SHADER))
    glUseProgram(program)

    vao = glGenVertexArrays(1)
    glBindVertexArray(vao)
    vertPositions = np.array([
        -0.5, -0.5,
        0.5, -0.5,
        0.0, 0.5
    ], dtype=np.float32)
    vertPosBuffer = glGenBuffers(1)
    glBindBuffer(GL_ARRAY_BUFFER, vertPosBuffer)
    glBufferData(GL_ARRAY_BUFFER, len(vertPositions) * 4,
        vertPositions, GL_STATIC_DRAW)
    aPositionLocation = glGetAttribLocation(program, "aPosition")
    glVertexAttribPointer(aPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, ctypes.c_void_p(0))
    glEnableVertexAttribArray(aPositionLocation)
    glBindBuffer(GL_ARRAY_BUFFER, 0)
    glBindVertexArray(0)

    print("OpenGL Version:", glGetString(GL_VERSION))

    event = SDL_Event()
    running = True
    while running:
        while SDL_PollEvent(ctypes.byref(event)) != 0:
            if event.type == SDL_QUIT:
                running = False
        startTicks = SDL_GetTicks()

        glClear(GL_COLOR_BUFFER_BIT);

        glBindVertexArray(vao)
        glDrawArrays(GL_TRIANGLES, 0, 3)

        SDL_GL_SwapWindow(window)

        # Limit the FPS to the max FPS
        frameTicks = SDL_GetTicks() - startTicks
        if 1000 / maxFPS > frameTicks:
            SDL_Delay(int(1000 / maxFPS - frameTicks))

    SDL_GL_DeleteContext(context)
    SDL_DestroyWindow(window)
    SDL_Quit()

main()

Example with OpenGL 3.0 and matrices without Core Profile and without VAO

Use ctypes.c_void_p here:

import ctypes

glVertexAttribPointer(aPositionLocation, 2, GL_FLOAT, GL_FALSE,
    0, ctypes.c_void_p(0))

image

main.py

import ctypes

import numpy as np
from OpenGL.GL import *
from OpenGL.GL.shaders import *
from pyrr import matrix44, vector3
from sdl2 import *

window = None
maxFPS = 20

vertexShaderSource = """
    #version 140\n
    in vec2 aPosition;\n
    uniform mat4 uMvpMatrix;\n
    void main() {\n
        gl_Position = uMvpMatrix * vec4(aPosition, 0.0, 1.0);\n
    }\n
"""

fragmentShaderSource = """
    #version 140\n
    uniform vec3 uColor;\n
    out vec4 fragColor;\n
    void main() {\n
        fragColor = vec4(uColor, 1.0);\n
    }\n
"""

def fatalError(message):
    print(message)
    if window:
        SDL_DestroyWindow(window)
    SDL_Quit()
    exit(-1)

def initVertexBuffers(program):
    vertPositions = np.array([
        0, 0,
        0, 1,
        1, 0,
        1, 1
    ], dtype=np.float32)
    vertPosBuffer = glGenBuffers(1)
    glBindBuffer(GL_ARRAY_BUFFER, vertPosBuffer)
    glBufferData(GL_ARRAY_BUFFER, len(vertPositions) * 4,
        vertPositions, GL_STATIC_DRAW)
    aPositionLocation = glGetAttribLocation(program, "aPosition")
    glVertexAttribPointer(aPositionLocation, 2, GL_FLOAT, GL_FALSE,
        0, ctypes.c_void_p(0))
    glEnableVertexAttribArray(aPositionLocation)

def main():
    if SDL_Init(SDL_INIT_VIDEO) < 0:
        fatalError(SDL_GetError())

    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1)

    winW, winH = 300, 300
    window = SDL_CreateWindow(
        b"OpenGL30, SDL2, Python",
        SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
        winW, winH,
        SDL_WINDOW_OPENGL)
    if not window:
        fatalError(SDL_GetError())

    context = SDL_GL_CreateContext(window)
    if not context:
        fatalError(SDL_GetError())

    glClearColor(0.5, 0.5, 0, 1) # QColor(128, 128, 0)
    glViewport(0, 0, winW, winH)

    program = compileProgram(
        compileShader(vertexShaderSource, GL_VERTEX_SHADER),
        compileShader(fragmentShaderSource, GL_FRAGMENT_SHADER))
    glUseProgram(program)
    initVertexBuffers(program)

    projMatrix = matrix44.create_orthogonal_projection(
        0, 200, 200, 0, 10, -10)
    viewMatrix = matrix44.create_look_at(
        eye=vector3.create(0, 0, 10),
        target=vector3.create(0, 0, 0),
        up=vector3.create(0, 1, 0))
    projViewMatrix = matrix44.multiply(viewMatrix, projMatrix)

    uColorLocation = glGetUniformLocation(program, "uColor")
    uMvpMatrixLocation = glGetUniformLocation(program, "uMvpMatrix")

    event = SDL_Event()
    running = True
    while running:
        while SDL_PollEvent(ctypes.byref(event)) != 0:
            if event.type == SDL_QUIT:
                running = False
        startTicks = SDL_GetTicks()

        glClear(GL_COLOR_BUFFER_BIT);

        translationMatrix = matrix44.create_from_translation(vector3.create(20, 20, 0))
        scaleMatrix = matrix44.create_from_scale(vector3.create(160, 60, 1))
        modelMatrix = matrix44.multiply(scaleMatrix, translationMatrix)
        mvpMatrix = matrix44.multiply(modelMatrix, projViewMatrix)
        glUniformMatrix4fv(uMvpMatrixLocation, 1, GL_FALSE, mvpMatrix)
        glUniform3fv(uColorLocation, 1, vector3.create(0.5, 0, 0))
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)

        SDL_GL_SwapWindow(window)

        # Limit the FPS to the max FPS
        frameTicks = SDL_GetTicks() - startTicks
        if 1000 / maxFPS > frameTicks:
            SDL_Delay(int(1000 / maxFPS - frameTicks))

    SDL_GL_DeleteContext(context)
    SDL_DestroyWindow(window)
    SDL_Quit()

main()