Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Modern opengl using Python
from glfwpy.glfw import (AUTO_POLL_EVENTS, OPENED, OPENGL_CORE_PROFILE,
OPENGL_FORWARD_COMPAT, OPENGL_PROFILE, OPENGL_VERSION_MAJOR,
OPENGL_VERSION_MINOR, WINDOW,
Enable, GetWindowParam, Init, OpenWindow, OpenWindowHint,
SetKeyCallback, SetWindowTitle, SwapBuffers, Terminate)
import numpy as np
from OpenGL.arrays import ArrayDatatype
from OpenGL.GL import (GL_ARRAY_BUFFER, GL_COLOR_BUFFER_BIT,
GL_COMPILE_STATUS, GL_FALSE, GL_FLOAT, GL_FRAGMENT_SHADER,
GL_LINK_STATUS, GL_RENDERER, GL_SHADING_LANGUAGE_VERSION,
GL_STATIC_DRAW, GL_TRIANGLES, GL_TRUE, GL_VENDOR, GL_VERSION,
GL_VERTEX_SHADER, glAttachShader, glBindBuffer, glBindVertexArray,
glBufferData, glClear, glClearColor, glCompileShader,
glCreateProgram, glCreateShader, glDeleteProgram,
glDeleteShader, glDrawArrays, glEnableVertexAttribArray,
glGenBuffers, glGenVertexArrays, glGetAttribLocation,
glGetProgramInfoLog, glGetProgramiv, glGetShaderInfoLog,
glGetShaderiv, glGetString, glGetUniformLocation, glLinkProgram,
glShaderSource, glUseProgram, glVertexAttribPointer)
import sys
vertex = """
#version 330
in vec3 vin_position;
in vec3 vin_color;
out vec3 vout_color;
void main(void)
{
vout_color = vin_color;
gl_Position = vec4(vin_position, 1.0);
}
"""
fragment = """
#version 330
in vec3 vout_color;
out vec4 fout_color;
void main(void)
{
fout_color = vec4(vout_color, 1.0);
}
"""
vertex_data = np.array([0.75, 0.75, 0.0,
0.75, -0.75, 0.0,
-0.75, -0.75, 0.0], dtype=np.float32)
color_data = np.array([1, 0, 0,
0, 1, 0,
0, 0, 1], dtype=np.float32)
class ShaderProgram(object):
""" Helper class for using GLSL shader programs
"""
def __init__(self, vertex, fragment):
"""
Parameters
----------
vertex : str
String containing shader source code for the vertex
shader
fragment : str
String containing shader source code for the fragment
shader
"""
self.program_id = glCreateProgram()
vs_id = self.add_shader(vertex, GL_VERTEX_SHADER)
frag_id = self.add_shader(fragment, GL_FRAGMENT_SHADER)
glAttachShader(self.program_id, vs_id)
glAttachShader(self.program_id, frag_id)
glLinkProgram(self.program_id)
if glGetProgramiv(self.program_id, GL_LINK_STATUS) != GL_TRUE:
info = glGetProgramInfoLog(self.program_id)
glDeleteProgram(self.program_id)
glDeleteShader(vs_id)
glDeleteShader(frag_id)
raise RuntimeError('Error linking program: %s' % (info))
glDeleteShader(vs_id)
glDeleteShader(frag_id)
def add_shader(self, source, shader_type):
""" Helper function for compiling a GLSL shader
Parameters
----------
source : str
String containing shader source code
shader_type : valid OpenGL shader type
Type of shader to compile
Returns
-------
value : int
Identifier for shader if compilation is successful
"""
try:
shader_id = glCreateShader(shader_type)
glShaderSource(shader_id, source)
glCompileShader(shader_id)
if glGetShaderiv(shader_id, GL_COMPILE_STATUS) != GL_TRUE:
info = glGetShaderInfoLog(shader_id)
raise RuntimeError('Shader compilation failed: %s' % (info))
return shader_id
except:
glDeleteShader(shader_id)
raise
def uniform_location(self, name):
""" Helper function to get location of an OpenGL uniform variable
Parameters
----------
name : str
Name of the variable for which location is to be returned
Returns
-------
value : int
Integer describing location
"""
return glGetUniformLocation(self.program_id, name)
def attribute_location(self, name):
""" Helper function to get location of an OpenGL attribute variable
Parameters
----------
name : str
Name of the variable for which location is to be returned
Returns
-------
value : int
Integer describing location
"""
return glGetAttribLocation(self.program_id, name)
def key_callback(key, action):
""" Sample keyboard callback function """
print 'Key: %s Action: %s pressed' % (key, action)
if __name__ == "__main__":
if not Init():
print 'GLFW initialization failed'
sys.exit(-1)
# These Window hints are used to specify
# which opengl version to use and other details
# for the opengl context that will be created
OpenWindowHint(OPENGL_VERSION_MAJOR, 3)
OpenWindowHint(OPENGL_VERSION_MINOR, 2)
OpenWindowHint(OPENGL_PROFILE, OPENGL_CORE_PROFILE)
OpenWindowHint(OPENGL_FORWARD_COMPAT, GL_TRUE)
if not OpenWindow(1400, 800, 0, 0, 0, 0, 32, 0, WINDOW):
print "OpenWindow failed"
Terminate()
sys.exit(-1)
# Every time a key on the keyboard is clicked
# call our callback function
SetKeyCallback(key_callback)
SetWindowTitle("Modern opengl example")
Enable(AUTO_POLL_EVENTS)
# If everything went well the following calls
# will display the version of opengl being used
print 'Vendor: %s' % (glGetString(GL_VENDOR))
print 'Opengl version: %s' % (glGetString(GL_VERSION))
print 'GLSL Version: %s' % (glGetString(GL_SHADING_LANGUAGE_VERSION))
print 'Renderer: %s' % (glGetString(GL_RENDERER))
glClearColor(0.95, 1.0, 0.95, 0)
# Lets compile our shaders since the use of shaders is now
# mandatory. We need at least a vertex and fragment shader
# begore we can draw anything
program = ShaderProgram(fragment=fragment, vertex=vertex)
# Lets create a VAO and bind it
# Think of VAO's as object that encapsulate buffer state
# Using a VAO enables you to cut down on calls in your draw
# loop which generally makes things run faster
vao_id = glGenVertexArrays(1)
glBindVertexArray(vao_id)
# Lets create our Vertex Buffer objects - these are the buffers
# that will contain our per vertex data
vbo_id = glGenBuffers(2)
# Bind a buffer before we can use it
glBindBuffer(GL_ARRAY_BUFFER, vbo_id[0])
# Now go ahead and fill this bound buffer with some data
glBufferData(GL_ARRAY_BUFFER, ArrayDatatype.arrayByteCount(vertex_data), vertex_data, GL_STATIC_DRAW)
# Now specify how the shader program will be receiving this data
# In this case the data from this buffer will be available in the shader as the vin_position vertex attribute
glVertexAttribPointer(program.attribute_location('vin_position'), 3, GL_FLOAT, GL_FALSE, 0, None)
# Turn on this vertex attribute in the shader
glEnableVertexAttribArray(0)
# Now do the same for the other vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, vbo_id[1])
glBufferData(GL_ARRAY_BUFFER, ArrayDatatype.arrayByteCount(color_data), color_data, GL_STATIC_DRAW)
glVertexAttribPointer(program.attribute_location('vin_color'), 3, GL_FLOAT, GL_FALSE, 0, None)
glEnableVertexAttribArray(1)
# Lets unbind our vbo and vao state
# We will bind these again in the draw loop
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindVertexArray(0)
running = True
while running:
glClear(GL_COLOR_BUFFER_BIT)
# Specify shader to be used
glUseProgram(program.program_id)
# Bind VAO - this will automatically
# bind all the vbo's saving us a bunch
# of calls
glBindVertexArray(vao_id)
# Modern GL makes the draw call really simple
# All the complexity has been pushed elsewhere
glDrawArrays(GL_TRIANGLES, 0, 3)
# Lets unbind the shader and vertex array state
glUseProgram(0)
glBindVertexArray(0)
# Now lets show our master piece on the screen
SwapBuffers()
# If the user has closed the window in anger
# then terminate this program
running = running and GetWindowParam(OPENED)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment