1#!/usr/bin/env python 2 3 4############################################################################# 5## 6## Copyright (C) 2018 Riverbank Computing Limited. 7## Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). 8## Contact: http://www.qt-project.org/legal 9## 10## This file is part of the documentation of the Qt Toolkit. 11## 12## $QT_BEGIN_LICENSE:BSD$ 13## You may use this file under the terms of the BSD license as follows: 14## 15## "Redistribution and use in source and binary forms, with or without 16## modification, are permitted provided that the following conditions are 17## met: 18## * Redistributions of source code must retain the above copyright 19## notice, this list of conditions and the following disclaimer. 20## * Redistributions in binary form must reproduce the above copyright 21## notice, this list of conditions and the following disclaimer in 22## the documentation and/or other materials provided with the 23## distribution. 24## * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names 25## of its contributors may be used to endorse or promote products derived 26## from this software without specific prior written permission. 27## 28## 29## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 32## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 33## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 34## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 35## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 36## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 40## $QT_END_LICENSE$ 41## 42############################################################################# 43 44 45import array 46 47from PyQt5.QtCore import QEvent 48from PyQt5.QtGui import (QGuiApplication, QMatrix4x4, QOpenGLContext, 49 QOpenGLShader, QOpenGLShaderProgram, QOpenGLVersionProfile, 50 QSurfaceFormat, QWindow) 51 52 53class OpenGLWindow(QWindow): 54 def __init__(self, parent=None): 55 super(OpenGLWindow, self).__init__(parent) 56 57 self.m_update_pending = False 58 self.m_animating = False 59 self.m_context = None 60 self.m_gl = None 61 62 self.setSurfaceType(QWindow.OpenGLSurface) 63 64 def initialize(self): 65 pass 66 67 def setAnimating(self, animating): 68 self.m_animating = animating 69 70 if animating: 71 self.renderLater() 72 73 def renderLater(self): 74 if not self.m_update_pending: 75 self.m_update_pending = True 76 QGuiApplication.postEvent(self, QEvent(QEvent.UpdateRequest)) 77 78 def renderNow(self): 79 if not self.isExposed(): 80 return 81 82 self.m_update_pending = False 83 84 needsInitialize = False 85 86 if self.m_context is None: 87 self.m_context = QOpenGLContext(self) 88 self.m_context.setFormat(self.requestedFormat()) 89 self.m_context.create() 90 91 needsInitialize = True 92 93 self.m_context.makeCurrent(self) 94 95 if needsInitialize: 96 version_profile = QOpenGLVersionProfile() 97 version_profile.setVersion(2, 0) 98 self.m_gl = self.m_context.versionFunctions(version_profile) 99 self.m_gl.initializeOpenGLFunctions() 100 101 self.initialize() 102 103 self.render(self.m_gl) 104 105 self.m_context.swapBuffers(self) 106 107 if self.m_animating: 108 self.renderLater() 109 110 def event(self, event): 111 if event.type() == QEvent.UpdateRequest: 112 self.renderNow() 113 return True 114 115 return super(OpenGLWindow, self).event(event) 116 117 def exposeEvent(self, event): 118 self.renderNow() 119 120 def resizeEvent(self, event): 121 self.renderNow() 122 123 124class TriangleWindow(OpenGLWindow): 125 vertexShaderSource = ''' 126attribute highp vec4 posAttr; 127attribute lowp vec4 colAttr; 128varying lowp vec4 col; 129uniform highp mat4 matrix; 130void main() { 131 col = colAttr; 132 gl_Position = matrix * posAttr; 133} 134''' 135 136 fragmentShaderSource = ''' 137varying lowp vec4 col; 138void main() { 139 gl_FragColor = col; 140} 141''' 142 143 def __init__(self): 144 super(TriangleWindow, self).__init__() 145 146 self.m_program = 0 147 self.m_frame = 0 148 149 self.m_posAttr = 0 150 self.m_colAttr = 0 151 self.m_matrixUniform = 0 152 153 def initialize(self): 154 self.m_program = QOpenGLShaderProgram(self) 155 156 self.m_program.addShaderFromSourceCode(QOpenGLShader.Vertex, 157 self.vertexShaderSource) 158 self.m_program.addShaderFromSourceCode(QOpenGLShader.Fragment, 159 self.fragmentShaderSource) 160 161 self.m_program.link() 162 163 self.m_posAttr = self.m_program.attributeLocation('posAttr') 164 self.m_colAttr = self.m_program.attributeLocation('colAttr') 165 self.m_matrixUniform = self.m_program.uniformLocation('matrix') 166 167 def render(self, gl): 168 gl.glViewport(0, 0, self.width(), self.height()) 169 170 gl.glClear(gl.GL_COLOR_BUFFER_BIT) 171 172 self.m_program.bind() 173 174 matrix = QMatrix4x4() 175 matrix.perspective(60, 4.0/3.0, 0.1, 100.0) 176 matrix.translate(0, 0, -2) 177 matrix.rotate(100.0 * self.m_frame / self.screen().refreshRate(), 178 0, 1, 0) 179 180 self.m_program.setUniformValue(self.m_matrixUniform, matrix) 181 182 vertices = array.array('f', [ 183 0.0, 0.707, 184 -0.5, -0.5, 185 0.5, -0.5]) 186 187 gl.glVertexAttribPointer(self.m_posAttr, 2, gl.GL_FLOAT, False, 0, 188 vertices) 189 gl.glEnableVertexAttribArray(self.m_posAttr) 190 191 colors = array.array('f', [ 192 1.0, 0.0, 0.0, 193 0.0, 1.0, 0.0, 194 0.0, 0.0, 1.0]) 195 196 gl.glVertexAttribPointer(self.m_colAttr, 3, gl.GL_FLOAT, False, 0, 197 colors) 198 gl.glEnableVertexAttribArray(self.m_colAttr) 199 200 gl.glDrawArrays(gl.GL_TRIANGLES, 0, 3) 201 202 self.m_program.release() 203 204 self.m_frame += 1 205 206 207if __name__ == '__main__': 208 209 import sys 210 211 app = QGuiApplication(sys.argv) 212 213 format = QSurfaceFormat() 214 format.setSamples(4) 215 216 window = TriangleWindow() 217 window.setFormat(format) 218 window.resize(640, 480) 219 window.show() 220 221 window.setAnimating(True) 222 223 sys.exit(app.exec_()) 224