2

I want to call glDrawElements on the same element buffer object more than once, where each draw call accesses different parts of the element buffer object. So, out of many ways possible, in C/C++, one of them was to set the void * indices argument. I tried a similar thing in PyQt5 using QOpenGLWidget, but I get the error

Traceback (most recent call last):
  File "path/to/dir/scratch.py", line 305, in paintGL
    self.renderer.draw(self.m_gl)
  File "path/to/dir/scratch.py", line 257, in draw
    obj.drawCall(gl)
  File "path/to/dir/scratch.py", line 217, in drawCall
    gl.glDrawElements(gl.GL_TRIANGLES, 3, self.idxdtype, 2) # tri2.
TypeError: glDrawElements(self, int, int, int, PYQT_OPENGL_ARRAY): array must be a sequence or a buffer

What does the type PYQT_OPENGL_ARRAY mean? I cannot seem to find any hints here or on SO. Whereas this post looks like a possible duplicate, the question firstly refers to PyOpenGL and besides the suggested answer ctypes.c_void_p(int) gives the error

Traceback (most recent call last):
  File "path/to/dir/scratch.py", line 305, in paintGL
    self.renderer.draw(self.m_gl)
  File "path/to/dir/scratch.py", line 257, in draw
    obj.drawCall(gl)
  File "path/to/dir/scratch.py", line 217, in drawCall
    gl.glDrawElements(gl.GL_TRIANGLES, 3, self.idxdtype, ctypes.c_void_p(2)) # tri2.
TypeError: a 1-dimensional buffer is required

The draw call looks like this. I am aware that I can directly use the entire element buffer to draw the two triangles, but I want to be able to use this functionality of void * indices

    def drawCall(self, gl):
        self.shaderProgram.bind()
        self.vao.bind()
        self.shaderProgram.setUniformValue(self.u_ColorIdx, self.color)
        self.shaderProgram.setUniformValue(self.u_MVPidx, self.mvpMatrix)

        # tri1 would be in the y-ve region and colored red.
        gl.glDrawElements(gl.GL_TRIANGLES, 3, self.idxdtype, None) # tri1
        # tri2 would be in the y+ve region and colored green.
        self.shaderProgram.setUniformValue(self.u_ColorIdx, QtGui.QVector4D(0.0, 0.7, 0.3, 1.0))
        gl.glDrawElements(gl.GL_TRIANGLES, 3, self.idxdtype, ctypes.c_void_p(2)) # tri2.

        # I am aware that I might as well rotate tri1 by 180 degrees around z-axis, 
        # and set u_color uniform value to green to achieve the desired effect. But I want
        # to do it using indices. It seems better for a large number of objects.

        self.shaderProgram.release()
        self.vao.release()

Finally, a link to the entire example code.

Edit: I am not looking for answers that suggest the usage of PyOpenGL/ModernGL to set the buffer objects.

Jaswant P
  • 83
  • 1
  • 8
  • There seems to be a difference between *PyQt5* and [*PyOpenGL*](http://pyopengl.sourceforge.net/). The code works when using *PyOpenGL* (it can be used additionally to *PyQt5*) – Rabbid76 Apr 06 '20 at 07:59
  • So, that's the only alternative? It's surprising. I wanted to use PyQt5's OpenGL bindings to avoid a context mess. Is it the way to go? – Jaswant P Apr 06 '20 at 17:34
  • I don't know. In my opinion you should never use OpenGL instructions directly in Qt. e.g. use `QOpenGLBuffer.VertexBuffer`. Anyway, `PYQT_OPENGL_ARRAY` is defines as `PYQT_OPENGL_ARRAY = typing.Union[typing.Sequence[int], typing.Sequence[float], sip.Buffer, None]`. See [pyqt/python-qt5](https://github.com/pyqt/python-qt5/blob/master/PyQt5/Qsci.pyi) – Rabbid76 Apr 06 '20 at 17:41
  • 1
    Thanks for pointing me to that. I searched a lot and could not find it, perhaps I just didn't know where to look. I tried `gl.glDrawElements(gl.GL_TRIANGLES, 3, self.idxdtype, [3])` but that doesn't help. As far as `sip.Buffer`, I couldn't find any documentation that explains its usage. I hold the same opinion and do not want to mix another OpenGL library's calls within Qt, hence trying to stay away from doing that. – Jaswant P Apr 06 '20 at 18:09
  • It would help if anyone can explain the usage of `PYQT_OPENGL_ARRAY` or `sip.Buffer`. I am absolutely clueless about this. – Jaswant P Apr 06 '20 at 22:52

1 Answers1

0

I had the same problem and finally found a solution using numpy.ndarray.tolist().

glf.glTexImage2D(glf.GL_TEXTURE_2D, 0, glf.GL_DEPTH_COMPONENT, self._images[i].shape[1], self._images[i].shape[0], 0, glf.GL_DEPTH_COMPONENT, glf.GL_FLOAT, self._images[i].flatten().tolist())

hmj
  • 39
  • 3