2

I am building an application using PyOpenGL and PyQt5 on Python3.5.2

The purpose of the application is to setup a window with QGLWidget class and draw a sphere using glutWireSphere function. The code works fine on my Ubuntu Linux 16.04 LTS laptop but it crashes on my Windows 7 desktop with OSError: exception: access violation reading 0x00000000000000C1 in the line of glutWireSphere. If I comment out this line, the program executes normally. I tried a different code example (sample below) that demonstrates how to draw a sphere with glut and it did not crushed, but it manages the windowing with glut.

My Code:

from OpenGL.GLUT import *
from OpenGL.GLU import *
from OpenGL.GL import *
from PyQt5.QtOpenGL import *
from PyQt5 import QtGui
from PyQt5 import QtWidgets
from PyQt5 import QtCore


class MyWidget(QGLWidget):

    def __init__(self, parent = None):
        super(MyWidget, self).__init__(parent)

        self.cameraDistanceZ = 10

    def paintGL(self):
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glColor3f(0.33, 0.33, 0.33)
        glutSolidSphere(1, 20, 20)


    def resizeGL(self, w, h):
        glViewport(0, 0, w, h)
        self.setOrthoProjection()
        self.screenCenterX = w/2
        self.screenCenterY = h/2

    def setOrthoProjection(self):
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        w = self.width()
        h = self.height()
        glOrtho(-10, 10, -10, 10, -5.0, 15.0)
        gluLookAt(0,0,self.cameraDistanceZ, 0,0, -10, 0,1,0)

    def initializeGL(self):
        print("Start init process")
        glutInit(sys.argv)
        glClearColor(0.0, 0.0, 0.1, 0.0)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glClearDepth(1.0)

        self.updateGL()


def main():
    app = QtWidgets.QApplication(["To parathyro"])
    widget = MyWidget()
    widget.show()
    sys.exit(app.exec_())
if __name__ == '__main__':
    main()

Working example:

from OpenGL.GLUT import *
from OpenGL.GLU import *
from OpenGL.GL import *
import sys


def main():
    glutInit(sys.argv)
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)
    glutInitWindowSize(400,400)
    glutCreateWindow(b"myWindow")

    glClearColor(0.,0.,0.,1.)
    glShadeModel(GL_SMOOTH)
    glEnable(GL_CULL_FACE)
    glEnable(GL_DEPTH_TEST)
    glEnable(GL_LIGHTING)
    lightZeroPosition = [10.,4.,10.,1.]
    lightZeroColor = [0.8,1.0,0.8,1.0] #green tinged
    glLightfv(GL_LIGHT0, GL_POSITION, lightZeroPosition)
    glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor)
    glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.1)
    glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.05)
    glEnable(GL_LIGHT0)
    glutDisplayFunc(display)
    glMatrixMode(GL_PROJECTION)
    gluPerspective(40.,1.,1.,40.)
    glMatrixMode(GL_MODELVIEW)
    gluLookAt(0,0,10,
              0,0,0,
              0,1,0)
    glPushMatrix()
    glutMainLoop()
    return

def display():
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
    glPushMatrix()
    color = [1.0,0.,0.,1.]
    glMaterialfv(GL_FRONT,GL_DIFFUSE,color)
    glutWireSphere(1,20,20)
    glPopMatrix()
    glutSwapBuffers()
    return

if __name__ == '__main__': main()

If i try to draw something else, for example glutSolidSphere I get the same error but on a different address. All access violation errors I have found online are application specific and they are mostly related to wrong input type in some function. There is not much room for such a mistake in my application since functions in my code do not take many arguments, or there is something that I have not noticed yet.

For my Windows 7 desktop system I downloaded Python 3.5.2 from the official website, I installed PyQt5 using pip and PyOpenGL through the Unofficial Windows Binaries for Python Extension Packages according to these instructions

I thought it was something related to problems in the freeglut library but it works on a different example. I guess it has something to do with how I initialize freeglut in my application, or it is related to PyQT5

Question

How can I track the problem and solve it without moving to different architecture for my application?

Boombastic
  • 23
  • 6
  • Any recommendations on how to make this question more clear? – Boombastic Mar 02 '18 at 08:28
  • I don't know the solution, but I was able to reproduce your exact same problem with PyQt5 and glut on Py 3 (so, it's probably something related to that toolchain). – Fabio Zadrozny Mar 13 '18 at 19:15
  • I guess it is something related to how PyQt5 sets up glut, or there is some sort of memory mismanagement between the two. I read on the Qt documentation that QGL widget is depreciated and QOpenGLWidget should be used instead, but the results are the same. – Boombastic Mar 14 '18 at 01:37
  • Yes... personally, I'll try to not use glut (the hassle of the dependency is not worth it for me, but I'm sure that if you compile freeglut in debug mode and step in a debugger you'd be able to diagnose the problem). – Fabio Zadrozny Mar 14 '18 at 11:31
  • I run my program in debug mode, and the problem is in a freeglut.dll, a relative jump in the assembly code. But how to proceed from there? Or you mean something else? – Boombastic Mar 18 '18 at 20:40
  • I mean getting the freeglut sources, compiling locally and fixing it (you could also try asking the freeglut maintainers, but as the last release is from 2015, it may not really be active). Probably some place inside: https://github.com/dcnieho/FreeGLUT/blob/c59188a9a8d14efbeed7b0d6feacae7b04d7ad69/freeglut/freeglut/src/fg_geometry.c#L1604 (or who knows, maybe the master version has that fixed and they just didn't release it yet). – Fabio Zadrozny Mar 19 '18 at 14:23

1 Answers1

0

It seems the crash occurs because glutWireSphere requires you to call first glutCreateWindow, check this little snippet for example:

from OpenGL.GLUT import *
from OpenGL.GLU import *
from OpenGL.GL import *

from PyQt5.Qt import *  # noqa


class MyWidget(QGLWidget):

    def __init__(self, parent=None):
        super().__init__(parent)

    def paintGL(self):
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        glPushMatrix()
        color = [1.0, 0., 0., 1.]
        glMaterialfv(GL_FRONT, GL_DIFFUSE, color)
        glutWireSphere(1, 20, 20)
        glPopMatrix()
        glutSwapBuffers()

    def glutInitialization(self):
        glutInit(sys.argv)
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)
        glutInitWindowSize(400, 400)
        glutCreateWindow(b"Glut Window")

    def initializeGL(self):
        glClearColor(0., 0., 0., 1.)
        glShadeModel(GL_SMOOTH)
        glEnable(GL_CULL_FACE)
        glEnable(GL_DEPTH_TEST)
        glEnable(GL_LIGHTING)
        lightZeroPosition = [10., 4., 10., 1.]
        lightZeroColor = [0.8, 1.0, 0.8, 1.0]  # green tinged
        glLightfv(GL_LIGHT0, GL_POSITION, lightZeroPosition)
        glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor)
        glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.1)
        glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.05)
        glEnable(GL_LIGHT0)
        glMatrixMode(GL_PROJECTION)
        gluPerspective(40., 1., 1., 40.)
        glMatrixMode(GL_MODELVIEW)
        gluLookAt(0, 0, 10,
                  0, 0, 0,
                  0, 1, 0)
        glPushMatrix()

        self.glutInitialization()


def main():
    app = QApplication(["To parathyro"])
    widget = MyWidget()
    widget.setWindowTitle("Pyqt Widget")
    widget.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

You can see how the sphere will appear in the pyqt window (active gl context). Then, comment glutCreateWindow(b"Glut Window") and run it again, so you'll see the seg fault crash will appear back.

My suggestion? I wouldn't rely on glut geometric function when not using Glut as the opengl window management system.

Btw, generating a sphere isn't hard at all and is worth you give it a shot :)

BPL
  • 9,632
  • 9
  • 59
  • 117