Skip to content

Instantly share code, notes, and snippets.

@hurricanerix
Last active May 28, 2023 21:59
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save hurricanerix/3be8221128d943ae2827 to your computer and use it in GitHub Desktop.
Save hurricanerix/3be8221128d943ae2827 to your computer and use it in GitHub Desktop.
Simple python app setting up SDL2 & OpenGL.
#!/usr/bin/env python
# The MIT License (MIT)
#
# Copyright (c) 2014 Richard Hawkins
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import ctypes
import numpy
import sys
import sdl2
from gameobjects.matrix44 import Matrix44
from OpenGL import GL as gl
from OpenGL.GL import shaders
WINDOW_WIDTH = 1024
WINDOW_HEIGHT = 768
VERT_SOURCE = """
#version 330
uniform mat4 model_matrix;
uniform mat4 view_matrix;
uniform mat4 proj_matrix;
in vec4 mc_vertex;
void main()
{
mat4 mv_matrix = view_matrix * model_matrix;
vec4 cc_vertex = mv_matrix * mc_vertex;
gl_Position = proj_matrix * cc_vertex;
}"""
FRAG_SOURCE = """
#version 330
out vec4 frag_color;
void main()
{
frag_color = vec4(1.0, 0.0, 0.0, 1.0);
}"""
VERTICES = [0.0, 0.0, 0.0, 1.0,
1.0, 0.0, 0.0, 1.0,
1.0, 1.0, 0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
0.0, 0.0, 0.0, 1.0,
1.0, 1.0, 0.0, 1.0]
VERTICES = numpy.array(VERTICES, dtype=numpy.float32)
def get_4x4_transform(scale_x, scale_y, trans_x, trans_y, trans_z):
"""Transform the from local coordinates to world coordinates.
@return: transformation matrix used to transform from local coords
to world coords.
@rtype: Matrix44
"""
transform = Matrix44()
transform.set_row(0, [scale_x, 0.0, 0.0, trans_x])
transform.set_row(1, [0.0, scale_y, 0.0, trans_y])
transform.set_row(2, [0.0, 0.0, 1.0, trans_z])
transform.set_row(3, [0.0, 0.0, 0.0, 1.0])
return transform.to_opengl()
def _get_projection_matrix(left, right, bottom, top):
"""Create a orthographic projection matrix.
U{Modern glOrtho2d<http://stackoverflow.com/questions/21323743/
modern-equivalent-of-gluortho2d>}
U{Orthographic Projection<http://en.wikipedia.org/wiki/
Orthographic_projection_(geometry)>}
@param left: position of the left side of the display
@type left: int
@param right: position of the right side of the display
@type right: int
@param bottom: position of the bottom side of the display
@type bottom: int
@param top: position of the top side of the display
@type top: int
@return: orthographic projection matrix
@rtype: Matrix44
"""
zNear = -25.0
zFar = 25.0
inv_z = 1.0 / (zFar - zNear)
inv_y = 1.0 / (top - bottom)
inv_x = 1.0 / (right - left)
mat = Matrix44()
mat.set_row(0, [(2.0 * inv_x), 0.0, 0.0, (-(right + left) * inv_x)])
mat.set_row(1, [0.0, (2.0 * inv_y), 0.0, (-(top + bottom) * inv_y)])
mat.set_row(2, [0.0, 0.0, (-2.0 * inv_z), (-(zFar + zNear) * inv_z)])
mat.set_row(3, [0.0, 0.0, 0.0, 1.0])
return mat.to_opengl()
def _get_view_matrix(x, y):
scale_x = 1.0
scale_y = 1.0
trans_x = x
trans_y = y
layer = 1.0
return get_4x4_transform(scale_x, scale_y, trans_x, trans_y, layer)
if __name__ == "__main__":
# Init
sdl2.SDL_Init(sdl2.SDL_INIT_EVERYTHING)
sdl2.SDL_GL_SetAttribute(sdl2.SDL_GL_CONTEXT_MAJOR_VERSION, 3)
sdl2.SDL_GL_SetAttribute(sdl2.SDL_GL_CONTEXT_MINOR_VERSION, 2)
sdl2.SDL_GL_SetAttribute(sdl2.SDL_GL_CONTEXT_PROFILE_MASK,
sdl2.SDL_GL_CONTEXT_PROFILE_CORE)
sdl2.SDL_GL_SetAttribute(sdl2.SDL_GL_DOUBLEBUFFER, 1)
sdl2.SDL_GL_SetAttribute(sdl2.SDL_GL_DEPTH_SIZE, 24)
sdl2.SDL_GL_SetSwapInterval(1)
window = sdl2.SDL_CreateWindow(
"Python/SDL2/OpenGL", sdl2.SDL_WINDOWPOS_CENTERED,
sdl2.SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT,
sdl2.SDL_WINDOW_OPENGL | sdl2.SDL_WINDOW_SHOWN)
if not window:
sys.stderr.write("Error: Could not create window\n")
exit(1)
glcontext = sdl2.SDL_GL_CreateContext(window)
gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
gl.glEnable(gl.GL_DEPTH_TEST)
gl.glEnable(gl.GL_CULL_FACE)
gl.glEnable(gl.GL_BLEND)
gl.glClearColor(0.3, 0.3, 0.3, 1.0)
# Load Shader
attrib_locs = {
"mc_vertex": -1,
}
uniform_locs = {
"model_matrix": -1,
"view_matrix": -1,
"proj_matrix": -1,
}
vert_prog = shaders.compileShader(VERT_SOURCE, gl.GL_VERTEX_SHADER)
if not gl.glGetShaderiv(vert_prog, gl.GL_COMPILE_STATUS):
sys.stderr.write("Error: Could not compile vertex shader.\n")
exit(2)
frag_prog = shaders.compileShader(FRAG_SOURCE, gl.GL_FRAGMENT_SHADER)
if not gl.glGetShaderiv(frag_prog, gl.GL_COMPILE_STATUS):
sys.stderr.write("Error: Could not compile fragment shader.\n")
exit(3)
shader = gl.glCreateProgram()
gl.glAttachShader(shader, vert_prog)
gl.glAttachShader(shader, frag_prog)
gl.glLinkProgram(shader)
if gl.glGetProgramiv(shader, gl.GL_LINK_STATUS) != gl.GL_TRUE:
sys.stderr.write("Error: {0}\n".format(gl.glGetProgramInfoLog(shader)))
exit(4)
for name in ['mc_vertex']:
attrib_locs[name] = gl.glGetAttribLocation(shader, name)
for name in ['model_matrix', 'view_matrix', 'proj_matrix']:
uniform_locs[name] = gl.glGetUniformLocation(shader, name)
# Load Object
vao = gl.glGenVertexArrays(1)
gl.glBindVertexArray(vao)
vertex_buffer = gl.glGenBuffers(1)
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vertex_buffer)
gl.glBufferData(gl.GL_ARRAY_BUFFER, len(VERTICES) * 4, VERTICES,
gl.GL_STATIC_DRAW)
gl.glVertexAttribPointer(attrib_locs['mc_vertex'], 4, gl.GL_FLOAT, False,
0, ctypes.c_void_p(0))
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)
gl.glBindVertexArray(0)
# Loop
running = True
event = sdl2.SDL_Event()
while running:
while sdl2.SDL_PollEvent(ctypes.byref(event)) != 0:
if event.type == sdl2.SDL_QUIT:
running = False
if event.type == sdl2.events.SDL_KEYDOWN:
print("SDL_KEYDOWN")
if event.key.keysym.sym == sdl2.SDLK_ESCAPE:
running = False
if (event.type == sdl2.SDL_MOUSEMOTION):
print("SDL_MOUSEMOTION")
if (event.type == sdl2.SDL_MOUSEBUTTONDOWN):
print("SDL_MOUSEBUTTONDOWN")
# Update model_matrix
object_w = 100
object_h = 100
object_x = WINDOW_WIDTH / 2 - object_w / 2
object_y = WINDOW_HEIGHT / 2 - object_h / 2
model_matrix = get_4x4_transform(scale_x=object_w, scale_y=object_h,
trans_x=object_x, trans_y=object_y,
trans_z=1.0)
# Update proj_matrix
proj_matrix = _get_projection_matrix(0.0, WINDOW_WIDTH,
0.0, WINDOW_HEIGHT)
# Update view_matrix
view_matrix = _get_view_matrix(1.0, 1.0)
# Start Rendering
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
gl.glUseProgram(shader)
# Draw object
gl.glBindVertexArray(vao)
gl.glEnableVertexAttribArray(attrib_locs['mc_vertex'])
gl.glUniformMatrix4fv(uniform_locs['model_matrix'], 1, gl.GL_TRUE,
model_matrix)
gl.glUniformMatrix4fv(uniform_locs['view_matrix'], 1, gl.GL_TRUE,
view_matrix)
gl.glUniformMatrix4fv(uniform_locs['proj_matrix'], 1, gl.GL_TRUE,
proj_matrix)
gl.glDrawArrays(gl.GL_TRIANGLES, 0, int(len(VERTICES) / 4.0))
gl.glBindVertexArray(0)
# Stop Rendering
gl.glUseProgram(0)
sdl2.SDL_GL_SwapWindow(window)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment