comparison pytouhou/ui/opengl/shader.pyx @ 513:5e3e0b09a531

Move the OpenGL backend to its own package.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Thu, 05 Dec 2013 02:16:31 +0100
parents pytouhou/ui/shader.pyx@1b56d62250ab
children 6e3b3d5d4691
comparison
equal deleted inserted replaced
512:b39ad30c6620 513:5e3e0b09a531
1 # -*- encoding: utf-8 -*-
2 #
3 # Copyright Tristam Macdonald 2008.
4 # Copyright Emmanuel Gil Peyrot 2012.
5 #
6 # Distributed under the Boost Software License, Version 1.0
7 # (see http://www.boost.org/LICENSE_1_0.txt)
8 #
9 # Source: https://swiftcoder.wordpress.com/2008/12/19/simple-glsl-wrapper-for-pyglet/
10 #
11
12 from pytouhou.lib.opengl cimport \
13 (glCreateProgram, glCreateShader, GL_VERTEX_SHADER,
14 GL_FRAGMENT_SHADER, glShaderSource, glCompileShader, glGetShaderiv,
15 GL_COMPILE_STATUS, GL_INFO_LOG_LENGTH, glGetShaderInfoLog,
16 glAttachShader, glLinkProgram, glGetProgramiv, glGetProgramInfoLog,
17 GL_LINK_STATUS, glUseProgram, glGetUniformLocation, glUniform1fv,
18 glUniform4fv, glUniformMatrix4fv, glBindAttribLocation)
19
20 from libc.stdlib cimport malloc, free
21
22
23 class GLSLException(Exception):
24 pass
25
26
27 cdef class Shader:
28 # vert and frag take arrays of source strings the arrays will be
29 # concattenated into one string by OpenGL
30 def __init__(self, vert=None, frag=None):
31 # create the program handle
32 self.handle = glCreateProgram()
33 # we are not linked yet
34 self.linked = False
35
36 # cache the uniforms location
37 self.location_cache = {}
38
39 # create the vertex shader
40 self.create_shader(vert[0], GL_VERTEX_SHADER)
41 # create the fragment shader
42 self.create_shader(frag[0], GL_FRAGMENT_SHADER)
43
44 #TODO: put those elsewhere.
45 glBindAttribLocation(self.handle, 0, 'in_position')
46 glBindAttribLocation(self.handle, 1, 'in_texcoord')
47 glBindAttribLocation(self.handle, 2, 'in_color')
48
49 # attempt to link the program
50 self.link()
51
52 cdef void create_shader(self, const GLchar *string, GLenum shader_type):
53 cdef GLint temp
54 cdef const GLchar **strings = &string
55
56 # create the shader handle
57 shader = glCreateShader(shader_type)
58
59 # upload the source strings
60 glShaderSource(shader, 1, strings, NULL)
61
62 # compile the shader
63 glCompileShader(shader)
64
65 # retrieve the compile status
66 glGetShaderiv(shader, GL_COMPILE_STATUS, &temp)
67
68 # if compilation failed, print the log
69 if not temp:
70 # retrieve the log length
71 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &temp)
72 # create a buffer for the log
73 temp_buf = <GLchar*>malloc(temp * sizeof(GLchar))
74 # retrieve the log text
75 glGetShaderInfoLog(shader, temp, NULL, temp_buf)
76 buf = temp_buf[:temp]
77 free(temp_buf)
78 # print the log to the console
79 raise GLSLException(buf)
80 else:
81 # all is well, so attach the shader to the program
82 glAttachShader(self.handle, shader)
83
84 cdef void link(self):
85 cdef GLint temp
86
87 # link the program
88 glLinkProgram(self.handle)
89
90 # retrieve the link status
91 glGetProgramiv(self.handle, GL_LINK_STATUS, &temp)
92
93 # if linking failed, print the log
94 if not temp:
95 # retrieve the log length
96 glGetProgramiv(self.handle, GL_INFO_LOG_LENGTH, &temp)
97 # create a buffer for the log
98 temp_buf = <GLchar*>malloc(temp * sizeof(GLchar))
99 # retrieve the log text
100 glGetProgramInfoLog(self.handle, temp, NULL, temp_buf)
101 buf = temp_buf[:temp]
102 free(temp_buf)
103 # print the log to the console
104 raise GLSLException(buf)
105 else:
106 # all is well, so we are linked
107 self.linked = True
108
109 cdef GLint get_uniform_location(self, name):
110 if name not in self.location_cache:
111 loc = glGetUniformLocation(self.handle, name)
112 if loc == -1:
113 raise GLSLException('Undefined {} uniform.'.format(name))
114 self.location_cache[name] = loc
115 return self.location_cache[name]
116
117 cdef void bind(self) nogil:
118 # bind the program
119 glUseProgram(self.handle)
120
121 # upload a floating point uniform
122 # this program must be currently bound
123 cdef void uniform_1(self, name, GLfloat val):
124 glUniform1fv(self.get_uniform_location(name), 1, &val)
125
126 # upload a vec4 uniform
127 cdef void uniform_4(self, name, GLfloat a, GLfloat b, GLfloat c, GLfloat d):
128 cdef GLfloat vals[4]
129 vals[0] = a
130 vals[1] = b
131 vals[2] = c
132 vals[3] = d
133 glUniform4fv(self.get_uniform_location(name), 1, vals)
134
135 # upload a uniform matrix
136 # works with matrices stored as lists,
137 # as well as euclid matrices
138 cdef void uniform_matrix(self, name, Matrix mat):
139 # obtain the uniform location
140 loc = self.get_uniform_location(name)
141 # uplaod the 4x4 floating point matrix
142 glUniformMatrix4fv(loc, 1, False, mat.data)