mirror of
https://github.com/cyberboy666/r_e_c_u_r.git
synced 2025-12-05 16:00:06 +01:00
158 lines
5.2 KiB
Python
158 lines
5.2 KiB
Python
# PyQt4 imports
|
|
from PyQt4 import QtGui, QtCore, QtOpenGL
|
|
from PyQt4.QtOpenGL import QGLWidget
|
|
# PyOpenGL imports
|
|
import OpenGL.GL as gl
|
|
import OpenGL.arrays.vbo as glvbo
|
|
|
|
# Window creation function.
|
|
def create_window(window_class):
|
|
"""Create a Qt window in Python, or interactively in IPython with Qt GUI
|
|
event loop integration:
|
|
# in ~/.ipython/ipython_config.py
|
|
c.TerminalIPythonApp.gui = 'qt'
|
|
c.TerminalIPythonApp.pylab = 'qt'
|
|
See also:
|
|
http://ipython.org/ipython-doc/dev/interactive/qtconsole.html#qt-and-the-qtconsole
|
|
"""
|
|
app_created = False
|
|
app = QtCore.QCoreApplication.instance()
|
|
if app is None:
|
|
app = QtGui.QApplication(sys.argv)
|
|
app_created = True
|
|
app.references = set()
|
|
window = window_class()
|
|
app.references.add(window)
|
|
window.show()
|
|
if app_created:
|
|
app.exec_()
|
|
return window
|
|
|
|
def compile_vertex_shader(source):
|
|
"""Compile a vertex shader from source."""
|
|
vertex_shader = gl.glCreateShader(gl.GL_VERTEX_SHADER)
|
|
gl.glShaderSource(vertex_shader, source)
|
|
gl.glCompileShader(vertex_shader)
|
|
# check compilation error
|
|
result = gl.glGetShaderiv(vertex_shader, gl.GL_COMPILE_STATUS)
|
|
if not(result):
|
|
raise RuntimeError(gl.glGetShaderInfoLog(vertex_shader))
|
|
return vertex_shader
|
|
|
|
def compile_fragment_shader(source):
|
|
"""Compile a fragment shader from source."""
|
|
fragment_shader = gl.glCreateShader(gl.GL_FRAGMENT_SHADER)
|
|
gl.glShaderSource(fragment_shader, source)
|
|
gl.glCompileShader(fragment_shader)
|
|
# check compilation error
|
|
result = gl.glGetShaderiv(fragment_shader, gl.GL_COMPILE_STATUS)
|
|
if not(result):
|
|
raise RuntimeError(gl.glGetShaderInfoLog(fragment_shader))
|
|
return fragment_shader
|
|
|
|
def link_shader_program(vertex_shader, fragment_shader):
|
|
"""Create a shader program with from compiled shaders."""
|
|
program = gl.glCreateProgram()
|
|
gl.glAttachShader(program, vertex_shader)
|
|
gl.glAttachShader(program, fragment_shader)
|
|
gl.glLinkProgram(program)
|
|
# check linking error
|
|
result = gl.glGetProgramiv(program, gl.GL_LINK_STATUS)
|
|
if not(result):
|
|
raise RuntimeError(gl.glGetProgramInfoLog(program))
|
|
return program
|
|
|
|
# Vertex shader
|
|
VS = """
|
|
#version 330
|
|
// Attribute variable that contains coordinates of the vertices.
|
|
layout(location = 0) in vec2 position;
|
|
|
|
// Main function, which needs to set `gl_Position`.
|
|
void main()
|
|
{
|
|
// The final position is transformed from a null signal to a sinewave here.
|
|
// We pass the position to gl_Position, by converting it into
|
|
// a 4D vector. The last coordinate should be 0 when rendering 2D figures.
|
|
gl_Position = vec4(position.x, .2 * sin(20 * position.x), 0., 1.);
|
|
}
|
|
"""
|
|
|
|
# Fragment shader
|
|
FS = """
|
|
#version 330
|
|
// Output variable of the fragment shader, which is a 4D vector containing the
|
|
// RGBA components of the pixel color.
|
|
out vec4 out_color;
|
|
|
|
// Main fragment shader function.
|
|
void main()
|
|
{
|
|
// We simply set the pixel color to yellow.
|
|
out_color = vec4(1., 1., 0., 1.);
|
|
}
|
|
"""
|
|
|
|
class GLPlotWidget(QGLWidget):
|
|
# default window size
|
|
width, height = 600, 600
|
|
|
|
def initializeGL(self):
|
|
"""Initialize OpenGL, VBOs, upload data on the GPU, etc."""
|
|
# background color
|
|
gl.glClearColor(0, 0, 0, 0)
|
|
# create a Vertex Buffer Object with the specified data
|
|
self.vbo = glvbo.VBO(self.data)
|
|
# compile the vertex shader
|
|
vs = compile_vertex_shader(VS)
|
|
# compile the fragment shader
|
|
fs = compile_fragment_shader(FS)
|
|
# compile the vertex shader
|
|
self.shaders_program = link_shader_program(vs, fs)
|
|
|
|
def paintGL(self):
|
|
"""Paint the scene."""
|
|
# clear the buffer
|
|
gl.glClear(gl.GL_COLOR_BUFFER_BIT)
|
|
# bind the VBO
|
|
self.vbo.bind()
|
|
# tell OpenGL that the VBO contains an array of vertices
|
|
# prepare the shader
|
|
gl.glEnableVertexAttribArray(0)
|
|
# these vertices contain 2 single precision coordinates
|
|
gl.glVertexAttribPointer(0, 2, gl.GL_FLOAT, gl.GL_FALSE, 0, None)
|
|
gl.glUseProgram(self.shaders_program)
|
|
# draw "count" points from the VBO
|
|
gl.glDrawArrays(gl.GL_LINE_STRIP, 0, len(self.data))
|
|
|
|
def resizeGL(self, width, height):
|
|
"""Called upon window resizing: reinitialize the viewport."""
|
|
# update the window size
|
|
self.width, self.height = width, height
|
|
# paint within the whole window
|
|
gl.glViewport(0, 0, width, height)
|
|
|
|
if __name__ == '__main__':
|
|
# import numpy for generating random data points
|
|
import sys
|
|
import numpy as np
|
|
|
|
# null signal
|
|
data = np.zeros((10000, 2), dtype=np.float32)
|
|
data[:,0] = np.linspace(-1., 1., len(data))
|
|
|
|
# define a Qt window with an OpenGL widget inside it
|
|
class TestWindow(QtGui.QMainWindow):
|
|
def __init__(self):
|
|
super(TestWindow, self).__init__()
|
|
# initialize the GL widget
|
|
self.widget = GLPlotWidget()
|
|
self.widget.data = data
|
|
# put the window at the screen position (100, 100)
|
|
self.setGeometry(100, 100, self.widget.width, self.widget.height)
|
|
self.setCentralWidget(self.widget)
|
|
self.show()
|
|
|
|
# show the window
|
|
win = create_window(TestWindow)
|