|
20 | 20 | __docformat__ = 'restructuredtext en' |
21 | 21 |
|
22 | 22 | from collections import deque |
23 | | -from contextlib import contextmanager |
24 | | -import threading |
25 | 23 | import time |
26 | 24 |
|
27 | 25 | import numpy |
|
32 | 30 | from pyctools.core.qt import (LowEventPriority, qt_version_info, qt_package, |
33 | 31 | QtCore, QtEventLoop, QtGui, QtSlot, QtWidgets) |
34 | 32 |
|
35 | | -if qt_package == 'PyQt5': |
36 | | - from PyQt5.QtWidgets import QOpenGLWidget |
37 | | -elif qt_package == 'PyQt6': |
| 33 | +if qt_package == 'PyQt6': |
38 | 34 | from PyQt6.QtOpenGLWidgets import QOpenGLWidget |
39 | | -elif qt_package == 'PySide2': |
40 | | - from PySide2.QtWidgets import QOpenGLWidget |
41 | 35 | elif qt_package == 'PySide6': |
42 | 36 | from PySide6.QtOpenGLWidgets import QOpenGLWidget |
43 | 37 | else: |
44 | | - raise ImportError(f'Unrecognised qt_package value "{qt_package}"') |
| 38 | + QOpenGLWidget = QtWidgets.QOpenGLWidget |
45 | 39 |
|
46 | 40 | if qt_version_info < (5, 4): |
47 | 41 | raise ImportError('Qt version 5.4 or higher required') |
48 | 42 |
|
49 | 43 |
|
50 | | -# single context lock to serialise OpenGL operations across multiple |
51 | | -# windows |
52 | | -ctx_lock = threading.RLock() |
53 | | - |
54 | | -@contextmanager |
55 | | -def context(): |
56 | | - ctx_lock.acquire() |
57 | | - yield |
58 | | - ctx_lock.release() |
59 | | - |
60 | | -class RenderingThread(QtCore.QObject): |
61 | | - next_frame_event = QtCore.QEvent.registerEventType() |
62 | | - |
63 | | - def __init__(self, widget, **kwds): |
64 | | - super(RenderingThread, self).__init__(**kwds) |
65 | | - self.widget = widget |
66 | | - self.running = False |
67 | | - |
68 | | - def next_frame(self): |
69 | | - self.widget.makeCurrent() |
70 | | - self.widget.paintGL() |
71 | | - # swapBuffers should block until frame interval, depending on hardware |
72 | | - self.widget.swapBuffers() |
73 | | - now = time.time() |
74 | | - self.clock += 1.0 / 75.0 |
75 | | - while now < self.clock: |
76 | | - # swapBuffers didn't block, so do our own free running at 75Hz |
77 | | - time.sleep(self.clock - now) |
78 | | - now = time.time() |
79 | | - self.widget.done_swap(now) |
80 | | - # schedule next frame, after processing other events |
81 | | - QtCore.QCoreApplication.postEvent( |
82 | | - self, QtCore.QEvent(self.next_frame_event), LowEventPriority) |
83 | | - |
84 | | - def event(self, event): |
85 | | - if event.type() == self.next_frame_event: |
86 | | - event.accept() |
87 | | - self.next_frame() |
88 | | - return True |
89 | | - return super(RenderingThread, self).event(event) |
90 | | - |
91 | | - @QtSlot(object) |
92 | | - def resize(self, event): |
93 | | - # resize event is always sent when window first becomes visible |
94 | | - if not self.running: |
95 | | - self.widget.makeCurrent() |
96 | | - self.widget.glInit() |
97 | | - self.clock = time.time() |
98 | | - self.widget.resizeEvent(event) |
99 | | - if not self.running: |
100 | | - self.running = True |
101 | | - self.next_frame() |
102 | | - |
103 | | - |
104 | 44 | class GLDisplay(QOpenGLWidget): |
105 | 45 | def __init__(self, logger, *arg, **kwds): |
106 | 46 | super(GLDisplay, self).__init__(*arg, **kwds) |
@@ -187,57 +127,54 @@ def step(self): |
187 | 127 | self.show_black = False |
188 | 128 |
|
189 | 129 | def initializeGL(self): |
190 | | - with context(): |
191 | | - GL.glClear(GL.GL_COLOR_BUFFER_BIT) |
192 | | - GL.glDisable(GL.GL_DEPTH_TEST) |
193 | | - GL.glEnable(GL.GL_TEXTURE_2D) |
194 | | - texture = GL.glGenTextures(1) |
195 | | - GL.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1) |
196 | | - GL.glBindTexture(GL.GL_TEXTURE_2D, texture) |
197 | | - GL.glDisable(GL.GL_TEXTURE_2D) |
| 130 | + GL.glClear(GL.GL_COLOR_BUFFER_BIT) |
| 131 | + GL.glDisable(GL.GL_DEPTH_TEST) |
| 132 | + GL.glEnable(GL.GL_TEXTURE_2D) |
| 133 | + texture = GL.glGenTextures(1) |
| 134 | + GL.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1) |
| 135 | + GL.glBindTexture(GL.GL_TEXTURE_2D, texture) |
| 136 | + GL.glDisable(GL.GL_TEXTURE_2D) |
198 | 137 |
|
199 | 138 | def resizeGL(self, w, h): |
200 | | - with context(): |
201 | | - GL.glViewport(0, 0, w, h) |
202 | | - GL.glMatrixMode(GL.GL_PROJECTION) |
203 | | - GL.glLoadIdentity() |
204 | | - GL.glOrtho(0, 1, 0, 1, -1, 1) |
205 | | - GL.glMatrixMode(GL.GL_MODELVIEW) |
206 | | - GL.glLoadIdentity() |
| 139 | + GL.glViewport(0, 0, w, h) |
| 140 | + GL.glMatrixMode(GL.GL_PROJECTION) |
| 141 | + GL.glLoadIdentity() |
| 142 | + GL.glOrtho(0, 1, 0, 1, -1, 1) |
| 143 | + GL.glMatrixMode(GL.GL_MODELVIEW) |
| 144 | + GL.glLoadIdentity() |
207 | 145 |
|
208 | 146 | def paintGL(self): |
209 | 147 | if self.show_black: |
210 | 148 | image = self.black_image |
211 | 149 | else: |
212 | 150 | image = self.numpy_image |
213 | 151 | ylen, xlen, bpc = image.shape |
214 | | - with context(): |
215 | | - GL.glEnable(GL.GL_TEXTURE_2D) |
216 | | - GL.glClear(GL.GL_COLOR_BUFFER_BIT) |
217 | | - GL.glDisable(GL.GL_DEPTH_TEST) |
218 | | - GL.glTexParameterf( |
219 | | - GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR) |
220 | | - GL.glTexParameterf( |
221 | | - GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR) |
222 | | - if bpc == 3: |
223 | | - GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB, xlen, ylen, |
224 | | - 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, image) |
225 | | - elif bpc == 1: |
226 | | - GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB, xlen, ylen, |
227 | | - 0, GL.GL_LUMINANCE, GL.GL_UNSIGNED_BYTE, image) |
228 | | - else: |
229 | | - return |
230 | | - GL.glBegin(GL.GL_QUADS) |
231 | | - GL.glTexCoord2i(0, 0) |
232 | | - GL.glVertex2i(0, 1) |
233 | | - GL.glTexCoord2i(0, 1) |
234 | | - GL.glVertex2i(0, 0) |
235 | | - GL.glTexCoord2i(1, 1) |
236 | | - GL.glVertex2i(1, 0) |
237 | | - GL.glTexCoord2i(1, 0) |
238 | | - GL.glVertex2i(1, 1) |
239 | | - GL.glEnd() |
240 | | - GL.glDisable(GL.GL_TEXTURE_2D) |
| 152 | + GL.glEnable(GL.GL_TEXTURE_2D) |
| 153 | + GL.glClear(GL.GL_COLOR_BUFFER_BIT) |
| 154 | + GL.glDisable(GL.GL_DEPTH_TEST) |
| 155 | + GL.glTexParameterf( |
| 156 | + GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR) |
| 157 | + GL.glTexParameterf( |
| 158 | + GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR) |
| 159 | + if bpc == 3: |
| 160 | + GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB, xlen, ylen, |
| 161 | + 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, image) |
| 162 | + elif bpc == 1: |
| 163 | + GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB, xlen, ylen, |
| 164 | + 0, GL.GL_LUMINANCE, GL.GL_UNSIGNED_BYTE, image) |
| 165 | + else: |
| 166 | + return |
| 167 | + GL.glBegin(GL.GL_QUADS) |
| 168 | + GL.glTexCoord2i(0, 0) |
| 169 | + GL.glVertex2i(0, 1) |
| 170 | + GL.glTexCoord2i(0, 1) |
| 171 | + GL.glVertex2i(0, 0) |
| 172 | + GL.glTexCoord2i(1, 1) |
| 173 | + GL.glVertex2i(1, 0) |
| 174 | + GL.glTexCoord2i(1, 0) |
| 175 | + GL.glVertex2i(1, 1) |
| 176 | + GL.glEnd() |
| 177 | + GL.glDisable(GL.GL_TEXTURE_2D) |
241 | 178 |
|
242 | 179 | def startup(self): |
243 | 180 | pass |
|
0 commit comments