Exemple #1
0
    def __init__(self,
                 ddsFile,
                 debugContext=False,
                 parent=None,
                 f=Qt.WindowFlags()):
        super(DDSWidget, self).__init__(parent, f)

        self.ddsFile = ddsFile

        self.clean = True

        self.logger = None

        self.program = None
        self.transparecyProgram = None
        self.texture = None
        self.vbo = None
        self.vao = None

        self.backgroundColour = None

        if debugContext:
            format = QSurfaceFormat()
            format.setOption(QSurfaceFormat.DebugContext)
            self.setFormat(format)
            self.logger = QOpenGLDebugLogger(self)
Exemple #2
0
class DDSWidget(QOpenGLWidget):
    def __init__(self, ddsFile, debugContext = False, parent = None, f = Qt.WindowFlags()):
        super(DDSWidget, self).__init__(parent, f)
        
        self.ddsFile = ddsFile
        
        self.clean = True
        
        self.logger = None
        
        self.program = None
        self.transparecyProgram = None
        self.texture = None
        self.vbo = None
        self.vao = None
        
        self.backgroundColour = None
        
        if debugContext:
            format = QSurfaceFormat()
            format.setOption(QSurfaceFormat.DebugContext)
            self.setFormat(format)
            self.logger = QOpenGLDebugLogger(self)
        
        qDebug("__init__()")
    
    def __del__(self):
        qDebug("__del__()")
        self.cleanup()
    
    def __dtor__(self):
        qDebug("__dtor__()")
        self.cleanup()
    
    def initializeGL(self):
        qDebug("initializeGL()")
        if self.logger:
            self.logger.initialize()
            self.logger.messageLogged.connect(lambda message: qDebug(self.__tr("OpenGL debug message: {0}").fomat(message.message())))
            self.logger.startLogging()
        
        gl = QOpenGLContext.currentContext().versionFunctions(glVersionProfile)
        QOpenGLContext.currentContext().aboutToBeDestroyed.connect(self.cleanup)
        
        self.clean = False
        
        fragmentShader = None
        vertexShader = vertexShader2D
        if self.ddsFile.isCubemap:
            fragmentShader = fragmentShaderCube
            vertexShader = vertexShaderCube
            if QOpenGLContext.currentContext().hasExtension(b"GL_ARB_seamless_cube_map"):
                GL_TEXTURE_CUBE_MAP_SEAMLESS = 0x884F
                gl.glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS)
        elif self.ddsFile.glFormat.samplerType == "F":
            fragmentShader = fragmentShaderFloat
        elif self.ddsFile.glFormat.samplerType == "UI":
            fragmentShader = fragmentShaderUInt
        else:
            fragmentShader = fragmentShaderSInt
        
        self.program = QOpenGLShaderProgram(self)
        self.program.addShaderFromSourceCode(QOpenGLShader.Vertex, vertexShader)
        self.program.addShaderFromSourceCode(QOpenGLShader.Fragment, fragmentShader)
        self.program.bindAttributeLocation("position", 0)
        self.program.bindAttributeLocation("texCoordIn", 1)
        self.program.link()
        
        self.transparecyProgram = QOpenGLShaderProgram(self)
        self.transparecyProgram.addShaderFromSourceCode(QOpenGLShader.Vertex, transparencyVS)
        self.transparecyProgram.addShaderFromSourceCode(QOpenGLShader.Fragment, transparencyFS)
        self.transparecyProgram.bindAttributeLocation("position", 0)
        self.transparecyProgram.link()
        
        self.vao = QOpenGLVertexArrayObject(self)
        vaoBinder = QOpenGLVertexArrayObject.Binder(self.vao)
        
        self.vbo = QOpenGLBuffer(QOpenGLBuffer.VertexBuffer)
        self.vbo.create()
        self.vbo.bind()
        
        theBytes = struct.pack("%sf" % len(vertices), *vertices)
        self.vbo.allocate(theBytes, len(theBytes))
        
        gl.glEnableVertexAttribArray(0)
        gl.glEnableVertexAttribArray(1)
        gl.glVertexAttribPointer(0, 4, gl.GL_FLOAT, False, 6 * 4, 0)
        gl.glVertexAttribPointer(1, 2, gl.GL_FLOAT, False, 6 * 4, 4 * 4)
        
        self.texture = self.ddsFile.asQOpenGLTexture(gl, QOpenGLContext.currentContext())
    
    def resizeGL(self, w, h):
        qDebug("resizeGL(" + str(w) + ", " + str(h) + ")")
        aspectRatioTex = self.texture.width() / self.texture.height() if self.texture else 1.0
        aspectRatioWidget = w / h
        ratioRatio = aspectRatioTex / aspectRatioWidget
        
        self.program.bind()
        self.program.setUniformValue("aspectRatioRatio", ratioRatio)
        self.program.release()
    
    def paintGL(self):
        qDebug("paintGL()")
        gl = QOpenGLContext.currentContext().versionFunctions(glVersionProfile)
        
        vaoBinder = QOpenGLVertexArrayObject.Binder(self.vao)
        
        # Draw checkerboard so transparency is obvious
        self.transparecyProgram.bind()
        
        if self.backgroundColour and self.backgroundColour.isValid():
            self.transparecyProgram.setUniformValue("backgroundColour", self.backgroundColour)
        
        gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6)
        
        self.transparecyProgram.release()
        
        self.program.bind()
            
        if self.texture:
            self.texture.bind()
        
        gl.glEnable(gl.GL_BLEND)
        gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
        
        gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6)
        
        if self.texture:
            self.texture.release()
        self.program.release()
    
    def cleanup(self):
        qDebug("cleanup()")
        if not self.clean:
            self.makeCurrent()
            
            self.program = None
            self.transparecyProgram = None
            if self.texture:
                self.texture.destroy()
            self.texture = None
            self.vbo.destroy()
            self.vbo = None
            self.vao.destroy()
            self.vao = None
            
            self.doneCurrent()
            self.clean = True
    
    def setBackgroundColour(self, colour):
        self.backgroundColour = colour
    
    def getBackgroundColour(self):
        return self.backgroundColour
    
    def __tr(self, str):
        return QCoreApplication.translate("DDSWidget", str)
    def renderNow(self):
        if not self.isExposed():
            return

        self.m_update_pending = False

        needsInitialize = False

        if self.m_context is None:
            self.m_context = QOpenGLContext(self)
            self.m_context.setFormat(self.requestedFormat())
            self.m_context.create()

            needsInitialize = True

        self.m_context.makeCurrent(self)

        if needsInitialize:
