diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2018-01-05 15:58:35 +0100 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2018-01-12 12:28:10 +0000 |
commit | 9f2a9aba3aff73e31ea15eb4a7a04b0e50f4ee4e (patch) | |
tree | 92dcb0c4f64df8a8375af2e1a9bb1170068c36b2 /examples/opengl/grabber.py | |
parent | 26c046e521c38bbfc3a263782a3bb74a7c1bf937 (diff) |
Move examples from submodule to pyside-setup
Move PySide2 examples that are owned by the Qt Company
to a new examples directory.
Done-with: Venugopal Shivashankar <Venugopal.Shivashankar@qt.io>
Task-number: PYSIDE-363
Change-Id: I14099764d9eef2bc35e067086121427955862e3a
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'examples/opengl/grabber.py')
-rw-r--r-- | examples/opengl/grabber.py | 436 |
1 files changed, 436 insertions, 0 deletions
diff --git a/examples/opengl/grabber.py b/examples/opengl/grabber.py new file mode 100644 index 000000000..f9eb9dc05 --- /dev/null +++ b/examples/opengl/grabber.py @@ -0,0 +1,436 @@ +#!/usr/bin/env python + +############################################################################ +## +## Copyright (C) 2013 Riverbank Computing Limited. +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: http://www.qt.io/licensing/ +## +## This file is part of the PySide examples of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## You may use this file under the terms of the BSD license as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################ + +"""PySide2 port of the opengl/legacy/grabber example from Qt v5.x""" + +import sys +import math + +from PySide2 import QtCore, QtGui, QtWidgets, QtOpenGL + +try: + from OpenGL.GL import * +except ImportError: + app = QtWidgets.QApplication(sys.argv) + messageBox = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Critical, "OpenGL grabber", + "PyOpenGL must be installed to run this example.", + QtWidgets.QMessageBox.Close) + messageBox.setDetailedText("Run:\npip install PyOpenGL PyOpenGL_accelerate") + messageBox.exec_() + sys.exit(1) + + +class GLWidget(QtOpenGL.QGLWidget): + xRotationChanged = QtCore.Signal(int) + yRotationChanged = QtCore.Signal(int) + zRotationChanged = QtCore.Signal(int) + + def __init__(self, parent=None): + super(GLWidget, self).__init__(parent) + + self.gear1 = 0 + self.gear2 = 0 + self.gear3 = 0 + self.xRot = 0 + self.yRot = 0 + self.zRot = 0 + self.gear1Rot = 0 + + timer = QtCore.QTimer(self) + timer.timeout.connect(self.advanceGears) + timer.start(20) + + def freeResources(self): + self.makeCurrent() + glDeleteLists(self.gear1, 1) + glDeleteLists(self.gear2, 1) + glDeleteLists(self.gear3, 1) + + def setXRotation(self, angle): + self.normalizeAngle(angle) + + if angle != self.xRot: + self.xRot = angle + self.xRotationChanged.emit(angle) + self.updateGL() + + def setYRotation(self, angle): + self.normalizeAngle(angle) + + if angle != self.yRot: + self.yRot = angle + self.yRotationChanged.emit(angle) + self.updateGL() + + def setZRotation(self, angle): + self.normalizeAngle(angle) + + if angle != self.zRot: + self.zRot = angle + self.zRotationChanged.emit(angle) + self.updateGL() + + def initializeGL(self): + lightPos = (5.0, 5.0, 10.0, 1.0) + reflectance1 = (0.8, 0.1, 0.0, 1.0) + reflectance2 = (0.0, 0.8, 0.2, 1.0) + reflectance3 = (0.2, 0.2, 1.0, 1.0) + + glLightfv(GL_LIGHT0, GL_POSITION, lightPos) + glEnable(GL_LIGHTING) + glEnable(GL_LIGHT0) + glEnable(GL_DEPTH_TEST) + + self.gear1 = self.makeGear(reflectance1, 1.0, 4.0, 1.0, 0.7, 20) + self.gear2 = self.makeGear(reflectance2, 0.5, 2.0, 2.0, 0.7, 10) + self.gear3 = self.makeGear(reflectance3, 1.3, 2.0, 0.5, 0.7, 10) + + glEnable(GL_NORMALIZE) + glClearColor(0.0, 0.0, 0.0, 1.0) + + def paintGL(self): + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + + glPushMatrix() + glRotated(self.xRot / 16.0, 1.0, 0.0, 0.0) + glRotated(self.yRot / 16.0, 0.0, 1.0, 0.0) + glRotated(self.zRot / 16.0, 0.0, 0.0, 1.0) + + self.drawGear(self.gear1, -3.0, -2.0, 0.0, self.gear1Rot / 16.0) + self.drawGear(self.gear2, +3.1, -2.0, 0.0, + -2.0 * (self.gear1Rot / 16.0) - 9.0) + + glRotated(+90.0, 1.0, 0.0, 0.0) + self.drawGear(self.gear3, -3.1, -1.8, -2.2, + +2.0 * (self.gear1Rot / 16.0) - 2.0) + + glPopMatrix() + + def resizeGL(self, width, height): + side = min(width, height) + if side < 0: + return + + glViewport(int((width - side) / 2), int((height - side) / 2), side, side) + + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + glFrustum(-1.0, +1.0, -1.0, 1.0, 5.0, 60.0) + glMatrixMode(GL_MODELVIEW) + glLoadIdentity() + glTranslated(0.0, 0.0, -40.0) + + def mousePressEvent(self, event): + self.lastPos = event.pos() + + def mouseMoveEvent(self, event): + dx = event.x() - self.lastPos.x() + dy = event.y() - self.lastPos.y() + + if event.buttons() & QtCore.Qt.LeftButton: + self.setXRotation(self.xRot + 8 * dy) + self.setYRotation(self.yRot + 8 * dx) + elif event.buttons() & QtCore.Qt.RightButton: + self.setXRotation(self.xRot + 8 * dy) + self.setZRotation(self.zRot + 8 * dx) + + self.lastPos = event.pos() + + def advanceGears(self): + self.gear1Rot += 2 * 16 + self.updateGL() + + def xRotation(self): + return self.xRot + + def yRotation(self): + return self.yRot + + def zRotation(self): + return self.zRot + + def makeGear(self, reflectance, innerRadius, outerRadius, thickness, toothSize, toothCount): + list = glGenLists(1) + glNewList(list, GL_COMPILE) + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, reflectance) + + r0 = innerRadius + r1 = outerRadius - toothSize / 2.0 + r2 = outerRadius + toothSize / 2.0 + delta = (2.0 * math.pi / toothCount) / 4.0 + z = thickness / 2.0 + + glShadeModel(GL_FLAT) + + for i in range(2): + if i == 0: + sign = +1.0 + else: + sign = -1.0 + + glNormal3d(0.0, 0.0, sign) + + glBegin(GL_QUAD_STRIP) + + for j in range(toothCount+1): + angle = 2.0 * math.pi * j / toothCount + glVertex3d(r0 * math.cos(angle), r0 * math.sin(angle), sign * z) + glVertex3d(r1 * math.cos(angle), r1 * math.sin(angle), sign * z) + glVertex3d(r0 * math.cos(angle), r0 * math.sin(angle), sign * z) + glVertex3d(r1 * math.cos(angle + 3 * delta), r1 * math.sin(angle + 3 * delta), sign * z) + + glEnd() + + glBegin(GL_QUADS) + + for j in range(toothCount): + angle = 2.0 * math.pi * j / toothCount + glVertex3d(r1 * math.cos(angle), r1 * math.sin(angle), sign * z) + glVertex3d(r2 * math.cos(angle + delta), r2 * math.sin(angle + delta), sign * z) + glVertex3d(r2 * math.cos(angle + 2 * delta), r2 * math.sin(angle + 2 * delta), sign * z) + glVertex3d(r1 * math.cos(angle + 3 * delta), r1 * math.sin(angle + 3 * delta), sign * z) + + glEnd() + + glBegin(GL_QUAD_STRIP) + + for i in range(toothCount): + for j in range(2): + angle = 2.0 * math.pi * (i + (j / 2.0)) / toothCount + s1 = r1 + s2 = r2 + + if j == 1: + s1, s2 = s2, s1 + + glNormal3d(math.cos(angle), math.sin(angle), 0.0) + glVertex3d(s1 * math.cos(angle), s1 * math.sin(angle), +z) + glVertex3d(s1 * math.cos(angle), s1 * math.sin(angle), -z) + + glNormal3d(s2 * math.sin(angle + delta) - s1 * math.sin(angle), s1 * math.cos(angle) - s2 * math.cos(angle + delta), 0.0) + glVertex3d(s2 * math.cos(angle + delta), s2 * math.sin(angle + delta), +z) + glVertex3d(s2 * math.cos(angle + delta), s2 * math.sin(angle + delta), -z) + + glVertex3d(r1, 0.0, +z) + glVertex3d(r1, 0.0, -z) + glEnd() + + glShadeModel(GL_SMOOTH) + + glBegin(GL_QUAD_STRIP) + + for i in range(toothCount+1): + angle = i * 2.0 * math.pi / toothCount + glNormal3d(-math.cos(angle), -math.sin(angle), 0.0) + glVertex3d(r0 * math.cos(angle), r0 * math.sin(angle), +z) + glVertex3d(r0 * math.cos(angle), r0 * math.sin(angle), -z) + + glEnd() + + glEndList() + + return list + + def drawGear(self, gear, dx, dy, dz, angle): + glPushMatrix() + glTranslated(dx, dy, dz) + glRotated(angle, 0.0, 0.0, 1.0) + glCallList(gear) + glPopMatrix() + + def normalizeAngle(self, angle): + while (angle < 0): + angle += 360 * 16 + + while (angle > 360 * 16): + angle -= 360 * 16 + + +class MainWindow(QtWidgets.QMainWindow): + def __init__(self): + super(MainWindow, self).__init__() + + centralWidget = QtWidgets.QWidget() + self.setCentralWidget(centralWidget) + + self.glWidget = GLWidget() + self.pixmapLabel = QtWidgets.QLabel() + + self.glWidgetArea = QtWidgets.QScrollArea() + self.glWidgetArea.setWidget(self.glWidget) + self.glWidgetArea.setWidgetResizable(True) + self.glWidgetArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + self.glWidgetArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + self.glWidgetArea.setSizePolicy(QtWidgets.QSizePolicy.Ignored, + QtWidgets.QSizePolicy.Ignored) + self.glWidgetArea.setMinimumSize(50, 50) + + self.pixmapLabelArea = QtWidgets.QScrollArea() + self.pixmapLabelArea.setWidget(self.pixmapLabel) + self.pixmapLabelArea.setSizePolicy(QtWidgets.QSizePolicy.Ignored, + QtWidgets.QSizePolicy.Ignored) + self.pixmapLabelArea.setMinimumSize(50, 50) + + xSlider = self.createSlider(self.glWidget.xRotationChanged, + self.glWidget.setXRotation) + ySlider = self.createSlider(self.glWidget.yRotationChanged, + self.glWidget.setYRotation) + zSlider = self.createSlider(self.glWidget.zRotationChanged, + self.glWidget.setZRotation) + + self.createActions() + self.createMenus() + + centralLayout = QtWidgets.QGridLayout() + centralLayout.addWidget(self.glWidgetArea, 0, 0) + centralLayout.addWidget(self.pixmapLabelArea, 0, 1) + centralLayout.addWidget(xSlider, 1, 0, 1, 2) + centralLayout.addWidget(ySlider, 2, 0, 1, 2) + centralLayout.addWidget(zSlider, 3, 0, 1, 2) + centralWidget.setLayout(centralLayout) + + xSlider.setValue(15 * 16) + ySlider.setValue(345 * 16) + zSlider.setValue(0 * 16) + + self.setWindowTitle("Grabber") + self.resize(400, 300) + + def renderIntoPixmap(self): + size = self.getSize() + + if size.isValid(): + pixmap = self.glWidget.renderPixmap(size.width(), size.height()) + self.setPixmap(pixmap) + + def grabFrameBuffer(self): + image = self.glWidget.grabFrameBuffer() + self.setPixmap(QtGui.QPixmap.fromImage(image)) + + def clearPixmap(self): + self.setPixmap(QtGui.QPixmap()) + + def about(self): + QtWidgets.QMessageBox.about(self, "About Grabber", + "The <b>Grabber</b> example demonstrates two approaches for " + "rendering OpenGL into a Qt pixmap.") + + def createActions(self): + self.renderIntoPixmapAct = QtWidgets.QAction("&Render into Pixmap...", + self, shortcut="Ctrl+R", triggered=self.renderIntoPixmap) + + self.grabFrameBufferAct = QtWidgets.QAction("&Grab Frame Buffer", self, + shortcut="Ctrl+G", triggered=self.grabFrameBuffer) + + self.clearPixmapAct = QtWidgets.QAction("&Clear Pixmap", self, + shortcut="Ctrl+L", triggered=self.clearPixmap) + + self.exitAct = QtWidgets.QAction("E&xit", self, shortcut="Ctrl+Q", + triggered=self.close) + + self.aboutAct = QtWidgets.QAction("&About", self, triggered=self.about) + + self.aboutQtAct = QtWidgets.QAction("About &Qt", self, + triggered=QtWidgets.qApp.aboutQt) + + def createMenus(self): + self.fileMenu = self.menuBar().addMenu("&File") + self.fileMenu.addAction(self.renderIntoPixmapAct) + self.fileMenu.addAction(self.grabFrameBufferAct) + self.fileMenu.addAction(self.clearPixmapAct) + self.fileMenu.addSeparator() + self.fileMenu.addAction(self.exitAct) + + self.helpMenu = self.menuBar().addMenu("&Help") + self.helpMenu.addAction(self.aboutAct) + self.helpMenu.addAction(self.aboutQtAct) + + def createSlider(self, changedSignal, setterSlot): + slider = QtWidgets.QSlider(QtCore.Qt.Horizontal) + slider.setRange(0, 360 * 16) + slider.setSingleStep(16) + slider.setPageStep(15 * 16) + slider.setTickInterval(15 * 16) + slider.setTickPosition(QtWidgets.QSlider.TicksRight) + + slider.valueChanged.connect(setterSlot) + changedSignal.connect(slider.setValue) + + return slider + + def setPixmap(self, pixmap): + self.pixmapLabel.setPixmap(pixmap) + size = pixmap.size() + + if size - QtCore.QSize(1, 0) == self.pixmapLabelArea.maximumViewportSize(): + size -= QtCore.QSize(1, 0) + + self.pixmapLabel.resize(size) + + def getSize(self): + text, ok = QtWidgets.QInputDialog.getText(self, "Grabber", + "Enter pixmap size:", QtWidgets.QLineEdit.Normal, + "%d x %d" % (self.glWidget.width(), self.glWidget.height())) + + if not ok: + return QtCore.QSize() + + regExp = QtCore.QRegExp("([0-9]+) *x *([0-9]+)") + + if regExp.exactMatch(text): + width = int(regExp.cap(1)) + height = int(regExp.cap(2)) + if width > 0 and width < 2048 and height > 0 and height < 2048: + return QtCore.QSize(width, height) + + return self.glWidget.size() + + +if __name__ == '__main__': + + app = QtWidgets.QApplication(sys.argv) + mainWin = MainWindow() + mainWin.show() + res = app.exec_() + mainWin.glWidget.freeResources() + sys.exit(res) |