1#!/usr/bin/env python 2 3""" 4helloglwidget.py 5 6A simple OpenGL custom widget for Qt Designer. 7 8Copyright (C) 2007 David Boddie <david@boddie.org.uk> 9Copyright (C) 2005-2006 Trolltech ASA. All rights reserved. 10 11This program is free software; you can redistribute it and/or modify 12it under the terms of the GNU General Public License as published by 13the Free Software Foundation; either version 2 of the License, or 14(at your option) any later version. 15 16This program is distributed in the hope that it will be useful, 17but WITHOUT ANY WARRANTY; without even the implied warranty of 18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19GNU General Public License for more details. 20 21You should have received a copy of the GNU General Public License 22along with this program; if not, write to the Free Software 23Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24""" 25 26import math 27 28from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QPoint, QSize, Qt 29from PyQt5.QtGui import QColor 30from PyQt5.QtWidgets import QApplication, QOpenGLWidget 31 32 33class HelloGLWidget(QOpenGLWidget): 34 """HelloGLWidget(QOpenGLWidget) 35 36 Provides a custom widget to display an OpenGL-rendered Qt logo. 37 Various properties and slots are defined so that the user can rotate 38 the logo, and signals are defined to enable other components to 39 react to changes to its orientation. 40 """ 41 42 # We define three signals that are used to indicate changes to the 43 # rotation of the logo. 44 xRotationChanged = pyqtSignal(int) 45 yRotationChanged = pyqtSignal(int) 46 zRotationChanged = pyqtSignal(int) 47 48 def __init__(self, parent=None): 49 super(HelloGLWidget, self).__init__(parent) 50 51 self.object = 0 52 self.xRot = 0 53 self.yRot = 0 54 self.zRot = 0 55 56 self.lastPos = QPoint() 57 58 self.trolltechGreen = QColor.fromCmykF(0.40, 0.0, 1.0, 0.0) 59 self.trolltechPurple = QColor.fromCmykF(0.39, 0.39, 0.0, 0.0) 60 61 self.setWindowTitle("Hello GL") 62 63 # The rotation of the logo about the x-axis can be controlled using the 64 # xRotation property, defined using the following getter and setter 65 # methods. 66 67 def getXRotation(self): 68 return self.xRot 69 70 # The setXRotation() setter method is also a slot. 71 @pyqtSlot(int) 72 def setXRotation(self, angle): 73 angle = self.normalizeAngle(angle) 74 if angle != self.xRot: 75 self.xRot = angle 76 self.xRotationChanged.emit(angle) 77 self.update() 78 79 xRotation = pyqtProperty(int, getXRotation, setXRotation) 80 81 # The rotation of the logo about the y-axis can be controlled using the 82 # yRotation property, defined using the following getter and setter 83 # methods. 84 85 def getYRotation(self): 86 return self.yRot 87 88 # The setYRotation() setter method is also a slot. 89 @pyqtSlot(int) 90 def setYRotation(self, angle): 91 angle = self.normalizeAngle(angle) 92 if angle != self.yRot: 93 self.yRot = angle 94 self.yRotationChanged.emit(angle) 95 self.update() 96 97 yRotation = pyqtProperty(int, getYRotation, setYRotation) 98 99 # The rotation of the logo about the z-axis can be controlled using the 100 # zRotation property, defined using the following getter and setter 101 # methods. 102 103 def getZRotation(self): 104 return self.zRot 105 106 # The setZRotation() setter method is also a slot. 107 @pyqtSlot(int) 108 def setZRotation(self, angle): 109 angle = self.normalizeAngle(angle) 110 if angle != self.zRot: 111 self.zRot = angle 112 self.zRotationChanged.emit(angle) 113 self.update() 114 115 zRotation = pyqtProperty(int, getZRotation, setZRotation) 116 117 def minimumSizeHint(self): 118 return QSize(50, 50) 119 120 def sizeHint(self): 121 return QSize(200, 200) 122 123 def initializeGL(self): 124 self.gl = self.context().versionFunctions() 125 self.gl.initializeOpenGLFunctions() 126 127 self.setClearColor(self.trolltechPurple.darker()) 128 self.object = self.makeObject() 129 self.gl.glShadeModel(self.gl.GL_SMOOTH) 130 self.gl.glEnable(self.gl.GL_DEPTH_TEST) 131 self.gl.glEnable(self.gl.GL_CULL_FACE) 132 133 def paintGL(self): 134 self.gl.glClear(self.gl.GL_COLOR_BUFFER_BIT | self.gl.GL_DEPTH_BUFFER_BIT) 135 self.gl.glLoadIdentity() 136 self.gl.glTranslated(0.0, 0.0, -10.0) 137 self.gl.glRotated(self.xRot / 16.0, 1.0, 0.0, 0.0) 138 self.gl.glRotated(self.yRot / 16.0, 0.0, 1.0, 0.0) 139 self.gl.glRotated(self.zRot / 16.0, 0.0, 0.0, 1.0) 140 self.gl.glCallList(self.object) 141 142 def resizeGL(self, width, height): 143 side = min(width, height) 144 self.gl.glViewport((width - side) / 2, (height - side) / 2, side, side) 145 146 self.gl.glMatrixMode(self.gl.GL_PROJECTION) 147 self.gl.glLoadIdentity() 148 self.gl.glOrtho(-0.5, +0.5, +0.5, -0.5, 4.0, 15.0) 149 self.gl.glMatrixMode(self.gl.GL_MODELVIEW) 150 151 def mousePressEvent(self, event): 152 self.lastPos = QPoint(event.pos()) 153 154 def mouseMoveEvent(self, event): 155 dx = event.x() - self.lastPos.x() 156 dy = event.y() - self.lastPos.y() 157 158 if event.buttons() & Qt.LeftButton: 159 self.setXRotation(self.xRot + 8 * dy) 160 self.setYRotation(self.yRot + 8 * dx) 161 elif event.buttons() & Qt.RightButton: 162 self.setXRotation(self.xRot + 8 * dy) 163 self.setZRotation(self.zRot + 8 * dx) 164 165 self.lastPos = QPoint(event.pos()) 166 167 def makeObject(self): 168 genList = self.gl.glGenLists(1) 169 self.gl.glNewList(genList, self.gl.GL_COMPILE) 170 171 self.gl.glBegin(self.gl.GL_QUADS) 172 173 x1 = +0.06 174 y1 = -0.14 175 x2 = +0.14 176 y2 = -0.06 177 x3 = +0.08 178 y3 = +0.00 179 x4 = +0.30 180 y4 = +0.22 181 182 self.quad(x1, y1, x2, y2, y2, x2, y1, x1) 183 self.quad(x3, y3, x4, y4, y4, x4, y3, x3) 184 185 self.extrude(x1, y1, x2, y2) 186 self.extrude(x2, y2, y2, x2) 187 self.extrude(y2, x2, y1, x1) 188 self.extrude(y1, x1, x1, y1) 189 self.extrude(x3, y3, x4, y4) 190 self.extrude(x4, y4, y4, x4) 191 self.extrude(y4, x4, y3, x3) 192 193 Pi = 3.14159265358979323846 194 NumSectors = 200 195 196 for i in range(NumSectors): 197 angle1 = (i * 2 * Pi) / NumSectors 198 x5 = 0.30 * math.sin(angle1) 199 y5 = 0.30 * math.cos(angle1) 200 x6 = 0.20 * math.sin(angle1) 201 y6 = 0.20 * math.cos(angle1) 202 203 angle2 = ((i + 1) * 2 * Pi) / NumSectors 204 x7 = 0.20 * math.sin(angle2) 205 y7 = 0.20 * math.cos(angle2) 206 x8 = 0.30 * math.sin(angle2) 207 y8 = 0.30 * math.cos(angle2) 208 209 self.quad(x5, y5, x6, y6, x7, y7, x8, y8) 210 211 self.extrude(x6, y6, x7, y7) 212 self.extrude(x8, y8, x5, y5) 213 214 self.gl.glEnd() 215 self.gl.glEndList() 216 217 return genList 218 219 def quad(self, x1, y1, x2, y2, x3, y3, x4, y4): 220 self.setColor(self.trolltechGreen) 221 222 self.gl.glVertex3d(x1, y1, -0.05) 223 self.gl.glVertex3d(x2, y2, -0.05) 224 self.gl.glVertex3d(x3, y3, -0.05) 225 self.gl.glVertex3d(x4, y4, -0.05) 226 227 self.gl.glVertex3d(x4, y4, +0.05) 228 self.gl.glVertex3d(x3, y3, +0.05) 229 self.gl.glVertex3d(x2, y2, +0.05) 230 self.gl.glVertex3d(x1, y1, +0.05) 231 232 def extrude(self, x1, y1, x2, y2): 233 self.setColor(self.trolltechGreen.darker(250 + int(100 * x1))) 234 235 self.gl.glVertex3d(x1, y1, +0.05) 236 self.gl.glVertex3d(x2, y2, +0.05) 237 self.gl.glVertex3d(x2, y2, -0.05) 238 self.gl.glVertex3d(x1, y1, -0.05) 239 240 def normalizeAngle(self, angle): 241 while angle < 0: 242 angle += 360 * 16 243 while angle > 360 * 16: 244 angle -= 360 * 16 245 return angle 246 247 def setClearColor(self, c): 248 self.gl.glClearColor(c.redF(), c.greenF(), c.blueF(), c.alphaF()) 249 250 def setColor(self, c): 251 self.gl.glColor4f(c.redF(), c.greenF(), c.blueF(), c.alphaF()) 252 253 254if __name__ == "__main__": 255 256 import sys 257 258 app = QApplication(sys.argv) 259 widget = HelloGLWidget() 260 widget.show() 261 sys.exit(app.exec_()) 262