rev |
line source |
nuclear@2
|
1 #include <stdio.h>
|
nuclear@2
|
2 #include <stdlib.h>
|
nuclear@2
|
3 #include <string.h>
|
nuclear@2
|
4 #include <errno.h>
|
nuclear@24
|
5 #include <stdarg.h>
|
nuclear@2
|
6 #include <assert.h>
|
nuclear@2
|
7 #include "opengl.h"
|
nuclear@24
|
8 #include "assman.h"
|
nuclear@2
|
9
|
nuclear@2
|
10 #if defined(unix) || defined(__unix__)
|
nuclear@2
|
11 #include <unistd.h>
|
nuclear@2
|
12 #include <sys/stat.h>
|
nuclear@2
|
13 #endif /* unix */
|
nuclear@2
|
14
|
nuclear@2
|
15 #include "sdr.h"
|
nuclear@2
|
16
|
nuclear@24
|
17 static const char *sdrtypestr(unsigned int sdrtype);
|
nuclear@2
|
18
|
nuclear@2
|
19 unsigned int create_vertex_shader(const char *src)
|
nuclear@2
|
20 {
|
nuclear@2
|
21 return create_shader(src, GL_VERTEX_SHADER);
|
nuclear@2
|
22 }
|
nuclear@2
|
23
|
nuclear@2
|
24 unsigned int create_pixel_shader(const char *src)
|
nuclear@2
|
25 {
|
nuclear@2
|
26 return create_shader(src, GL_FRAGMENT_SHADER);
|
nuclear@2
|
27 }
|
nuclear@2
|
28
|
nuclear@24
|
29 unsigned int create_tessctl_shader(const char *src)
|
nuclear@24
|
30 {
|
nuclear@24
|
31 #ifdef GL_TESS_CONTROL_SHADER
|
nuclear@24
|
32 return create_shader(src, GL_TESS_CONTROL_SHADER);
|
nuclear@24
|
33 #else
|
nuclear@24
|
34 return 0;
|
nuclear@24
|
35 #endif
|
nuclear@24
|
36 }
|
nuclear@24
|
37
|
nuclear@24
|
38 unsigned int create_tesseval_shader(const char *src)
|
nuclear@24
|
39 {
|
nuclear@24
|
40 #ifdef GL_TESS_EVALUATION_SHADER
|
nuclear@24
|
41 return create_shader(src, GL_TESS_EVALUATION_SHADER);
|
nuclear@24
|
42 #else
|
nuclear@24
|
43 return 0;
|
nuclear@24
|
44 #endif
|
nuclear@24
|
45 }
|
nuclear@24
|
46
|
nuclear@24
|
47 unsigned int create_geometry_shader(const char *src)
|
nuclear@24
|
48 {
|
nuclear@24
|
49 #ifdef GL_GEOMETRY_SHADER
|
nuclear@24
|
50 return create_shader(src, GL_GEOMETRY_SHADER);
|
nuclear@24
|
51 #else
|
nuclear@24
|
52 return 0;
|
nuclear@24
|
53 #endif
|
nuclear@24
|
54 }
|
nuclear@24
|
55
|
nuclear@2
|
56 unsigned int create_shader(const char *src, unsigned int sdr_type)
|
nuclear@2
|
57 {
|
nuclear@2
|
58 unsigned int sdr;
|
nuclear@2
|
59 int success, info_len;
|
nuclear@2
|
60 char *info_str = 0;
|
nuclear@2
|
61 GLenum err;
|
nuclear@2
|
62
|
nuclear@2
|
63 sdr = glCreateShader(sdr_type);
|
nuclear@2
|
64 assert(glGetError() == GL_NO_ERROR);
|
nuclear@2
|
65 glShaderSource(sdr, 1, &src, 0);
|
nuclear@2
|
66 err = glGetError();
|
nuclear@2
|
67 assert(err == GL_NO_ERROR);
|
nuclear@2
|
68 glCompileShader(sdr);
|
nuclear@2
|
69 assert(glGetError() == GL_NO_ERROR);
|
nuclear@2
|
70
|
nuclear@2
|
71 glGetShaderiv(sdr, GL_COMPILE_STATUS, &success);
|
nuclear@2
|
72 assert(glGetError() == GL_NO_ERROR);
|
nuclear@2
|
73 glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len);
|
nuclear@2
|
74 assert(glGetError() == GL_NO_ERROR);
|
nuclear@2
|
75
|
nuclear@2
|
76 if(info_len) {
|
nuclear@2
|
77 if((info_str = malloc(info_len + 1))) {
|
nuclear@2
|
78 glGetShaderInfoLog(sdr, info_len, 0, info_str);
|
nuclear@2
|
79 assert(glGetError() == GL_NO_ERROR);
|
nuclear@24
|
80 info_str[info_len] = 0;
|
nuclear@2
|
81 }
|
nuclear@2
|
82 }
|
nuclear@2
|
83
|
nuclear@2
|
84 if(success) {
|
nuclear@2
|
85 fprintf(stderr, info_str ? "done: %s\n" : "done\n", info_str);
|
nuclear@2
|
86 } else {
|
nuclear@2
|
87 fprintf(stderr, info_str ? "failed: %s\n" : "failed\n", info_str);
|
nuclear@2
|
88 glDeleteShader(sdr);
|
nuclear@2
|
89 sdr = 0;
|
nuclear@2
|
90 }
|
nuclear@2
|
91
|
nuclear@2
|
92 free(info_str);
|
nuclear@2
|
93 return sdr;
|
nuclear@2
|
94 }
|
nuclear@2
|
95
|
nuclear@2
|
96 void free_shader(unsigned int sdr)
|
nuclear@2
|
97 {
|
nuclear@2
|
98 glDeleteShader(sdr);
|
nuclear@2
|
99 }
|
nuclear@2
|
100
|
nuclear@2
|
101 unsigned int load_vertex_shader(const char *fname)
|
nuclear@2
|
102 {
|
nuclear@2
|
103 return load_shader(fname, GL_VERTEX_SHADER);
|
nuclear@2
|
104 }
|
nuclear@2
|
105
|
nuclear@2
|
106 unsigned int load_pixel_shader(const char *fname)
|
nuclear@2
|
107 {
|
nuclear@2
|
108 return load_shader(fname, GL_FRAGMENT_SHADER);
|
nuclear@2
|
109 }
|
nuclear@2
|
110
|
nuclear@24
|
111 unsigned int load_tessctl_shader(const char *fname)
|
nuclear@24
|
112 {
|
nuclear@24
|
113 #ifdef GL_TESS_CONTROL_SHADER
|
nuclear@24
|
114 return load_shader(fname, GL_TESS_CONTROL_SHADER);
|
nuclear@24
|
115 #else
|
nuclear@24
|
116 return 0;
|
nuclear@24
|
117 #endif
|
nuclear@24
|
118 }
|
nuclear@24
|
119
|
nuclear@24
|
120 unsigned int load_tesseval_shader(const char *fname)
|
nuclear@24
|
121 {
|
nuclear@24
|
122 #ifdef GL_TESS_EVALUATION_SHADER
|
nuclear@24
|
123 return load_shader(fname, GL_TESS_EVALUATION_SHADER);
|
nuclear@24
|
124 #else
|
nuclear@24
|
125 return 0;
|
nuclear@24
|
126 #endif
|
nuclear@24
|
127 }
|
nuclear@24
|
128
|
nuclear@24
|
129 unsigned int load_geometry_shader(const char *fname)
|
nuclear@24
|
130 {
|
nuclear@24
|
131 #ifdef GL_GEOMETRY_SHADER
|
nuclear@24
|
132 return load_shader(fname, GL_GEOMETRY_SHADER);
|
nuclear@24
|
133 #else
|
nuclear@24
|
134 return 0;
|
nuclear@24
|
135 #endif
|
nuclear@24
|
136 }
|
nuclear@24
|
137
|
nuclear@2
|
138 unsigned int load_shader(const char *fname, unsigned int sdr_type)
|
nuclear@2
|
139 {
|
nuclear@2
|
140 unsigned int sdr;
|
nuclear@2
|
141 size_t filesize;
|
nuclear@24
|
142 ass_file *fp;
|
nuclear@2
|
143 char *src;
|
nuclear@2
|
144
|
nuclear@24
|
145 if(!(fp = ass_fopen(fname, "rb"))) {
|
nuclear@2
|
146 fprintf(stderr, "failed to open shader %s: %s\n", fname, strerror(errno));
|
nuclear@2
|
147 return 0;
|
nuclear@2
|
148 }
|
nuclear@2
|
149
|
nuclear@24
|
150 filesize = ass_fseek(fp, 0, SEEK_END);
|
nuclear@24
|
151 /*filesize = ass_ftell(fp);*/
|
nuclear@24
|
152 ass_fseek(fp, 0, SEEK_SET);
|
nuclear@2
|
153
|
nuclear@2
|
154 if(!(src = malloc(filesize + 1))) {
|
nuclear@24
|
155 ass_fclose(fp);
|
nuclear@2
|
156 return 0;
|
nuclear@2
|
157 }
|
nuclear@24
|
158 ass_fread(src, 1, filesize, fp);
|
nuclear@2
|
159 src[filesize] = 0;
|
nuclear@24
|
160 ass_fclose(fp);
|
nuclear@2
|
161
|
nuclear@24
|
162 fprintf(stderr, "compiling %s shader: %s... ", sdrtypestr(sdr_type), fname);
|
nuclear@2
|
163 sdr = create_shader(src, sdr_type);
|
nuclear@2
|
164
|
nuclear@2
|
165 free(src);
|
nuclear@2
|
166 return sdr;
|
nuclear@2
|
167 }
|
nuclear@2
|
168
|
nuclear@2
|
169
|
nuclear@2
|
170 /* ---- gpu programs ---- */
|
nuclear@2
|
171
|
nuclear@2
|
172 unsigned int create_program(void)
|
nuclear@2
|
173 {
|
nuclear@2
|
174 unsigned int prog = glCreateProgram();
|
nuclear@2
|
175 assert(glGetError() == GL_NO_ERROR);
|
nuclear@2
|
176 return prog;
|
nuclear@2
|
177 }
|
nuclear@2
|
178
|
nuclear@24
|
179 unsigned int create_program_link(unsigned int sdr0, ...)
|
nuclear@2
|
180 {
|
nuclear@24
|
181 unsigned int prog, sdr;
|
nuclear@24
|
182 va_list ap;
|
nuclear@2
|
183
|
nuclear@2
|
184 if(!(prog = create_program())) {
|
nuclear@2
|
185 return 0;
|
nuclear@2
|
186 }
|
nuclear@2
|
187
|
nuclear@24
|
188 attach_shader(prog, sdr0);
|
nuclear@24
|
189 if(glGetError()) {
|
nuclear@24
|
190 return 0;
|
nuclear@24
|
191 }
|
nuclear@24
|
192
|
nuclear@24
|
193 va_start(ap, sdr0);
|
nuclear@24
|
194 while((sdr = va_arg(ap, unsigned int))) {
|
nuclear@24
|
195 attach_shader(prog, sdr);
|
nuclear@24
|
196 if(glGetError()) {
|
nuclear@24
|
197 return 0;
|
nuclear@24
|
198 }
|
nuclear@24
|
199 }
|
nuclear@24
|
200 va_end(ap);
|
nuclear@2
|
201
|
nuclear@2
|
202 if(link_program(prog) == -1) {
|
nuclear@2
|
203 free_program(prog);
|
nuclear@2
|
204 return 0;
|
nuclear@2
|
205 }
|
nuclear@2
|
206 return prog;
|
nuclear@2
|
207 }
|
nuclear@2
|
208
|
nuclear@2
|
209 unsigned int create_program_load(const char *vfile, const char *pfile)
|
nuclear@2
|
210 {
|
nuclear@24
|
211 unsigned int vs = 0, ps = 0;
|
nuclear@2
|
212
|
nuclear@24
|
213 if(vfile && *vfile && !(vs = load_vertex_shader(vfile))) {
|
nuclear@2
|
214 return 0;
|
nuclear@2
|
215 }
|
nuclear@24
|
216 if(pfile && *pfile && !(ps = load_pixel_shader(pfile))) {
|
nuclear@24
|
217 return 0;
|
nuclear@24
|
218 }
|
nuclear@24
|
219 return create_program_link(vs, ps, 0);
|
nuclear@2
|
220 }
|
nuclear@2
|
221
|
nuclear@2
|
222 void free_program(unsigned int sdr)
|
nuclear@2
|
223 {
|
nuclear@2
|
224 glDeleteProgram(sdr);
|
nuclear@2
|
225 }
|
nuclear@2
|
226
|
nuclear@2
|
227 void attach_shader(unsigned int prog, unsigned int sdr)
|
nuclear@2
|
228 {
|
nuclear@24
|
229 int err;
|
nuclear@24
|
230
|
nuclear@24
|
231 if(prog && sdr) {
|
nuclear@24
|
232 assert(glGetError() == GL_NO_ERROR);
|
nuclear@24
|
233 glAttachShader(prog, sdr);
|
nuclear@24
|
234 if((err = glGetError()) != GL_NO_ERROR) {
|
nuclear@24
|
235 fprintf(stderr, "failed to attach shader %u to program %u (err: 0x%x)\n", sdr, prog, err);
|
nuclear@24
|
236 abort();
|
nuclear@24
|
237 }
|
nuclear@24
|
238 }
|
nuclear@2
|
239 }
|
nuclear@2
|
240
|
nuclear@2
|
241 int link_program(unsigned int prog)
|
nuclear@2
|
242 {
|
nuclear@2
|
243 int linked, info_len, retval = 0;
|
nuclear@2
|
244 char *info_str = 0;
|
nuclear@2
|
245
|
nuclear@2
|
246 glLinkProgram(prog);
|
nuclear@2
|
247 assert(glGetError() == GL_NO_ERROR);
|
nuclear@2
|
248 glGetProgramiv(prog, GL_LINK_STATUS, &linked);
|
nuclear@2
|
249 assert(glGetError() == GL_NO_ERROR);
|
nuclear@2
|
250 glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &info_len);
|
nuclear@2
|
251 assert(glGetError() == GL_NO_ERROR);
|
nuclear@2
|
252
|
nuclear@2
|
253 if(info_len) {
|
nuclear@2
|
254 if((info_str = malloc(info_len + 1))) {
|
nuclear@2
|
255 glGetProgramInfoLog(prog, info_len, 0, info_str);
|
nuclear@2
|
256 assert(glGetError() == GL_NO_ERROR);
|
nuclear@24
|
257 info_str[info_len] = 0;
|
nuclear@2
|
258 }
|
nuclear@2
|
259 }
|
nuclear@2
|
260
|
nuclear@2
|
261 if(linked) {
|
nuclear@2
|
262 fprintf(stderr, info_str ? "linking done: %s\n" : "linking done\n", info_str);
|
nuclear@2
|
263 } else {
|
nuclear@2
|
264 fprintf(stderr, info_str ? "linking failed: %s\n" : "linking failed\n", info_str);
|
nuclear@2
|
265 retval = -1;
|
nuclear@2
|
266 }
|
nuclear@2
|
267
|
nuclear@2
|
268 free(info_str);
|
nuclear@2
|
269 return retval;
|
nuclear@2
|
270 }
|
nuclear@2
|
271
|
nuclear@2
|
272 int bind_program(unsigned int prog)
|
nuclear@2
|
273 {
|
nuclear@2
|
274 GLenum err;
|
nuclear@2
|
275
|
nuclear@2
|
276 glUseProgram(prog);
|
nuclear@2
|
277 if(prog && (err = glGetError()) != GL_NO_ERROR) {
|
nuclear@2
|
278 /* maybe the program is not linked, try linking first */
|
nuclear@2
|
279 if(err == GL_INVALID_OPERATION) {
|
nuclear@2
|
280 if(link_program(prog) == -1) {
|
nuclear@2
|
281 return -1;
|
nuclear@2
|
282 }
|
nuclear@2
|
283 glUseProgram(prog);
|
nuclear@2
|
284 return glGetError() == GL_NO_ERROR ? 0 : -1;
|
nuclear@2
|
285 }
|
nuclear@2
|
286 return -1;
|
nuclear@2
|
287 }
|
nuclear@2
|
288 return 0;
|
nuclear@2
|
289 }
|
nuclear@2
|
290
|
nuclear@2
|
291 /* ugly but I'm not going to write the same bloody code over and over */
|
nuclear@2
|
292 #define BEGIN_UNIFORM_CODE \
|
nuclear@2
|
293 int loc, curr_prog; \
|
nuclear@2
|
294 glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog); \
|
nuclear@24
|
295 if((unsigned int)curr_prog != prog && bind_program(prog) == -1) { \
|
nuclear@2
|
296 return -1; \
|
nuclear@2
|
297 } \
|
nuclear@2
|
298 if((loc = glGetUniformLocation(prog, name)) != -1)
|
nuclear@2
|
299
|
nuclear@2
|
300 #define END_UNIFORM_CODE \
|
nuclear@24
|
301 if((unsigned int)curr_prog != prog) { \
|
nuclear@2
|
302 bind_program(curr_prog); \
|
nuclear@2
|
303 } \
|
nuclear@2
|
304 return loc == -1 ? -1 : 0
|
nuclear@2
|
305
|
nuclear@2
|
306 int set_uniform_int(unsigned int prog, const char *name, int val)
|
nuclear@2
|
307 {
|
nuclear@2
|
308 BEGIN_UNIFORM_CODE {
|
nuclear@2
|
309 glUniform1i(loc, val);
|
nuclear@2
|
310 }
|
nuclear@2
|
311 END_UNIFORM_CODE;
|
nuclear@2
|
312 }
|
nuclear@2
|
313
|
nuclear@2
|
314 int set_uniform_float(unsigned int prog, const char *name, float val)
|
nuclear@2
|
315 {
|
nuclear@2
|
316 BEGIN_UNIFORM_CODE {
|
nuclear@2
|
317 glUniform1f(loc, val);
|
nuclear@2
|
318 }
|
nuclear@2
|
319 END_UNIFORM_CODE;
|
nuclear@2
|
320 }
|
nuclear@2
|
321
|
nuclear@24
|
322 int set_uniform_float2(unsigned int prog, const char *name, float x, float y)
|
nuclear@24
|
323 {
|
nuclear@24
|
324 BEGIN_UNIFORM_CODE {
|
nuclear@24
|
325 glUniform2f(loc, x, y);
|
nuclear@24
|
326 }
|
nuclear@24
|
327 END_UNIFORM_CODE;
|
nuclear@24
|
328 }
|
nuclear@24
|
329
|
nuclear@2
|
330 int set_uniform_float3(unsigned int prog, const char *name, float x, float y, float z)
|
nuclear@2
|
331 {
|
nuclear@2
|
332 BEGIN_UNIFORM_CODE {
|
nuclear@2
|
333 glUniform3f(loc, x, y, z);
|
nuclear@2
|
334 }
|
nuclear@2
|
335 END_UNIFORM_CODE;
|
nuclear@2
|
336 }
|
nuclear@2
|
337
|
nuclear@2
|
338 int set_uniform_float4(unsigned int prog, const char *name, float x, float y, float z, float w)
|
nuclear@2
|
339 {
|
nuclear@2
|
340 BEGIN_UNIFORM_CODE {
|
nuclear@2
|
341 glUniform4f(loc, x, y, z, w);
|
nuclear@2
|
342 }
|
nuclear@2
|
343 END_UNIFORM_CODE;
|
nuclear@2
|
344 }
|
nuclear@2
|
345
|
nuclear@2
|
346 int set_uniform_matrix4(unsigned int prog, const char *name, float *mat)
|
nuclear@2
|
347 {
|
nuclear@2
|
348 BEGIN_UNIFORM_CODE {
|
nuclear@2
|
349 glUniformMatrix4fv(loc, 1, GL_FALSE, mat);
|
nuclear@2
|
350 }
|
nuclear@2
|
351 END_UNIFORM_CODE;
|
nuclear@2
|
352 }
|
nuclear@2
|
353
|
nuclear@2
|
354 int set_uniform_matrix4_transposed(unsigned int prog, const char *name, float *mat)
|
nuclear@2
|
355 {
|
nuclear@2
|
356 BEGIN_UNIFORM_CODE {
|
nuclear@2
|
357 glUniformMatrix4fv(loc, 1, GL_TRUE, mat);
|
nuclear@2
|
358 }
|
nuclear@2
|
359 END_UNIFORM_CODE;
|
nuclear@2
|
360 }
|
nuclear@2
|
361
|
nuclear@2
|
362 int get_attrib_loc(unsigned int prog, const char *name)
|
nuclear@2
|
363 {
|
nuclear@2
|
364 int loc, curr_prog;
|
nuclear@2
|
365
|
nuclear@2
|
366 glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog);
|
nuclear@24
|
367 if((unsigned int)curr_prog != prog && bind_program(prog) == -1) {
|
nuclear@2
|
368 return -1;
|
nuclear@2
|
369 }
|
nuclear@2
|
370
|
nuclear@2
|
371 loc = glGetAttribLocation(prog, (char*)name);
|
nuclear@2
|
372
|
nuclear@24
|
373 if((unsigned int)curr_prog != prog) {
|
nuclear@2
|
374 bind_program(curr_prog);
|
nuclear@2
|
375 }
|
nuclear@2
|
376 return loc;
|
nuclear@2
|
377 }
|
nuclear@2
|
378
|
nuclear@2
|
379 void set_attrib_float3(int attr_loc, float x, float y, float z)
|
nuclear@2
|
380 {
|
nuclear@2
|
381 glVertexAttrib3f(attr_loc, x, y, z);
|
nuclear@2
|
382 }
|
nuclear@24
|
383
|
nuclear@24
|
384 static const char *sdrtypestr(unsigned int sdrtype)
|
nuclear@24
|
385 {
|
nuclear@24
|
386 switch(sdrtype) {
|
nuclear@24
|
387 case GL_VERTEX_SHADER:
|
nuclear@24
|
388 return "vertex";
|
nuclear@24
|
389 case GL_FRAGMENT_SHADER:
|
nuclear@24
|
390 return "pixel";
|
nuclear@24
|
391 #ifdef GL_TESS_CONTROL_SHADER
|
nuclear@24
|
392 case GL_TESS_CONTROL_SHADER:
|
nuclear@24
|
393 return "tessellation control";
|
nuclear@24
|
394 #endif
|
nuclear@24
|
395 #ifdef GL_TESS_EVALUATION_SHADER
|
nuclear@24
|
396 case GL_TESS_EVALUATION_SHADER:
|
nuclear@24
|
397 return "tessellation evaluation";
|
nuclear@24
|
398 #endif
|
nuclear@24
|
399 #ifdef GL_GEOMETRY_SHADER
|
nuclear@24
|
400 case GL_GEOMETRY_SHADER:
|
nuclear@24
|
401 return "geometry";
|
nuclear@24
|
402 #endif
|
nuclear@24
|
403
|
nuclear@24
|
404 default:
|
nuclear@24
|
405 break;
|
nuclear@24
|
406 }
|
nuclear@24
|
407 return "<unknown>";
|
nuclear@24
|
408 }
|