Mercurial > touhou
comparison pytouhou/ui/shader.py @ 370:74471afbac37
Add a programmable pipeline renderer, and a --fixed-pipeline switch to use the old one.
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Fri, 27 Jul 2012 18:43:48 +0200 |
parents | |
children | 0537af9125a7 |
comparison
equal
deleted
inserted
replaced
369:f305cdd6f6c5 | 370:74471afbac37 |
---|---|
1 # | |
2 # Copyright Tristam Macdonald 2008. | |
3 # Copyright Emmanuel Gil Peyrot 2012. | |
4 # | |
5 # Distributed under the Boost Software License, Version 1.0 | |
6 # (see http://www.boost.org/LICENSE_1_0.txt) | |
7 # | |
8 # Source: https://swiftcoder.wordpress.com/2008/12/19/simple-glsl-wrapper-for-pyglet/ | |
9 # | |
10 | |
11 from pyglet.gl import * | |
12 | |
13 | |
14 class GLSLException(Exception): | |
15 pass | |
16 | |
17 | |
18 class Shader(object): | |
19 # vert and frag take arrays of source strings the arrays will be | |
20 # concattenated into one string by OpenGL | |
21 def __init__(self, vert=None, frag=None): | |
22 # create the program handle | |
23 self.handle = glCreateProgram() | |
24 # we are not linked yet | |
25 self.linked = False | |
26 | |
27 # cache the uniforms location | |
28 self.location_cache = {} | |
29 | |
30 # create the vertex shader | |
31 self.createShader(vert, GL_VERTEX_SHADER) | |
32 # create the fragment shader | |
33 self.createShader(frag, GL_FRAGMENT_SHADER) | |
34 | |
35 # attempt to link the program | |
36 self.link() | |
37 | |
38 def load_source(self, path): | |
39 with open(path, 'rb') as file: | |
40 source = file.read() | |
41 return source | |
42 | |
43 def createShader(self, strings, type): | |
44 count = len(strings) | |
45 # if we have no source code, ignore this shader | |
46 if count < 1: | |
47 return | |
48 | |
49 # create the shader handle | |
50 shader = glCreateShader(type) | |
51 | |
52 # convert the source strings into a ctypes pointer-to-char array, and upload them | |
53 # this is deep, dark, dangerous black magick - don't try stuff like this at home! | |
54 src = (c_char_p * count)(*strings) | |
55 glShaderSource(shader, count, cast(byref(src), POINTER(POINTER(c_char))), None) | |
56 | |
57 # compile the shader | |
58 glCompileShader(shader) | |
59 | |
60 temp = c_int(0) | |
61 # retrieve the compile status | |
62 glGetShaderiv(shader, GL_COMPILE_STATUS, byref(temp)) | |
63 | |
64 # if compilation failed, print the log | |
65 if not temp: | |
66 # retrieve the log length | |
67 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, byref(temp)) | |
68 # create a buffer for the log | |
69 buffer = create_string_buffer(temp.value) | |
70 # retrieve the log text | |
71 glGetShaderInfoLog(shader, temp, None, buffer) | |
72 # print the log to the console | |
73 raise GLSLException(buffer.value) | |
74 else: | |
75 # all is well, so attach the shader to the program | |
76 glAttachShader(self.handle, shader); | |
77 | |
78 def link(self): | |
79 # link the program | |
80 glLinkProgram(self.handle) | |
81 | |
82 temp = c_int(0) | |
83 # retrieve the link status | |
84 glGetProgramiv(self.handle, GL_LINK_STATUS, byref(temp)) | |
85 | |
86 # if linking failed, print the log | |
87 if not temp: | |
88 # retrieve the log length | |
89 glGetProgramiv(self.handle, GL_INFO_LOG_LENGTH, byref(temp)) | |
90 # create a buffer for the log | |
91 buffer = create_string_buffer(temp.value) | |
92 # retrieve the log text | |
93 glGetProgramInfoLog(self.handle, temp, None, buffer) | |
94 # print the log to the console | |
95 raise GLSLException(buffer.value) | |
96 else: | |
97 # all is well, so we are linked | |
98 self.linked = True | |
99 | |
100 def bind(self): | |
101 # bind the program | |
102 glUseProgram(self.handle) | |
103 | |
104 @classmethod | |
105 def unbind(self): | |
106 # unbind whatever program is currently bound | |
107 glUseProgram(0) | |
108 | |
109 def get_uniform_location(self, name): | |
110 try: | |
111 return self.location_cache[name] | |
112 except KeyError: | |
113 loc = glGetUniformLocation(self.handle, name) | |
114 if loc == -1: | |
115 raise GLSLException #TODO | |
116 self.location_cache[name] = loc | |
117 return loc | |
118 | |
119 # upload a floating point uniform | |
120 # this program must be currently bound | |
121 def uniformf(self, name, *vals): | |
122 # check there are 1-4 values | |
123 if len(vals) in range(1, 5): | |
124 # select the correct function | |
125 { 1 : glUniform1f, | |
126 2 : glUniform2f, | |
127 3 : glUniform3f, | |
128 4 : glUniform4f | |
129 # retrieve the uniform location, and set | |
130 }[len(vals)](self.get_uniform_location(name), *vals) | |
131 | |
132 # upload an integer uniform | |
133 # this program must be currently bound | |
134 def uniformi(self, name, *vals): | |
135 # check there are 1-4 values | |
136 if len(vals) in range(1, 5): | |
137 # select the correct function | |
138 { 1 : glUniform1i, | |
139 2 : glUniform2i, | |
140 3 : glUniform3i, | |
141 4 : glUniform4i | |
142 # retrieve the uniform location, and set | |
143 }[len(vals)](self.get_uniform_location(name), *vals) | |
144 | |
145 # upload a uniform matrix | |
146 # works with matrices stored as lists, | |
147 # as well as euclid matrices | |
148 def uniform_matrixf(self, name, mat): | |
149 # obtian the uniform location | |
150 loc = self.get_uniform_location(name) | |
151 # uplaod the 4x4 floating point matrix | |
152 glUniformMatrix4fv(loc, 1, False, mat) | |
153 |