#           Sorry, no support for higher versions for now.
            profile = QOpenGLVersionProfile()
            profile.setVersion(2, 0)

            self.m_gl = self.m_context.versionFunctions(profile)
            self.m_gl.initializeOpenGLFunctions()

            #print(self.m_context.hasExtension('GL_EXT_framebuffer_object'))
            #print(self.m_context.hasExtension('GL_ARB_texture_float'))
            #print(*sorted(self.m_context.extensions()), sep='\n')

#           Small hack. Guess noone mind?            
            import ctypes
            import ctypes.util
            GL = ctypes.CDLL(ctypes.util.find_library('GL'))

            self.addGlFunctuins(GL, {
                'glFramebufferTexture2D': (ctypes.c_uint, ctypes.c_uint, ctypes.c_uint, ctypes.c_uint, ctypes.c_int)
                })

            self.logger = QOpenGLDebugLogger()
            self.logger.initialize()
            self.logger.loggedMessages()
            self.logger.messageLogged.connect(self.handleLoggedMassage)
            self.logger.startLogging()

            self.initialize(self.m_gl)
        
        if not self.m_device:
            self.m_device = QOpenGLPaintDevice()

        self.m_gl.glClear(self.m_gl.GL_COLOR_BUFFER_BIT | self.m_gl.GL_DEPTH_BUFFER_BIT);

        self.m_device.setSize(self.size())

        painter = QPainter(self.m_device)


        painter.beginNativePainting()
        self.render(self.m_gl)
        painter.endNativePainting()

        self.paint(painter)

        self.m_context.swapBuffers(self)

        if self.m_animating:
            self.renderLater()
