Advertisement
Guest User

Untitled

a guest
Jan 17th, 2017
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.48 KB | None | 0 0
  1. glcontext=None
  2.  
  3. if (VideoImageWidget.glcontext==None):
  4. print("VideoImageWidget: initializeGL: creating context for sharing")
  5. VideoImageWidget.glcontext=QtGui.QOpenGLContext()
  6. ok=VideoImageWidget.glcontext.create()
  7. print("VideoImageWidget: initializeGL: created context for sharing",VideoImageWidget.glcontext,ok)
  8.  
  9. context=self.context()
  10. print("VideoImageWidget: initializeGL: automatically created context:",context)
  11. context.setShareContext(VideoImageWidget.glcontext)
  12. ok=context.create() # must call this ..
  13. print("VideoImageWidget: initializeGL: recreated my context:",ok)
  14.  
  15. import sys
  16. import time
  17. from PyQt5 import QtWidgets, QtCore, QtGui # Qt5
  18. from OpenGL.GL import *
  19. from PIL import Image
  20.  
  21. """
  22. Demonstrating a bug (?) in QOpenGLWidget / Qt OpenGL insfrastructure :
  23.  
  24. You need:
  25. * to have two tiff images ("base.tif" and "2.tif") in the same directory
  26. * to remove/install some libraries:
  27. sudo apt-get install python3-pyqt5 pip3
  28. sudo apt-get remove python3-opengl # we want the most recent version of the opengl bindings
  29. sudo pip3 install PyOpenGL PyOpenGL_accelerate
  30. sudo pip3 install imutils
  31.  
  32. Usage:
  33. * look for the tag "TOGGLE HERE" below to switch between nested QWidgets / individual windows
  34. * run program with
  35. python3 context_test.py
  36.  
  37. What's going on here?
  38. * Press the button a few times : a new image appears to the first widget
  39. * The image should appear only to the first widget
  40. * .. but it appears in both widgets if we set "nested=False", i.e. when the widgets constitute individual windows
  41. * .. confirm this by clicking / resizing the second window after clicking the button a few times
  42.  
  43. Why this happens?
  44. * Qt creates some sort of "top-level" (?) opengl context that is referring to the same texture ids = bug ?
  45.  
  46.  
  47. This code is licensed under the do-with-it-whatever-you-want license, written by Sampsa Riikonen, 2017
  48. """
  49.  
  50. def getImg(fname):
  51. im =QtGui.QImage(fname)
  52. im =im.convertToFormat(QtGui.QImage.Format_RGB888)
  53. ix =im.width()
  54. iy =im.height()
  55. ptr=im.bits()
  56. ptr.setsize(im.byteCount())
  57. return ptr.asstring(), ix, iy
  58.  
  59.  
  60. class VideoImageWidget(QtWidgets.QOpenGLWidget): # http://doc.qt.io/qt-5/qopenglwidget.html # Qt5
  61.  
  62.  
  63. def __init__(self,parent=None):
  64. super().__init__(parent=parent)
  65. self.parent=parent
  66.  
  67. self.baseimage, self.ix, self.iy =getImg("base.tif")
  68.  
  69. self.gl_format=GL_RGB
  70. self.ratio =1
  71. self.picratio =1
  72.  
  73.  
  74. def changeTexture(self,image,ix,iy):
  75. glBindTexture(GL_TEXTURE_2D, self.tex) # this is the texture we will manipulate
  76. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
  77. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
  78. glTexImage2D(GL_TEXTURE_2D, 0, self.gl_format, ix, iy, 0, self.gl_format, GL_UNSIGNED_BYTE, image) # load bitmap to texture
  79. self.picratio=self.iy/self.ix
  80.  
  81.  
  82. def resetTexture(self):
  83. self.changeTexture(self.baseimage,self.ix,self.iy)
  84.  
  85.  
  86. def initializeGL(self):
  87. # "This function should set up any required OpenGL resources and state"
  88. glEnable(GL_TEXTURE_2D)
  89. self.tex = glGenTextures(1) # create a new texture
  90. # https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGenTextures.xml
  91. # "it is guaranteed that none of the returned names was in use immediately before the call"
  92. print("VideoImageWidget: glGenTextures returned:",self.tex)
  93. self.resetTexture()
  94.  
  95.  
  96. def paintGL(self):
  97. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # Clear The Screen And The Depth Buffer
  98. glLoadIdentity() # Reset The View
  99. glBindTexture(GL_TEXTURE_2D, self.tex) # this is the texture we will manipulate
  100. glBegin(GL_QUADS)
  101. dz=0
  102. r=self.ratio/self.picratio # screen h/w // picture h/w
  103. if (r<1): # screen wider than image
  104. dy=1
  105. dx=r
  106. elif (r>1): # screen taller than image
  107. dx=1
  108. dy=1/r
  109. else:
  110. dx=1
  111. dy=1
  112. glTexCoord2f(0.0, 0.0); glVertex3f(-dx, dy, dz)
  113. glTexCoord2f(1.0, 0.0); glVertex3f( dx, dy, dz)
  114. glTexCoord2f(1.0, 1.0); glVertex3f( dx,-dy, dz)
  115. glTexCoord2f(0.0, 1.0); glVertex3f(-dx,-dy, dz)
  116. glEnd()
  117.  
  118.  
  119. def resizeGL(self, width, height):
  120. """Called upon window resizing: reinitialize the viewport.
  121. """
  122. glViewport(0, 0, width, height)
  123. glLoadIdentity()
  124. glOrtho(-1, 1, 1, -1, -1, 1)
  125. self.ratio=height/width
  126.  
  127.  
  128. @QtCore.pyqtSlot(object)
  129. def frameReceived(self,frame):
  130. buf =frame[0]
  131. width =frame[1]
  132. height=frame[2]
  133. print("VideoImageWidget updating with frame",width,height)
  134. self.changeTexture(buf,width,height)
  135. self.update()
  136.  
  137.  
  138. class MyGui(QtWidgets.QMainWindow):
  139.  
  140. f1 = QtCore.pyqtSignal(object)
  141. f2 = QtCore.pyqtSignal(object)
  142.  
  143. def __init__(self,parent=None):
  144. super().__init__(parent)
  145. self.cw=QtWidgets.QWidget(self)
  146. self.setCentralWidget(self.cw)
  147.  
  148. self.lay = QtWidgets.QVBoxLayout(self.cw)
  149.  
  150. self.b = QtWidgets.QPushButton("Send frame",self.cw)
  151.  
  152. # *** TOGGLE HERE ***
  153. # nested=True # *** widgets sitting in the QMainWindow
  154. nested=False # *** individual windows
  155.  
  156. self.lay.addWidget(self.b)
  157. if (nested):
  158. self.v1 = VideoImageWidget(parent=self.cw)
  159. self.v2 = VideoImageWidget(parent=self.cw)
  160. self.lay.addWidget(self.v1)
  161. self.lay.addWidget(self.v2)
  162. else:
  163. self.v1 = VideoImageWidget(parent=None)
  164. self.v2 = VideoImageWidget(parent=None)
  165. self.v1.show()
  166. self.v2.show()
  167.  
  168. self.b.clicked. connect(self.clicked)
  169. self.f1. connect(self.v1.frameReceived)
  170.  
  171. self.newimage, self.ix, self.iy =getImg("2.tif")
  172.  
  173.  
  174. @QtCore.pyqtSlot()
  175. def clicked(self):
  176. print("emitting frame")
  177. self.f1.emit([self.newimage, self.ix, self.iy]) # update _only_ the first VideoImageWidget
  178.  
  179.  
  180. if (__name__=="__main__"):
  181. app=QtWidgets.QApplication([])
  182.  
  183. # *** Set this to apply context sharing ***
  184. # app.setAttribute(QtCore.Qt.AA_ShareOpenGLContexts)
  185. """
  186. .. but that does not work for textures
  187.  
  188. See the last comment on this post:
  189. http://stackoverflow.com/questions/29838356/is-it-possible-to-use-the-same-opengl-context-between-top-level-windows-in-qt
  190. "I've realised that this does not solve the problem in the question, as it does not actually share the context, but enables sharing of a subset of resources .."
  191.  
  192. That is said also in the qt docs, but in an extremely implicit way..
  193. http://doc.qt.io/qt-5/qopenglwidget.html
  194. "Creating extra QOpenGLContext instances that share resources like textures .. "
  195. """
  196.  
  197. print("OpenGL context sharing status:",app.testAttribute(QtCore.Qt.AA_ShareOpenGLContexts))
  198. mg=MyGui()
  199. mg.show()
  200. app.exec_()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement