0
votes

Good afternoon, I'm studying OpenGL - the "red book". I'm trying to make the first example (draw two triangles):

# PyQT4 imports
from PyQt4 import QtGui, QtCore, QtOpenGL
from PyQt4.QtOpenGL import QGLWidget
# PyOpenGL imports
from OpenGL.GL import *
from OpenGL.GL.shaders import *

class GLPlotWidget(QGLWidget):
# default window size
width, height = 600, 600

def __init__(self, format = None):
    super(GLPlotWidget, self).__init__(format, None)

def set_data(self, data):
    self.data = data
    self.count = data.shape[0]
    self.numVAOs = 2
    self.VAOs = [0] * self.numVAOs
    self.numVBOs = 2
    self.VBOs = [0] * self.numVBOs
    self.shader = None
    self.vPositionLocation = 0

def initializeGL(self):
    glGenVertexArrays(self.numVAOs, self.VAOs)
    glBindVertexArray(self.VAOs[0])

    glGenBuffers(self.numVBOs, self.VBOs)
    glBindBuffer(GL_ARRAY_BUFFER, self.VBOs[0])
    glBufferData(GL_ARRAY_BUFFER, self.count, self.data, GL_STATIC_DRAW)

    VERTEX_SHADER = compileShader("""
        #version 410 core
        layout(location = 0) in vec4 vPosition;
        void main() {
            gl_Position = vPosition;
        }
    """, GL_VERTEX_SHADER)

    FRAGMENT_SHADER = compileShader("""
        #version 410 core
        out vec4 fColor;
        void main() {
            fColor = vec4(0.0, 0.0, 1.0, 1.0);
        }
    """, GL_FRAGMENT_SHADER)

    self.shader = compileProgram(VERTEX_SHADER, FRAGMENT_SHADER)
    glUseProgram(self.shader)

    glVertexAttribPointer(self.vPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, 0)
    glEnableVertexAttribArray(self.vPositionLocation)

def paintGL(self):
    glClear(GL_COLOR_BUFFER_BIT)

    glBindVertexArray(self.VAOs[0])
    glDrawArrays(GL_TRIANGLES, 0, self.count)

    glFlush()

def resizeGL(self, width, height):
    # update the window size
    self.width, self.height = width, height

    # paint within the whole window
    glViewport(0, 0, width, height)

    # set orthographic projection (2D only)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()

    # the window corner OpenGL coordinates are (-+1, -+1)
    glOrtho(-1, 1, -1, 1, -1, 1)

if __name__ == '__main__':
    # import numpy for generating random data points
    import sys
    import numpy as np
    import numpy.random as rnd

    # define a QT window with an OpenGL widget inside it
    class TestWindow(QtGui.QMainWindow):
        def __init__(self, parent = None):
            super(TestWindow, self).__init__(parent)

            # generate random data points
            self.data = np.array([
                [ -0.90, -0.90 ], [ 0.85, -0.90 ], [ -0.90, 0.85 ],
                [  0.90, -0.85 ], [ 0.90,  0.90 ], [ -0.85, 0.90 ]
            ], dtype = np.float32)

            # initialize the GL widget
            glformat = QtOpenGL.QGLFormat()
            glformat.setVersion(4, 1)
            glformat.setProfile(QtOpenGL.QGLFormat.CoreProfile)
            glformat.setSampleBuffers( True )
            QtOpenGL.QGLFormat.setDefaultFormat(glformat)
            self.widget = GLPlotWidget(glformat)
            self.widget.set_data(self.data)

            # put the window at the screen position (100, 100)
            self.setGeometry(100, 100, self.widget.width, self.widget.height)
            self.setCentralWidget(self.widget)
            self.show()

    # create the QT App and window
    app = QtGui.QApplication(sys.argv)
    glutInitDisplayMode(GLUT_RGBA or GLUT_3_2_CORE_PROFILE)
    window = TestWindow()
    window.show()
    app.exec_()

And I get this errors:

OpenGL.error.NullFunctionError: Attempt to call an undefined function glGenVertexArrays, check for bool(glGenVertexArrays) before calling
OpenGL.error.NullFunctionError: Attempt to call an undefined function glBindVertexArray, check for bool(glBindVertexArray) before calling
OpenGL.error.NullFunctionError: Attempt to call an undefined function glBindVertexArray, check for bool(glBindVertexArray) before calling

I found out that I have to enable GL core profile, but even after I enabled it, it's not working...

