comparison pytouhou/ui/shader.pyx @ 424:f4d76d3d6f2a

Make the Shader class use cython too.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Tue, 16 Jul 2013 21:07:15 +0200
parents pytouhou/ui/shader.py@346614f788f1
children 878273a984c4
comparison
equal deleted inserted replaced
423:d8630c086926 424:f4d76d3d6f2a
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, GLint,
19 GLuint, GLchar, GLfloat, GLenum)
20
21 from libc.stdlib cimport malloc, free
22 from pytouhou.utils.matrix cimport Matrix, matrix_to_floats
23
24
25 class GLSLException(Exception):
26 pass
27
28
29 cdef class Shader:
30 cdef GLuint handle
31 cdef bint linked
32 cdef dict location_cache
33
34 # vert and frag take arrays of source strings the arrays will be
35 # concattenated into one string by OpenGL
36 def __init__(self, vert=None, frag=None):
37 # create the program handle
38 self.handle = glCreateProgram()
39 # we are not linked yet
40 self.linked = False
41
42 # cache the uniforms location
43 self.location_cache = {}
44
45 # create the vertex shader
46 self.create_shader(vert[0], GL_VERTEX_SHADER)
47 # create the fragment shader
48 self.create_shader(frag[0], GL_FRAGMENT_SHADER)
49
50 #TODO: put those elsewhere.
51 glBindAttribLocation(self.handle, 0, 'in_position')
52 glBindAttribLocation(self.handle, 1, 'in_texcoord')
53 glBindAttribLocation(self.handle, 2, 'in_color')
54
55 # attempt to link the program
56 self.link()
57
58 cdef void create_shader(self, const GLchar *string, GLenum shader_type):
59 cdef GLint temp
60 cdef const GLchar **strings = &string
61
62 # create the shader handle
63 shader = glCreateShader(shader_type)
64
65 # upload the source strings
66 glShaderSource(shader, 1, strings, NULL)
67
68 # compile the shader
69 glCompileShader(shader)
70
71 # retrieve the compile status
72 glGetShaderiv(shader, GL_COMPILE_STATUS, &temp)
73
74 # if compilation failed, print the log
75 if not temp:
76 # retrieve the log length
77 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &temp)
78 # create a buffer for the log
79 temp_buf = <GLchar*>malloc(temp * sizeof(GLchar))
80 # retrieve the log text
81 glGetShaderInfoLog(shader, temp, NULL, temp_buf)
82 buf = temp_buf[:temp]
83 free(temp_buf)
84 # print the log to the console
85 raise GLSLException(buf)
86 else:
87 # all is well, so attach the shader to the program
88 glAttachShader(self.handle, shader)
89
90 cdef void link(self):
91 cdef GLint temp
92
93 # link the program
94 glLinkProgram(self.handle)
95
96 # retrieve the link status
97 glGetProgramiv(self.handle, GL_LINK_STATUS, &temp)
98
99 # if linking failed, print the log
100 if not temp:
101 # retrieve the log length
102 glGetProgramiv(self.handle, GL_INFO_LOG_LENGTH, &temp)
103 # create a buffer for the log
104 temp_buf = <GLchar*>malloc(temp * sizeof(GLchar))
105 # retrieve the log text
106 glGetProgramInfoLog(self.handle, temp, NULL, temp_buf)
107 buf = temp_buf[:temp]
108 free(temp_buf)
109 # print the log to the console
110 raise GLSLException(buf)
111 else:
112 # all is well, so we are linked
113 self.linked = True
114
115 cdef GLint get_uniform_location(self, name):
116 if name not in self.location_cache:
117 loc = glGetUniformLocation(self.handle, name)
118 if loc == -1:
119 raise GLSLException('Undefined {} uniform.'.format(name))
120 self.location_cache[name] = loc
121 return self.location_cache[name]
122
123 def bind(self):
124 # bind the program
125 glUseProgram(self.handle)
126
127 # upload a floating point uniform
128 # this program must be currently bound
129 def uniform_1(self, name, GLfloat val):
130 glUniform1fv(self.get_uniform_location(name), 1, &val)
131
132 # upload a vec4 uniform
133 def uniform_4(self, name, GLfloat a, GLfloat b, GLfloat c, GLfloat d):
134 cdef GLfloat vals[4]
135 vals[0] = a
136 vals[1] = b
137 vals[2] = c
138 vals[3] = d
139 glUniform4fv(self.get_uniform_location(name), 1, vals)
140
141 # upload a uniform matrix
142 # works with matrices stored as lists,
143 # as well as euclid matrices
144 def uniform_matrix(self, name, Matrix mat):
145 # obtain the uniform location
146 loc = self.get_uniform_location(name)
147 # uplaod the 4x4 floating point matrix
148 glUniformMatrix4fv(loc, 1, False, matrix_to_floats(mat))