erebus
diff src/sdr.c @ 0:4abdce1361b9
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 27 Apr 2014 16:02:47 +0300 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/sdr.c Sun Apr 27 16:02:47 2014 +0300 1.3 @@ -0,0 +1,427 @@ 1.4 +/* 1.5 +Printblobs - halftoning display hack 1.6 +Copyright (C) 2013 John Tsiombikas <nuclear@member.fsf.org> 1.7 + 1.8 +This program is free software: you can redistribute it and/or modify 1.9 +it under the terms of the GNU General Public License as published by 1.10 +the Free Software Foundation, either version 3 of the License, or 1.11 +(at your option) any later version. 1.12 + 1.13 +This program is distributed in the hope that it will be useful, 1.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of 1.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.16 +GNU General Public License for more details. 1.17 + 1.18 +You should have received a copy of the GNU General Public License 1.19 +along with this program. If not, see <http://www.gnu.org/licenses/>. 1.20 +*/ 1.21 +#include <stdio.h> 1.22 +#include <stdlib.h> 1.23 +#include <string.h> 1.24 +#include <errno.h> 1.25 +#include <stdarg.h> 1.26 +#include <assert.h> 1.27 +#include <GL/glew.h> 1.28 + 1.29 +#if defined(unix) || defined(__unix__) 1.30 +#include <unistd.h> 1.31 +#include <sys/stat.h> 1.32 +#endif /* unix */ 1.33 + 1.34 +#include "sdr.h" 1.35 + 1.36 +static const char *sdrtypestr(unsigned int sdrtype); 1.37 + 1.38 +unsigned int create_vertex_shader(const char *src) 1.39 +{ 1.40 + return create_shader(src, GL_VERTEX_SHADER); 1.41 +} 1.42 + 1.43 +unsigned int create_pixel_shader(const char *src) 1.44 +{ 1.45 + return create_shader(src, GL_FRAGMENT_SHADER); 1.46 +} 1.47 + 1.48 +unsigned int create_tessctl_shader(const char *src) 1.49 +{ 1.50 + return create_shader(src, GL_TESS_CONTROL_SHADER); 1.51 +} 1.52 + 1.53 +unsigned int create_tesseval_shader(const char *src) 1.54 +{ 1.55 + return create_shader(src, GL_TESS_EVALUATION_SHADER); 1.56 +} 1.57 + 1.58 +unsigned int create_geometry_shader(const char *src) 1.59 +{ 1.60 + return create_shader(src, GL_GEOMETRY_SHADER); 1.61 +} 1.62 + 1.63 +unsigned int create_shader(const char *src, unsigned int sdr_type) 1.64 +{ 1.65 + unsigned int sdr; 1.66 + int success, info_len; 1.67 + char *info_str = 0; 1.68 + GLenum err; 1.69 + 1.70 + sdr = glCreateShader(sdr_type); 1.71 + assert(glGetError() == GL_NO_ERROR); 1.72 + glShaderSource(sdr, 1, &src, 0); 1.73 + err = glGetError(); 1.74 + assert(err == GL_NO_ERROR); 1.75 + glCompileShader(sdr); 1.76 + assert(glGetError() == GL_NO_ERROR); 1.77 + 1.78 + glGetShaderiv(sdr, GL_COMPILE_STATUS, &success); 1.79 + assert(glGetError() == GL_NO_ERROR); 1.80 + glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len); 1.81 + assert(glGetError() == GL_NO_ERROR); 1.82 + 1.83 + if(info_len) { 1.84 + if((info_str = malloc(info_len + 1))) { 1.85 + glGetShaderInfoLog(sdr, info_len, 0, info_str); 1.86 + assert(glGetError() == GL_NO_ERROR); 1.87 + } 1.88 + } 1.89 + 1.90 + if(success) { 1.91 + fprintf(stderr, info_str ? "done: %s\n" : "done\n", info_str); 1.92 + } else { 1.93 + fprintf(stderr, info_str ? "failed: %s\n" : "failed\n", info_str); 1.94 + glDeleteShader(sdr); 1.95 + sdr = 0; 1.96 + } 1.97 + 1.98 + free(info_str); 1.99 + return sdr; 1.100 +} 1.101 + 1.102 +void free_shader(unsigned int sdr) 1.103 +{ 1.104 + glDeleteShader(sdr); 1.105 +} 1.106 + 1.107 +unsigned int load_vertex_shader(const char *fname) 1.108 +{ 1.109 + return load_shader(fname, GL_VERTEX_SHADER); 1.110 +} 1.111 + 1.112 +unsigned int load_pixel_shader(const char *fname) 1.113 +{ 1.114 + return load_shader(fname, GL_FRAGMENT_SHADER); 1.115 +} 1.116 + 1.117 +unsigned int load_tessctl_shader(const char *fname) 1.118 +{ 1.119 + return load_shader(fname, GL_TESS_CONTROL_SHADER); 1.120 +} 1.121 + 1.122 +unsigned int load_tesseval_shader(const char *fname) 1.123 +{ 1.124 + return load_shader(fname, GL_TESS_EVALUATION_SHADER); 1.125 +} 1.126 + 1.127 +unsigned int load_geometry_shader(const char *fname) 1.128 +{ 1.129 + return load_shader(fname, GL_GEOMETRY_SHADER); 1.130 +} 1.131 + 1.132 +unsigned int load_shader(const char *fname, unsigned int sdr_type) 1.133 +{ 1.134 +#if defined(unix) || defined(__unix__) 1.135 + struct stat st; 1.136 +#endif 1.137 + unsigned int sdr; 1.138 + size_t filesize; 1.139 + FILE *fp; 1.140 + char *src; 1.141 + 1.142 + if(!(fp = fopen(fname, "r"))) { 1.143 + fprintf(stderr, "failed to open shader %s: %s\n", fname, strerror(errno)); 1.144 + return 0; 1.145 + } 1.146 + 1.147 +#if defined(unix) || defined(__unix__) 1.148 + fstat(fileno(fp), &st); 1.149 + filesize = st.st_size; 1.150 +#else 1.151 + fseek(fp, 0, SEEK_END); 1.152 + filesize = ftell(fp); 1.153 + fseek(fp, 0, SEEK_SET); 1.154 +#endif /* unix */ 1.155 + 1.156 + if(!(src = malloc(filesize + 1))) { 1.157 + fclose(fp); 1.158 + return 0; 1.159 + } 1.160 + fread(src, 1, filesize, fp); 1.161 + src[filesize] = 0; 1.162 + fclose(fp); 1.163 + 1.164 + fprintf(stderr, "compiling %s shader: %s... ", sdrtypestr(sdr_type), fname); 1.165 + sdr = create_shader(src, sdr_type); 1.166 + 1.167 + free(src); 1.168 + return sdr; 1.169 +} 1.170 + 1.171 + 1.172 +unsigned int get_vertex_shader(const char *fname) 1.173 +{ 1.174 + return get_shader(fname, GL_VERTEX_SHADER); 1.175 +} 1.176 + 1.177 +unsigned int get_pixel_shader(const char *fname) 1.178 +{ 1.179 + return get_shader(fname, GL_FRAGMENT_SHADER); 1.180 +} 1.181 + 1.182 +unsigned int get_tessctl_shader(const char *fname) 1.183 +{ 1.184 + return get_shader(fname, GL_TESS_CONTROL_SHADER); 1.185 +} 1.186 + 1.187 +unsigned int get_tesseval_shader(const char *fname) 1.188 +{ 1.189 + return get_shader(fname, GL_TESS_EVALUATION_SHADER); 1.190 +} 1.191 + 1.192 +unsigned int get_geometry_shader(const char *fname) 1.193 +{ 1.194 + return get_shader(fname, GL_GEOMETRY_SHADER); 1.195 +} 1.196 + 1.197 +unsigned int get_shader(const char *fname, unsigned int sdr_type) 1.198 +{ 1.199 + unsigned int sdr; 1.200 + if(!(sdr = load_shader(fname, sdr_type))) { 1.201 + return 0; 1.202 + } 1.203 + return sdr; 1.204 +} 1.205 + 1.206 + 1.207 +/* ---- gpu programs ---- */ 1.208 + 1.209 +unsigned int create_program(void) 1.210 +{ 1.211 + unsigned int prog = glCreateProgram(); 1.212 + assert(glGetError() == GL_NO_ERROR); 1.213 + return prog; 1.214 +} 1.215 + 1.216 +unsigned int create_program_link(unsigned int sdr0, ...) 1.217 +{ 1.218 + unsigned int prog, sdr; 1.219 + va_list ap; 1.220 + 1.221 + if(!(prog = create_program())) { 1.222 + return 0; 1.223 + } 1.224 + 1.225 + attach_shader(prog, sdr0); 1.226 + if(glGetError()) { 1.227 + return 0; 1.228 + } 1.229 + 1.230 + va_start(ap, sdr0); 1.231 + while((sdr = va_arg(ap, unsigned int))) { 1.232 + attach_shader(prog, sdr); 1.233 + if(glGetError()) { 1.234 + return 0; 1.235 + } 1.236 + } 1.237 + va_end(ap); 1.238 + 1.239 + if(link_program(prog) == -1) { 1.240 + free_program(prog); 1.241 + return 0; 1.242 + } 1.243 + return prog; 1.244 +} 1.245 + 1.246 +unsigned int create_program_load(const char *vfile, const char *pfile) 1.247 +{ 1.248 + unsigned int vs = 0, ps = 0; 1.249 + 1.250 + if(vfile && *vfile && !(vs = get_vertex_shader(vfile))) { 1.251 + return 0; 1.252 + } 1.253 + if(pfile && *pfile && !(ps = get_pixel_shader(pfile))) { 1.254 + return 0; 1.255 + } 1.256 + return create_program_link(vs, ps, 0); 1.257 +} 1.258 + 1.259 +void free_program(unsigned int sdr) 1.260 +{ 1.261 + glDeleteProgram(sdr); 1.262 +} 1.263 + 1.264 +void attach_shader(unsigned int prog, unsigned int sdr) 1.265 +{ 1.266 + glAttachShader(prog, sdr); 1.267 + assert(glGetError() == GL_NO_ERROR); 1.268 +} 1.269 + 1.270 +int link_program(unsigned int prog) 1.271 +{ 1.272 + int linked, info_len, retval = 0; 1.273 + char *info_str = 0; 1.274 + 1.275 + glLinkProgram(prog); 1.276 + assert(glGetError() == GL_NO_ERROR); 1.277 + glGetProgramiv(prog, GL_LINK_STATUS, &linked); 1.278 + assert(glGetError() == GL_NO_ERROR); 1.279 + glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &info_len); 1.280 + assert(glGetError() == GL_NO_ERROR); 1.281 + 1.282 + if(info_len) { 1.283 + if((info_str = malloc(info_len + 1))) { 1.284 + glGetProgramInfoLog(prog, info_len, 0, info_str); 1.285 + assert(glGetError() == GL_NO_ERROR); 1.286 + } 1.287 + } 1.288 + 1.289 + if(linked) { 1.290 + fprintf(stderr, info_str ? "linking done: %s\n" : "linking done\n", info_str); 1.291 + } else { 1.292 + fprintf(stderr, info_str ? "linking failed: %s\n" : "linking failed\n", info_str); 1.293 + retval = -1; 1.294 + } 1.295 + 1.296 + free(info_str); 1.297 + return retval; 1.298 +} 1.299 + 1.300 +int bind_program(unsigned int prog) 1.301 +{ 1.302 + GLenum err; 1.303 + 1.304 + glUseProgram(prog); 1.305 + if(prog && (err = glGetError()) != GL_NO_ERROR) { 1.306 + /* maybe the program is not linked, try linking first */ 1.307 + if(err == GL_INVALID_OPERATION) { 1.308 + if(link_program(prog) == -1) { 1.309 + return -1; 1.310 + } 1.311 + glUseProgram(prog); 1.312 + return glGetError() == GL_NO_ERROR ? 0 : -1; 1.313 + } 1.314 + return -1; 1.315 + } 1.316 + return 0; 1.317 +} 1.318 + 1.319 +/* ugly but I'm not going to write the same bloody code over and over */ 1.320 +#define BEGIN_UNIFORM_CODE \ 1.321 + int loc, curr_prog; \ 1.322 + glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog); \ 1.323 + if((unsigned int)curr_prog != prog && bind_program(prog) == -1) { \ 1.324 + return -1; \ 1.325 + } \ 1.326 + if((loc = glGetUniformLocation(prog, name)) != -1) 1.327 + 1.328 +#define END_UNIFORM_CODE \ 1.329 + if((unsigned int)curr_prog != prog) { \ 1.330 + bind_program(curr_prog); \ 1.331 + } \ 1.332 + return loc == -1 ? -1 : 0 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, 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, 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 +static const char *sdrtypestr(unsigned int sdrtype) 1.413 +{ 1.414 + switch(sdrtype) { 1.415 + case GL_VERTEX_SHADER: 1.416 + return "vertex"; 1.417 + case GL_FRAGMENT_SHADER: 1.418 + return "pixel"; 1.419 + case GL_TESS_CONTROL_SHADER: 1.420 + return "tessellation control"; 1.421 + case GL_TESS_EVALUATION_SHADER: 1.422 + return "tessellation evaluation"; 1.423 + case GL_GEOMETRY_SHADER: 1.424 + return "geometry"; 1.425 + 1.426 + default: 1.427 + break; 1.428 + } 1.429 + return "<unknown>"; 1.430 +}