# initialize the GL widget
glformat = QtOpenGL.QGLFormat()
glformat.setVersion(4, 1)
glformat.setProfile(QtOpenGL.QGLFormat.CoreProfile)
glformat.setSampleBuffers( True )
QtOpenGL.QGLFormat.setDefaultFormat(glformat)

At the same time if I use VBO from OpenGL.arrays.vbo it works fine.

How can I solve this problem? Where am I wrong?

Addition: I'm using Mac OS X 10.9.4, iMac with NVIDIA GeForce GTX 660M 512 MB (OpenGL 4.1 support and GLSL 4.1.0)

1
This sounds very much like you don't have a proper OpenGL driver installed on your system. In Windows the default drivers and those installed through the Windows Update mechanism are stripped of their OpenGL support and there's only a software fallback for OpenGL-1.4. The first thing you should do is visit your GPU vendors website, download the latest drivers for your GPU from there and install those.datenwolf
Made an addition to the questionEugene Kolesnikov

1 Answers

-1
votes

Moving from PyQt4 to PyQt5 solves the problem

Full source code:

# PyQT5 imports
from PyQt5 import QtGui, QtCore, QtOpenGL, QtWidgets
from PyQt5.QtOpenGL import QGLWidget
from ctypes import *
# PyOpenGL imports
from OpenGL.GL import *
from OpenGL.GL.shaders import *
from OpenGL.GLUT import *

class GLPlotWidget(QGLWidget):
    # default window size
    width, height = 600, 600

    def __init__(self, format = None):
        super(GLPlotWidget, self).__init__(format, None)

    def set_data(self, data):
        self.data = data
        self.count = self.data.nbytes
        self.numVAOs = 2
        self.VAOs = [0] * self.numVAOs
        self.numVBOs = 2
        self.VBOs = [0] * self.numVBOs
        self.shader = None
        self.vPositionLocation = 0

    def initializeGL(self):

        glClearColor(0.0, 0.0, 0.0, 1.0)

        self.VAOs = glGenVertexArrays(self.numVAOs)
        glBindVertexArray(self.VAOs[0])

        self.VBOs = glGenBuffers(self.numVBOs)
        glBindBuffer(GL_ARRAY_BUFFER, self.VBOs[0])
        glBufferData(GL_ARRAY_BUFFER, self.count, self.data, GL_STATIC_DRAW)

        VERTEX_SHADER = compileShader("""
            #version 410 core
            layout(location = 0) in vec4 vPosition;
            void main() {
                gl_Position = vPosition;
            }
        """, GL_VERTEX_SHADER)

        FRAGMENT_SHADER = compileShader("""
            #version 410 core
            out vec4 fColor;
            void main() {
                fColor = vec4(1.0, 1.0, 0.0, 1.0);
            }
        """, GL_FRAGMENT_SHADER)

        self.shader = compileProgram(VERTEX_SHADER, FRAGMENT_SHADER)
        glUseProgram(self.shader)

        glVertexAttribPointer(self.vPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, c_void_p(0))
        glEnableVertexAttribArray(self.vPositionLocation)

    def paintGL(self):
        glClear(GL_COLOR_BUFFER_BIT)

        glBindVertexArray(self.VAOs[0])
        glDrawArrays(GL_TRIANGLES, 0, self.count)

        glFlush()

if __name__ == '__main__':
    # import numpy for generating random data points
    import sys
    import numpy as np
    import numpy.random as rnd

    # define a QT window with an OpenGL widget inside it
    class TestWindow(QtWidgets.QMainWindow):
        def __init__(self, parent = None):
            super(TestWindow, self).__init__(parent)
            self.data = np.array([
                [ -0.90, -0.90 ],
                [  0.85, -0.90 ],
                [ -0.90,  0.85 ],
                [  0.90, -0.85 ],
                [  0.90,  0.90 ],
                [ -0.85,  0.90 ]
            ], dtype = np.float32)
            # initialize the GL widget
            glformat = QtOpenGL.QGLFormat()
            glformat.setVersion(4, 1)
            glformat.setProfile(QtOpenGL.QGLFormat.CoreProfile)
            glformat.setSampleBuffers( True )
            self.widget = GLPlotWidget(glformat)
            self.widget.set_data(self.data)
            # put the window at the screen position (100, 100)
            self.setGeometry(100, 100, self.widget.width, self.widget.height)
            self.setCentralWidget(self.widget)
            self.show()

    # create the QT App and window
    app = QtWidgets.QApplication(sys.argv)
    window = TestWindow()
    window.show()
    app.exec_()