Mercurial > touhou
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)) |