class OpenGLWindow(QWindow):
    def __init__(self, parent=None):
        super(OpenGLWindow, self).__init__(parent)

        self.m_update_pending = False
        self.m_animating = False
        self.m_context = None
        self.m_device = None
        self.m_gl = None
        self.logger = None

        self.setSurfaceType(QWindow.OpenGLSurface)

    def initialize(self, gl):
        pass

    def setAnimating(self, animating):
        self.m_animating = animating

        if animating:
            self.renderLater()

    def renderLater(self):
        if not self.m_update_pending:
            self.m_update_pending = True
            QGuiApplication.postEvent(self, QEvent(QEvent.UpdateRequest))

    def paint(self, painter):
        pass

    def render(self, gl):
        pass

    def addGlFunctuins(self, GL, functions):
        for function, arguments in functions.items():
            GL[function].restype = None
            GL[function].argtypes = arguments
            setattr(self.m_gl, function, GL[function])

    @exitOnKeyboardInterrupt
    def renderNow(self):
        if not self.isExposed():
            return

        self.m_update_pending = False

        needsInitialize = False

        if self.m_context is None:
            self.m_context = QOpenGLContext(self)
            self.m_context.setFormat(self.requestedFormat())
            self.m_context.create()

            needsInitialize = True

        self.m_context.makeCurrent(self)

        if needsInitialize:
#           Sorry, no support for higher versions for now.
            profile = QOpenGLVersionProfile()
            profile.setVersion(2, 0)

            self.m_gl = self.m_context.versionFunctions(profile)
            self.m_gl.initializeOpenGLFunctions()

            #print(self.m_context.hasExtension('GL_EXT_framebuffer_object'))
            #print(self.m_context.hasExtension('GL_ARB_texture_float'))
            #print(*sorted(self.m_context.extensions()), sep='\n')

#           Small hack. Guess noone mind?            
            import ctypes
            import ctypes.util
            GL = ctypes.CDLL(ctypes.util.find_library('GL'))

            self.addGlFunctuins(GL, {
                'glFramebufferTexture2D': (ctypes.c_uint, ctypes.c_uint, ctypes.c_uint, ctypes.c_uint, ctypes.c_int)
                })

            self.logger = QOpenGLDebugLogger()
            self.logger.initialize()
            self.logger.loggedMessages()
            self.logger.messageLogged.connect(self.handleLoggedMassage)
            self.logger.startLogging()

            self.initialize(self.m_gl)
        
        if not self.m_device:
            self.m_device = QOpenGLPaintDevice()

        self.m_gl.glClear(self.m_gl.GL_COLOR_BUFFER_BIT | self.m_gl.GL_DEPTH_BUFFER_BIT);

        self.m_device.setSize(self.size())

        painter = QPainter(self.m_device)


        painter.beginNativePainting()
        self.render(self.m_gl)
        painter.endNativePainting()

        self.paint(painter)

        self.m_context.swapBuffers(self)

        if self.m_animating:
            self.renderLater()

    def handleLoggedMassage(self, message):
#       This three really annoyng and brings no useful info =\        
        if not (message.message().find('Use glDrawRangeElements() to avoid this.') > -1 or 
                message.message().find('CPU mapping a busy miptree') > -1 or
                message.message().find('Flushing before mapping a referenced bo.') > -1
                ):
            print(message.message().strip())

    def event(self, event):
        if event.type() == QEvent.UpdateRequest:
            self.renderNow()
            return True

        return super(OpenGLWindow, self).event(event)

    def exposeEvent(self, event):
        self.renderNow()

    def resizeEvent(self, event):
        self.renderNow()