Source code for pyqtgraph.opengl.items.GLImageItem

import importlib

from OpenGL import GL
from OpenGL.GL import shaders
import numpy as np

from ...Qt import QtGui, QT_LIB
from ..GLGraphicsItem import GLGraphicsItem

if QT_LIB in ["PyQt5", "PySide2"]:
    QtOpenGL = QtGui
else:
    QtOpenGL = importlib.import_module(f"{QT_LIB}.QtOpenGL")

__all__ = ['GLImageItem']

[docs] class GLImageItem(GLGraphicsItem): """ **Bases:** :class:`GLGraphicsItem <pyqtgraph.opengl.GLGraphicsItem.GLGraphicsItem>` Displays image data as a textured quad. """ _shaderProgram = None
[docs] def __init__(self, data, smooth=False, glOptions='translucent', parentItem=None): """ ============== ======================================================================================= **Arguments:** data Volume data to be rendered. *Must* be 3D numpy array (x, y, RGBA) with dtype=ubyte. (See functions.makeRGBA) smooth (bool) If True, the volume slices are rendered with linear interpolation ============== ======================================================================================= """ super().__init__() self.setGLOptions(glOptions) self.smooth = smooth self._needUpdate = False self.texture = None self.m_vbo_position = QtOpenGL.QOpenGLBuffer(QtOpenGL.QOpenGLBuffer.Type.VertexBuffer) self.setParentItem(parentItem) self.setData(data)
def setData(self, data): self.data = data self._needUpdate = True self.update() def _updateTexture(self): if self.texture is None: self.texture = GL.glGenTextures(1) GL.glBindTexture(GL.GL_TEXTURE_2D, self.texture) filt = GL.GL_LINEAR if self.smooth else GL.GL_NEAREST GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, filt) GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, filt) GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_BORDER) GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_BORDER) shape = self.data.shape context = QtGui.QOpenGLContext.currentContext() if not context.isOpenGLES(): ## Test texture dimensions first GL.glTexImage2D(GL.GL_PROXY_TEXTURE_2D, 0, GL.GL_RGBA, shape[0], shape[1], 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, None) if GL.glGetTexLevelParameteriv(GL.GL_PROXY_TEXTURE_2D, 0, GL.GL_TEXTURE_WIDTH) == 0: raise Exception("OpenGL failed to create 2D texture (%dx%d); too large for this hardware." % shape[:2]) data = np.ascontiguousarray(self.data.transpose((1,0,2))) GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, shape[0], shape[1], 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, data) GL.glBindTexture(GL.GL_TEXTURE_2D, 0) x, y = shape[:2] pos = np.array([ [0, 0, 0, 0], [x, 0, 1, 0], [0, y, 0, 1], [x, y, 1, 1], ], dtype=np.float32) vbo = self.m_vbo_position if not vbo.isCreated(): vbo.create() vbo.bind() vbo.allocate(pos, pos.nbytes) vbo.release() @staticmethod def getShaderProgram(): klass = GLImageItem if klass._shaderProgram is not None: return klass._shaderProgram ctx = QtGui.QOpenGLContext.currentContext() fmt = ctx.format() if ctx.isOpenGLES(): if fmt.version() >= (3, 0): glsl_version = "#version 300 es\n" sources = SHADER_CORE else: glsl_version = "" sources = SHADER_LEGACY else: if fmt.version() >= (3, 1): glsl_version = "#version 140\n" sources = SHADER_CORE else: glsl_version = "" sources = SHADER_LEGACY compiled = [shaders.compileShader([glsl_version, v], k) for k, v in sources.items()] program = shaders.compileProgram(*compiled) GL.glBindAttribLocation(program, 0, "a_position") GL.glBindAttribLocation(program, 1, "a_texcoord") GL.glLinkProgram(program) klass._shaderProgram = program return program def paint(self): if self._needUpdate: self._updateTexture() self._needUpdate = False self.setupGLState() mat_mvp = self.mvpMatrix() mat_mvp = np.array(mat_mvp.data(), dtype=np.float32) program = self.getShaderProgram() loc_pos, loc_tex = 0, 1 self.m_vbo_position.bind() GL.glVertexAttribPointer(loc_pos, 2, GL.GL_FLOAT, False, 4*4, None) GL.glVertexAttribPointer(loc_tex, 2, GL.GL_FLOAT, False, 4*4, GL.GLvoidp(2*4)) self.m_vbo_position.release() enabled_locs = [loc_pos, loc_tex] GL.glBindTexture(GL.GL_TEXTURE_2D, self.texture) for loc in enabled_locs: GL.glEnableVertexAttribArray(loc) with program: loc = GL.glGetUniformLocation(program, "u_mvp") GL.glUniformMatrix4fv(loc, 1, False, mat_mvp) GL.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 4) for loc in enabled_locs: GL.glDisableVertexAttribArray(loc) GL.glBindTexture(GL.GL_TEXTURE_2D, 0)
SHADER_LEGACY = { GL.GL_VERTEX_SHADER : """ uniform mat4 u_mvp; attribute vec4 a_position; attribute vec2 a_texcoord; varying vec2 v_texcoord; void main() { gl_Position = u_mvp * a_position; v_texcoord = a_texcoord; } """, GL.GL_FRAGMENT_SHADER : """ #ifdef GL_ES precision mediump float; #endif uniform sampler2D u_texture; varying vec2 v_texcoord; void main() { gl_FragColor = texture2D(u_texture, v_texcoord); } """, } SHADER_CORE = { GL.GL_VERTEX_SHADER : """ uniform mat4 u_mvp; in vec4 a_position; in vec2 a_texcoord; out vec2 v_texcoord; void main() { gl_Position = u_mvp * a_position; v_texcoord = a_texcoord; } """, GL.GL_FRAGMENT_SHADER : """ #ifdef GL_ES precision mediump float; #endif uniform sampler2D u_texture; in vec2 v_texcoord; out vec4 fragColor; void main() { fragColor = texture(u_texture, v_texcoord); } """, }