fractorb
diff src/sdr.c @ 0:6e849d7377ff
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 18 Nov 2017 20:04:16 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/sdr.c Sat Nov 18 20:04:16 2017 +0200 1.3 @@ -0,0 +1,562 @@ 1.4 +#include <stdio.h> 1.5 +#include <stdlib.h> 1.6 +#include <string.h> 1.7 +#include <errno.h> 1.8 +#include <stdarg.h> 1.9 +#include <assert.h> 1.10 +#include "opengl.h" 1.11 + 1.12 +#if defined(unix) || defined(__unix__) 1.13 +#include <unistd.h> 1.14 +#include <sys/stat.h> 1.15 +#endif /* unix */ 1.16 + 1.17 +#include "sdr.h" 1.18 + 1.19 +static const char *sdrtypestr(unsigned int sdrtype); 1.20 +static int sdrtypeidx(unsigned int sdrtype); 1.21 + 1.22 + 1.23 +unsigned int create_vertex_shader(const char *src) 1.24 +{ 1.25 + return create_shader(src, GL_VERTEX_SHADER); 1.26 +} 1.27 + 1.28 +unsigned int create_pixel_shader(const char *src) 1.29 +{ 1.30 + return create_shader(src, GL_FRAGMENT_SHADER); 1.31 +} 1.32 + 1.33 +unsigned int create_tessctl_shader(const char *src) 1.34 +{ 1.35 +#ifdef GL_TESS_CONTROL_SHADER 1.36 + return create_shader(src, GL_TESS_CONTROL_SHADER); 1.37 +#else 1.38 + return 0; 1.39 +#endif 1.40 +} 1.41 + 1.42 +unsigned int create_tesseval_shader(const char *src) 1.43 +{ 1.44 +#ifdef GL_TESS_EVALUATION_SHADER 1.45 + return create_shader(src, GL_TESS_EVALUATION_SHADER); 1.46 +#else 1.47 + return 0; 1.48 +#endif 1.49 +} 1.50 + 1.51 +unsigned int create_geometry_shader(const char *src) 1.52 +{ 1.53 +#ifdef GL_GEOMETRY_SHADER 1.54 + return create_shader(src, GL_GEOMETRY_SHADER); 1.55 +#else 1.56 + return 0; 1.57 +#endif 1.58 +} 1.59 + 1.60 +unsigned int create_shader(const char *src, unsigned int sdr_type) 1.61 +{ 1.62 + unsigned int sdr; 1.63 + int success, info_len; 1.64 + char *info_str = 0; 1.65 + const char *src_str[3], *header, *footer; 1.66 + int src_str_count = 0; 1.67 + GLenum err; 1.68 + 1.69 + if((header = get_shader_header(sdr_type))) { 1.70 + src_str[src_str_count++] = header; 1.71 + } 1.72 + src_str[src_str_count++] = src; 1.73 + if((footer = get_shader_footer(sdr_type))) { 1.74 + src_str[src_str_count++] = footer; 1.75 + } 1.76 + 1.77 + sdr = glCreateShader(sdr_type); 1.78 + assert(glGetError() == GL_NO_ERROR); 1.79 + glShaderSource(sdr, src_str_count, src_str, 0); 1.80 + err = glGetError(); 1.81 + assert(err == GL_NO_ERROR); 1.82 + glCompileShader(sdr); 1.83 + assert(glGetError() == GL_NO_ERROR); 1.84 + 1.85 + glGetShaderiv(sdr, GL_COMPILE_STATUS, &success); 1.86 + assert(glGetError() == GL_NO_ERROR); 1.87 + glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len); 1.88 + assert(glGetError() == GL_NO_ERROR); 1.89 + 1.90 + if(info_len) { 1.91 + if((info_str = malloc(info_len + 1))) { 1.92 + glGetShaderInfoLog(sdr, info_len, 0, info_str); 1.93 + assert(glGetError() == GL_NO_ERROR); 1.94 + info_str[info_len] = 0; 1.95 + } 1.96 + } 1.97 + 1.98 + if(success) { 1.99 + fprintf(stderr, info_str ? "done: %s\n" : "done\n", info_str); 1.100 + } else { 1.101 + fprintf(stderr, info_str ? "failed: %s\n" : "failed\n", info_str); 1.102 + glDeleteShader(sdr); 1.103 + sdr = 0; 1.104 + } 1.105 + 1.106 + free(info_str); 1.107 + return sdr; 1.108 +} 1.109 + 1.110 +void free_shader(unsigned int sdr) 1.111 +{ 1.112 + glDeleteShader(sdr); 1.113 +} 1.114 + 1.115 +unsigned int load_vertex_shader(const char *fname) 1.116 +{ 1.117 + return load_shader(fname, GL_VERTEX_SHADER); 1.118 +} 1.119 + 1.120 +unsigned int load_pixel_shader(const char *fname) 1.121 +{ 1.122 + return load_shader(fname, GL_FRAGMENT_SHADER); 1.123 +} 1.124 + 1.125 +unsigned int load_tessctl_shader(const char *fname) 1.126 +{ 1.127 +#ifdef GL_TESS_CONTROL_SHADER 1.128 + return load_shader(fname, GL_TESS_CONTROL_SHADER); 1.129 +#else 1.130 + return 0; 1.131 +#endif 1.132 +} 1.133 + 1.134 +unsigned int load_tesseval_shader(const char *fname) 1.135 +{ 1.136 +#ifdef GL_TESS_EVALUATION_SHADER 1.137 + return load_shader(fname, GL_TESS_EVALUATION_SHADER); 1.138 +#else 1.139 + return 0; 1.140 +#endif 1.141 +} 1.142 + 1.143 +unsigned int load_geometry_shader(const char *fname) 1.144 +{ 1.145 +#ifdef GL_GEOMETRY_SHADER 1.146 + return load_shader(fname, GL_GEOMETRY_SHADER); 1.147 +#else 1.148 + return 0; 1.149 +#endif 1.150 +} 1.151 + 1.152 +unsigned int load_shader(const char *fname, unsigned int sdr_type) 1.153 +{ 1.154 + unsigned int sdr; 1.155 + size_t filesize; 1.156 + FILE *fp; 1.157 + char *src; 1.158 + 1.159 + if(!(fp = fopen(fname, "rb"))) { 1.160 + fprintf(stderr, "failed to open shader %s: %s\n", fname, strerror(errno)); 1.161 + return 0; 1.162 + } 1.163 + 1.164 + fseek(fp, 0, SEEK_END); 1.165 + filesize = ftell(fp); 1.166 + fseek(fp, 0, SEEK_SET); 1.167 + 1.168 + if(!(src = malloc(filesize + 1))) { 1.169 + fclose(fp); 1.170 + return 0; 1.171 + } 1.172 + fread(src, 1, filesize, fp); 1.173 + src[filesize] = 0; 1.174 + fclose(fp); 1.175 + 1.176 + fprintf(stderr, "compiling %s shader: %s... ", sdrtypestr(sdr_type), fname); 1.177 + sdr = create_shader(src, sdr_type); 1.178 + 1.179 + free(src); 1.180 + return sdr; 1.181 +} 1.182 + 1.183 + 1.184 +/* ---- gpu programs ---- */ 1.185 + 1.186 +unsigned int create_program(void) 1.187 +{ 1.188 + unsigned int prog = glCreateProgram(); 1.189 + assert(glGetError() == GL_NO_ERROR); 1.190 + return prog; 1.191 +} 1.192 + 1.193 +unsigned int create_program_link(unsigned int sdr0, ...) 1.194 +{ 1.195 + unsigned int prog, sdr; 1.196 + va_list ap; 1.197 + 1.198 + if(!(prog = create_program())) { 1.199 + return 0; 1.200 + } 1.201 + 1.202 + attach_shader(prog, sdr0); 1.203 + if(glGetError()) { 1.204 + return 0; 1.205 + } 1.206 + 1.207 + va_start(ap, sdr0); 1.208 + while((sdr = va_arg(ap, unsigned int))) { 1.209 + attach_shader(prog, sdr); 1.210 + if(glGetError()) { 1.211 + return 0; 1.212 + } 1.213 + } 1.214 + va_end(ap); 1.215 + 1.216 + if(link_program(prog) == -1) { 1.217 + free_program(prog); 1.218 + return 0; 1.219 + } 1.220 + return prog; 1.221 +} 1.222 + 1.223 +unsigned int create_program_load(const char *vfile, const char *pfile) 1.224 +{ 1.225 + unsigned int vs = 0, ps = 0; 1.226 + 1.227 + if(vfile && *vfile && !(vs = load_vertex_shader(vfile))) { 1.228 + return 0; 1.229 + } 1.230 + if(pfile && *pfile && !(ps = load_pixel_shader(pfile))) { 1.231 + return 0; 1.232 + } 1.233 + return create_program_link(vs, ps, 0); 1.234 +} 1.235 + 1.236 +void free_program(unsigned int sdr) 1.237 +{ 1.238 + glDeleteProgram(sdr); 1.239 +} 1.240 + 1.241 +void attach_shader(unsigned int prog, unsigned int sdr) 1.242 +{ 1.243 + int err; 1.244 + 1.245 + if(prog && sdr) { 1.246 + assert(glGetError() == GL_NO_ERROR); 1.247 + glAttachShader(prog, sdr); 1.248 + if((err = glGetError()) != GL_NO_ERROR) { 1.249 + fprintf(stderr, "failed to attach shader %u to program %u (err: 0x%x)\n", sdr, prog, err); 1.250 + abort(); 1.251 + } 1.252 + } 1.253 +} 1.254 + 1.255 +int link_program(unsigned int prog) 1.256 +{ 1.257 + int linked, info_len, retval = 0; 1.258 + char *info_str = 0; 1.259 + 1.260 + glLinkProgram(prog); 1.261 + assert(glGetError() == GL_NO_ERROR); 1.262 + glGetProgramiv(prog, GL_LINK_STATUS, &linked); 1.263 + assert(glGetError() == GL_NO_ERROR); 1.264 + glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &info_len); 1.265 + assert(glGetError() == GL_NO_ERROR); 1.266 + 1.267 + if(info_len) { 1.268 + if((info_str = malloc(info_len + 1))) { 1.269 + glGetProgramInfoLog(prog, info_len, 0, info_str); 1.270 + assert(glGetError() == GL_NO_ERROR); 1.271 + info_str[info_len] = 0; 1.272 + } 1.273 + } 1.274 + 1.275 + if(linked) { 1.276 + fprintf(stderr, info_str ? "linking done: %s\n" : "linking done\n", info_str); 1.277 + } else { 1.278 + fprintf(stderr, info_str ? "linking failed: %s\n" : "linking failed\n", info_str); 1.279 + retval = -1; 1.280 + } 1.281 + 1.282 + free(info_str); 1.283 + return retval; 1.284 +} 1.285 + 1.286 +int bind_program(unsigned int prog) 1.287 +{ 1.288 + GLenum err; 1.289 + 1.290 + glUseProgram(prog); 1.291 + if(prog && (err = glGetError()) != GL_NO_ERROR) { 1.292 + /* maybe the program is not linked, try linking first */ 1.293 + if(err == GL_INVALID_OPERATION) { 1.294 + if(link_program(prog) == -1) { 1.295 + return -1; 1.296 + } 1.297 + glUseProgram(prog); 1.298 + return glGetError() == GL_NO_ERROR ? 0 : -1; 1.299 + } 1.300 + return -1; 1.301 + } 1.302 + return 0; 1.303 +} 1.304 + 1.305 +/* ugly but I'm not going to write the same bloody code over and over */ 1.306 +#define BEGIN_UNIFORM_CODE \ 1.307 + int loc, curr_prog; \ 1.308 + glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog); \ 1.309 + if((unsigned int)curr_prog != prog && bind_program(prog) == -1) { \ 1.310 + return -1; \ 1.311 + } \ 1.312 + if((loc = glGetUniformLocation(prog, name)) != -1) 1.313 + 1.314 +#define END_UNIFORM_CODE \ 1.315 + if((unsigned int)curr_prog != prog) { \ 1.316 + bind_program(curr_prog); \ 1.317 + } \ 1.318 + return loc == -1 ? -1 : 0 1.319 + 1.320 +int get_uniform_loc(unsigned int prog, const char *name) 1.321 +{ 1.322 + int loc, curr_prog; 1.323 + glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog); 1.324 + if((unsigned int)curr_prog != prog && bind_program(prog) == -1) { 1.325 + return -1; 1.326 + } 1.327 + loc = glGetUniformLocation(prog, name); 1.328 + if((unsigned int)curr_prog != prog) { 1.329 + bind_program(curr_prog); 1.330 + } 1.331 + return loc; 1.332 +} 1.333 + 1.334 +int set_uniform_int(unsigned int prog, const char *name, int val) 1.335 +{ 1.336 + BEGIN_UNIFORM_CODE { 1.337 + glUniform1i(loc, val); 1.338 + } 1.339 + END_UNIFORM_CODE; 1.340 +} 1.341 + 1.342 +int set_uniform_float(unsigned int prog, const char *name, float val) 1.343 +{ 1.344 + BEGIN_UNIFORM_CODE { 1.345 + glUniform1f(loc, val); 1.346 + } 1.347 + END_UNIFORM_CODE; 1.348 +} 1.349 + 1.350 +int set_uniform_float2(unsigned int prog, const char *name, float x, float y) 1.351 +{ 1.352 + BEGIN_UNIFORM_CODE { 1.353 + glUniform2f(loc, x, y); 1.354 + } 1.355 + END_UNIFORM_CODE; 1.356 +} 1.357 + 1.358 +int set_uniform_float3(unsigned int prog, const char *name, float x, float y, float z) 1.359 +{ 1.360 + BEGIN_UNIFORM_CODE { 1.361 + glUniform3f(loc, x, y, z); 1.362 + } 1.363 + END_UNIFORM_CODE; 1.364 +} 1.365 + 1.366 +int set_uniform_float4(unsigned int prog, const char *name, float x, float y, float z, float w) 1.367 +{ 1.368 + BEGIN_UNIFORM_CODE { 1.369 + glUniform4f(loc, x, y, z, w); 1.370 + } 1.371 + END_UNIFORM_CODE; 1.372 +} 1.373 + 1.374 +int set_uniform_matrix4(unsigned int prog, const char *name, const float *mat) 1.375 +{ 1.376 + BEGIN_UNIFORM_CODE { 1.377 + glUniformMatrix4fv(loc, 1, GL_FALSE, mat); 1.378 + } 1.379 + END_UNIFORM_CODE; 1.380 +} 1.381 + 1.382 +int set_uniform_matrix4_transposed(unsigned int prog, const char *name, const float *mat) 1.383 +{ 1.384 + BEGIN_UNIFORM_CODE { 1.385 + glUniformMatrix4fv(loc, 1, GL_TRUE, mat); 1.386 + } 1.387 + END_UNIFORM_CODE; 1.388 +} 1.389 + 1.390 +int get_attrib_loc(unsigned int prog, const char *name) 1.391 +{ 1.392 + int loc, curr_prog; 1.393 + 1.394 + glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog); 1.395 + if((unsigned int)curr_prog != prog && bind_program(prog) == -1) { 1.396 + return -1; 1.397 + } 1.398 + 1.399 + loc = glGetAttribLocation(prog, (char*)name); 1.400 + 1.401 + if((unsigned int)curr_prog != prog) { 1.402 + bind_program(curr_prog); 1.403 + } 1.404 + return loc; 1.405 +} 1.406 + 1.407 +void set_attrib_float3(int attr_loc, float x, float y, float z) 1.408 +{ 1.409 + glVertexAttrib3f(attr_loc, x, y, z); 1.410 +} 1.411 + 1.412 +/* ---- shader composition ---- */ 1.413 +struct string { 1.414 + char *text; 1.415 + int len; 1.416 +}; 1.417 + 1.418 +#define NUM_SHADER_TYPES 5 1.419 +static struct string header[NUM_SHADER_TYPES]; 1.420 +static struct string footer[NUM_SHADER_TYPES]; 1.421 + 1.422 +static void clear_string(struct string *str) 1.423 +{ 1.424 + free(str->text); 1.425 + str->text = 0; 1.426 + str->len = 0; 1.427 +} 1.428 + 1.429 +static void append_string(struct string *str, const char *s) 1.430 +{ 1.431 + int len, newlen; 1.432 + char *newstr; 1.433 + 1.434 + if(!s || !*s) return; 1.435 + 1.436 + len = strlen(s); 1.437 + newlen = str->len + len; 1.438 + if(!(newstr = malloc(newlen + 2))) { /* leave space for a possible newline */ 1.439 + fprintf(stderr, "shader composition: failed to append string of size %d\n", len); 1.440 + abort(); 1.441 + } 1.442 + 1.443 + if(str->text) { 1.444 + memcpy(newstr, str->text, str->len); 1.445 + } 1.446 + memcpy(newstr + str->len, s, len + 1); 1.447 + 1.448 + if(s[len - 1] != '\n') { 1.449 + newstr[newlen] = '\n'; 1.450 + newstr[newlen + 1] = 0; 1.451 + } 1.452 + 1.453 + free(str->text); 1.454 + str->text = newstr; 1.455 + str->len = newlen; 1.456 +} 1.457 + 1.458 +void clear_shader_header(unsigned int type) 1.459 +{ 1.460 + if(type) { 1.461 + int idx = sdrtypeidx(type); 1.462 + clear_string(&header[idx]); 1.463 + } else { 1.464 + int i; 1.465 + for(i=0; i<NUM_SHADER_TYPES; i++) { 1.466 + clear_string(&header[i]); 1.467 + } 1.468 + } 1.469 +} 1.470 + 1.471 +void clear_shader_footer(unsigned int type) 1.472 +{ 1.473 + if(type) { 1.474 + int idx = sdrtypeidx(type); 1.475 + clear_string(&footer[idx]); 1.476 + } else { 1.477 + int i; 1.478 + for(i=0; i<NUM_SHADER_TYPES; i++) { 1.479 + clear_string(&footer[i]); 1.480 + } 1.481 + } 1.482 +} 1.483 + 1.484 +void add_shader_header(unsigned int type, const char *s) 1.485 +{ 1.486 + if(type) { 1.487 + int idx = sdrtypeidx(type); 1.488 + append_string(&header[idx], s); 1.489 + } else { 1.490 + int i; 1.491 + for(i=0; i<NUM_SHADER_TYPES; i++) { 1.492 + append_string(&header[i], s); 1.493 + } 1.494 + } 1.495 +} 1.496 + 1.497 +void add_shader_footer(unsigned int type, const char *s) 1.498 +{ 1.499 + if(type) { 1.500 + int idx = sdrtypeidx(type); 1.501 + append_string(&footer[idx], s); 1.502 + } else { 1.503 + int i; 1.504 + for(i=0; i<NUM_SHADER_TYPES; i++) { 1.505 + append_string(&footer[i], s); 1.506 + } 1.507 + } 1.508 +} 1.509 + 1.510 +const char *get_shader_header(unsigned int type) 1.511 +{ 1.512 + int idx = sdrtypeidx(type); 1.513 + return header[idx].text; 1.514 +} 1.515 + 1.516 +const char *get_shader_footer(unsigned int type) 1.517 +{ 1.518 + int idx = sdrtypeidx(type); 1.519 + return footer[idx].text; 1.520 +} 1.521 + 1.522 +static const char *sdrtypestr(unsigned int sdrtype) 1.523 +{ 1.524 + switch(sdrtype) { 1.525 + case GL_VERTEX_SHADER: 1.526 + return "vertex"; 1.527 + case GL_FRAGMENT_SHADER: 1.528 + return "pixel"; 1.529 +#ifdef GL_TESS_CONTROL_SHADER 1.530 + case GL_TESS_CONTROL_SHADER: 1.531 + return "tessellation control"; 1.532 +#endif 1.533 +#ifdef GL_TESS_EVALUATION_SHADER 1.534 + case GL_TESS_EVALUATION_SHADER: 1.535 + return "tessellation evaluation"; 1.536 +#endif 1.537 +#ifdef GL_GEOMETRY_SHADER 1.538 + case GL_GEOMETRY_SHADER: 1.539 + return "geometry"; 1.540 +#endif 1.541 + 1.542 + default: 1.543 + break; 1.544 + } 1.545 + return "<unknown>"; 1.546 +} 1.547 + 1.548 +static int sdrtypeidx(unsigned int sdrtype) 1.549 +{ 1.550 + switch(sdrtype) { 1.551 + case GL_VERTEX_SHADER: 1.552 + return 0; 1.553 + case GL_FRAGMENT_SHADER: 1.554 + return 1; 1.555 + case GL_TESS_CONTROL_SHADER: 1.556 + return 2; 1.557 + case GL_TESS_EVALUATION_SHADER: 1.558 + return 3; 1.559 + case GL_GEOMETRY_SHADER: 1.560 + return 4; 1.561 + default: 1.562 + break; 1.563 + } 1.564 + return 0; 1.565 +}