9 #if defined(unix) || defined(__unix__)
16 #ifndef GL_GEOMETRY_SHADER
17 #define GL_GEOMETRY_SHADER 0x8dd9
19 #ifndef GL_TESS_EVALUATION_SHADER
20 #define GL_TESS_EVALUATION_SHADER 0x8e87
22 #ifndef GL_TESS_CONTROL_SHADER
23 #define GL_TESS_CONTROL_SHADER 0x8e88
26 static const char *sdrtypestr(unsigned int sdrtype);
27 static int sdrtypeidx(unsigned int sdrtype);
30 unsigned int create_vertex_shader(const char *src)
32 return create_shader(src, GL_VERTEX_SHADER);
35 unsigned int create_pixel_shader(const char *src)
37 return create_shader(src, GL_FRAGMENT_SHADER);
40 unsigned int create_tessctl_shader(const char *src)
42 return create_shader(src, GL_TESS_CONTROL_SHADER);
45 unsigned int create_tesseval_shader(const char *src)
47 return create_shader(src, GL_TESS_EVALUATION_SHADER);
50 unsigned int create_geometry_shader(const char *src)
52 #ifdef GL_GEOMETRY_SHADER
53 return create_shader(src, GL_GEOMETRY_SHADER);
59 unsigned int create_shader(const char *src, unsigned int sdr_type)
62 int success, info_len;
64 const char *src_str[3], *header, *footer;
65 int src_str_count = 0;
68 if((header = get_shader_header(sdr_type))) {
69 src_str[src_str_count++] = header;
71 src_str[src_str_count++] = src;
72 if((footer = get_shader_footer(sdr_type))) {
73 src_str[src_str_count++] = footer;
76 sdr = glCreateShader(sdr_type);
77 assert(glGetError() == GL_NO_ERROR);
78 glShaderSource(sdr, src_str_count, src_str, 0);
80 assert(err == GL_NO_ERROR);
82 assert(glGetError() == GL_NO_ERROR);
84 glGetShaderiv(sdr, GL_COMPILE_STATUS, &success);
85 assert(glGetError() == GL_NO_ERROR);
86 glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len);
87 assert(glGetError() == GL_NO_ERROR);
90 if((info_str = malloc(info_len + 1))) {
91 glGetShaderInfoLog(sdr, info_len, 0, info_str);
92 assert(glGetError() == GL_NO_ERROR);
93 info_str[info_len] = 0;
98 fprintf(stderr, info_str ? "done: %s\n" : "done\n", info_str);
100 fprintf(stderr, info_str ? "failed: %s\n" : "failed\n", info_str);
110 void free_shader(unsigned int sdr)
115 unsigned int load_vertex_shader(const char *fname)
117 return load_shader(fname, GL_VERTEX_SHADER);
120 unsigned int load_pixel_shader(const char *fname)
122 return load_shader(fname, GL_FRAGMENT_SHADER);
125 unsigned int load_tessctl_shader(const char *fname)
127 return load_shader(fname, GL_TESS_CONTROL_SHADER);
130 unsigned int load_tesseval_shader(const char *fname)
132 return load_shader(fname, GL_TESS_EVALUATION_SHADER);
135 unsigned int load_geometry_shader(const char *fname)
137 #ifdef GL_GEOMETRY_SHADER
138 return load_shader(fname, GL_GEOMETRY_SHADER);
144 unsigned int load_shader(const char *fname, unsigned int sdr_type)
151 if(!(fp = fopen(fname, "rb"))) {
152 fprintf(stderr, "failed to open shader %s: %s\n", fname, strerror(errno));
156 fseek(fp, 0, SEEK_END);
157 filesize = ftell(fp);
158 fseek(fp, 0, SEEK_SET);
160 if(!(src = malloc(filesize + 1))) {
164 fread(src, 1, filesize, fp);
168 fprintf(stderr, "compiling %s shader: %s... ", sdrtypestr(sdr_type), fname);
169 sdr = create_shader(src, sdr_type);
176 /* ---- gpu programs ---- */
178 unsigned int create_program(void)
180 unsigned int prog = glCreateProgram();
181 assert(glGetError() == GL_NO_ERROR);
185 unsigned int create_program_link(unsigned int sdr0, ...)
187 unsigned int prog, sdr;
190 if(!(prog = create_program())) {
194 attach_shader(prog, sdr0);
200 while((sdr = va_arg(ap, unsigned int))) {
201 attach_shader(prog, sdr);
208 if(link_program(prog) == -1) {
215 unsigned int create_program_load(const char *vfile, const char *pfile)
217 unsigned int vs = 0, ps = 0;
219 if(vfile && *vfile && !(vs = load_vertex_shader(vfile))) {
222 if(pfile && *pfile && !(ps = load_pixel_shader(pfile))) {
225 return create_program_link(vs, ps, 0);
228 void free_program(unsigned int sdr)
230 glDeleteProgram(sdr);
233 void attach_shader(unsigned int prog, unsigned int sdr)
238 assert(glGetError() == GL_NO_ERROR);
239 glAttachShader(prog, sdr);
240 if((err = glGetError()) != GL_NO_ERROR) {
241 fprintf(stderr, "failed to attach shader %u to program %u (err: 0x%x)\n", sdr, prog, err);
247 int link_program(unsigned int prog)
249 int linked, info_len, retval = 0;
253 assert(glGetError() == GL_NO_ERROR);
254 glGetProgramiv(prog, GL_LINK_STATUS, &linked);
255 assert(glGetError() == GL_NO_ERROR);
256 glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &info_len);
257 assert(glGetError() == GL_NO_ERROR);
260 if((info_str = malloc(info_len + 1))) {
261 glGetProgramInfoLog(prog, info_len, 0, info_str);
262 assert(glGetError() == GL_NO_ERROR);
263 info_str[info_len] = 0;
268 fprintf(stderr, info_str ? "linking done: %s\n" : "linking done\n", info_str);
270 fprintf(stderr, info_str ? "linking failed: %s\n" : "linking failed\n", info_str);
279 int bind_program(unsigned int prog)
284 if(prog && (err = glGetError()) != GL_NO_ERROR) {
285 /* maybe the program is not linked, try linking first */
286 if(err == GL_INVALID_OPERATION) {
287 if(link_program(prog) == -1) {
291 return glGetError() == GL_NO_ERROR ? 0 : -1;
298 /* ugly but I'm not going to write the same bloody code over and over */
299 #define BEGIN_UNIFORM_CODE \
300 int loc, curr_prog; \
301 glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog); \
302 if((unsigned int)curr_prog != prog && bind_program(prog) == -1) { \
305 if((loc = glGetUniformLocation(prog, name)) != -1)
307 #define END_UNIFORM_CODE \
308 if((unsigned int)curr_prog != prog) { \
309 bind_program(curr_prog); \
311 return loc == -1 ? -1 : 0
313 int get_uniform_loc(unsigned int prog, const char *name)
316 glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog);
317 if((unsigned int)curr_prog != prog && bind_program(prog) == -1) {
320 loc = glGetUniformLocation(prog, name);
321 if((unsigned int)curr_prog != prog) {
322 bind_program(curr_prog);
327 int set_uniform_int(unsigned int prog, const char *name, int val)
330 glUniform1i(loc, val);
335 int set_uniform_float(unsigned int prog, const char *name, float val)
338 glUniform1f(loc, val);
343 int set_uniform_float2(unsigned int prog, const char *name, float x, float y)
346 glUniform2f(loc, x, y);
351 int set_uniform_float3(unsigned int prog, const char *name, float x, float y, float z)
354 glUniform3f(loc, x, y, z);
359 int set_uniform_float4(unsigned int prog, const char *name, float x, float y, float z, float w)
362 glUniform4f(loc, x, y, z, w);
367 int set_uniform_matrix4(unsigned int prog, const char *name, const float *mat)
370 glUniformMatrix4fv(loc, 1, GL_FALSE, mat);
375 int set_uniform_matrix4_transposed(unsigned int prog, const char *name, const float *mat)
378 glUniformMatrix4fv(loc, 1, GL_TRUE, mat);
383 int get_attrib_loc(unsigned int prog, const char *name)
387 glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog);
388 if((unsigned int)curr_prog != prog && bind_program(prog) == -1) {
392 loc = glGetAttribLocation(prog, (char*)name);
394 if((unsigned int)curr_prog != prog) {
395 bind_program(curr_prog);
400 void set_attrib_float3(int attr_loc, float x, float y, float z)
402 glVertexAttrib3f(attr_loc, x, y, z);
405 /* ---- shader composition ---- */
411 #define NUM_SHADER_TYPES 5
412 static struct string header[NUM_SHADER_TYPES];
413 static struct string footer[NUM_SHADER_TYPES];
415 static void clear_string(struct string *str)
422 static void append_string(struct string *str, const char *s)
427 if(!s || !*s) return;
430 newlen = str->len + len;
431 if(!(newstr = malloc(newlen + 2))) { /* leave space for a possible newline */
432 fprintf(stderr, "shader composition: failed to append string of size %d\n", len);
437 memcpy(newstr, str->text, str->len);
439 memcpy(newstr + str->len, s, len + 1);
441 if(s[len - 1] != '\n') {
442 newstr[newlen] = '\n';
443 newstr[newlen + 1] = 0;
451 void clear_shader_header(unsigned int type)
454 int idx = sdrtypeidx(type);
455 clear_string(&header[idx]);
458 for(i=0; i<NUM_SHADER_TYPES; i++) {
459 clear_string(&header[i]);
464 void clear_shader_footer(unsigned int type)
467 int idx = sdrtypeidx(type);
468 clear_string(&footer[idx]);
471 for(i=0; i<NUM_SHADER_TYPES; i++) {
472 clear_string(&footer[i]);
477 void add_shader_header(unsigned int type, const char *s)
480 int idx = sdrtypeidx(type);
481 append_string(&header[idx], s);
484 for(i=0; i<NUM_SHADER_TYPES; i++) {
485 append_string(&header[i], s);
490 void add_shader_footer(unsigned int type, const char *s)
493 int idx = sdrtypeidx(type);
494 append_string(&footer[idx], s);
497 for(i=0; i<NUM_SHADER_TYPES; i++) {
498 append_string(&footer[i], s);
503 const char *get_shader_header(unsigned int type)
505 int idx = sdrtypeidx(type);
506 return header[idx].text;
509 const char *get_shader_footer(unsigned int type)
511 int idx = sdrtypeidx(type);
512 return footer[idx].text;
515 static const char *sdrtypestr(unsigned int sdrtype)
518 case GL_VERTEX_SHADER:
520 case GL_FRAGMENT_SHADER:
522 case GL_TESS_CONTROL_SHADER:
523 return "tessellation control";
524 case GL_TESS_EVALUATION_SHADER:
525 return "tessellation evaluation";
526 case GL_GEOMETRY_SHADER:
534 static int sdrtypeidx(unsigned int sdrtype)
537 case GL_VERTEX_SHADER:
539 case GL_FRAGMENT_SHADER:
541 case GL_TESS_CONTROL_SHADER:
543 case GL_TESS_EVALUATION_SHADER:
545 case GL_GEOMETRY_SHADER: