16#define GLSL_VERSION "#version 140\n\n"
17#define GLSL_SUBROUTINE "#define HAS_GL_ARB_shader_subroutine 1\n"
22static void print_with_line_numbers(
const char *str );
23static char* gl_shader_preprocess(
size_t *size,
const char *fbuf,
size_t fbufsize,
const char *prepend,
const char *filename );
24static char* gl_shader_loadfile(
const char *filename,
size_t *size,
const char *prepend );
25static GLuint gl_shader_compile( GLuint type,
const char *buf,
26 GLint length,
const char *filename);
27static int gl_program_link( GLuint program );
28static GLuint gl_program_make( GLuint vertex_shader, GLuint fragment_shader );
29static int gl_log_says_anything(
const char* log );
39static char* gl_shader_loadfile(
const char *filename,
size_t *size,
const char *prepend )
47 snprintf(path,
sizeof(path), GLSL_PATH
"%s", filename);
50 WARN( _(
"Shader '%s' not found."), path);
53 buf = gl_shader_preprocess( size, fbuf, fbufsize, prepend, filename );
68static char* gl_shader_preprocess(
size_t *size,
const char *fbuf,
size_t fbufsize,
const char *prepend,
const char *filename )
70 size_t i, bufsize, ibufsize;
71 char *
buf, *ibuf, *newbuf;
72 char include[
PATH_MAX-
sizeof(GLSL_PATH)-1];
73 const char *substart, *subs, *subss, *keyword;
77 if (prepend != NULL) {
78 bufsize =
asprintf( &buf,
"%s%s", prepend, fbuf ) + 1 ;
93 while ((substart =
strnstr( subs, keyword, bufsize-(subs-buf) ))!=NULL) {
94 subs = substart+strlen(keyword)+1;
97 subss =
strnstr( subs,
"\"", bufsize-(subs-buf));
99 WARN(_(
"Invalid #include syntax in '%s%s'!"), GLSL_PATH, filename);
103 while (isprint(*subs) && (i<
sizeof(include)) && (*subs!=
'"')) {
104 include[i++] = *subs;
108 WARN(_(
"Invalid #include syntax in '%s%s'!"), GLSL_PATH, filename);
114 ibuf = gl_shader_loadfile( include, &ibufsize, NULL );
117 newbuf = malloc( bufsize+ibufsize );
120 strncpy( &newbuf[offset], buf, len );
123 strncpy( &newbuf[offset], ibuf, len );
126 len = bufsize-(subs-
buf);
127 strncpy( &newbuf[offset], subs, bufsize-(subs-buf) );
129 newbuf[offset] =
'\0';
132 subs = &newbuf[subs-
buf];
147static void print_with_line_numbers(
const char *str )
150 for (
int i=0; str[i] !=
'\0'; i++) {
151 if ((i==0) || (str[i]==
'\n'))
152 logprintf( stderr, 0,
"\n%03d: ", ++counter );
162static GLuint gl_shader_compile( GLuint type,
const char *buf,
163 GLint length,
const char *filename)
166 GLint compile_status, log_length;
169 shader = glCreateShader(type);
170 glShaderSource(shader, 1, (
const char**)&buf, &length);
171 glCompileShader(shader);
174 glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
175 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
176 if (log_length > 0) {
177 char *log = malloc(log_length + 1);
178 glGetShaderInfoLog(shader, log_length, &log_length, log);
179 if (gl_log_says_anything( log )) {
180 print_with_line_numbers( buf );
181 WARN(
"compile_status==%d: %s: [[\n%s\n]]", compile_status, filename, log);
184 if (compile_status == GL_FALSE)
197static int gl_program_link( GLuint program )
199 GLint link_status, log_length;
201 glLinkProgram(program);
204 glGetProgramiv(program, GL_LINK_STATUS, &link_status);
205 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
206 if (log_length > 0) {
208 log = malloc(log_length + 1);
209 glGetProgramInfoLog(program, log_length, &log_length, log);
210 if (gl_log_says_anything( log ))
211 WARN(
"link_status==%d: [[\n%s\n]]", link_status, log);
213 if (link_status == GL_FALSE)
227GLuint gl_program_vert_frag(
const char *vertfile,
const char *fragfile )
229 char *vert_str, *frag_str, prepend[STRMAX];
230 size_t vert_size, frag_size;
231 GLuint vertex_shader, fragment_shader, program;
233 strncpy( prepend, GLSL_VERSION,
sizeof(prepend)-1 );
234 if (gl_has( OPENGL_SUBROUTINES ))
235 strncat( prepend, GLSL_SUBROUTINE,
sizeof(prepend)-strlen(prepend)-1 );
237 vert_str = gl_shader_loadfile( vertfile, &vert_size, prepend );
238 frag_str = gl_shader_loadfile( fragfile, &frag_size, prepend );
240 vertex_shader = gl_shader_compile( GL_VERTEX_SHADER, vert_str, vert_size, vertfile );
241 fragment_shader = gl_shader_compile( GL_FRAGMENT_SHADER, frag_str, frag_size, fragfile );
246 program = gl_program_make( vertex_shader, fragment_shader );
248 WARN(_(
"Failed to link vertex shader '%s' and fragment shader '%s'!"), vertfile, fragfile);
262GLuint gl_program_vert_frag_string(
const char *vert,
size_t vert_size,
const char *frag,
size_t frag_size )
264 GLuint vertex_shader, fragment_shader;
268 vbuf = gl_shader_preprocess( &vlen, vert, vert_size, NULL, NULL );
269 fbuf = gl_shader_preprocess( &flen, frag, frag_size, NULL, NULL );
272 vertex_shader = gl_shader_compile( GL_VERTEX_SHADER, vbuf, vlen, NULL );
273 fragment_shader = gl_shader_compile( GL_FRAGMENT_SHADER, fbuf, flen, NULL );
280 return gl_program_make( vertex_shader, fragment_shader );
290static GLuint gl_program_make( GLuint vertex_shader, GLuint fragment_shader )
293 if (vertex_shader != 0 && fragment_shader != 0) {
294 program = glCreateProgram();
295 glAttachShader(program, vertex_shader);
296 glAttachShader(program, fragment_shader);
297 if (gl_program_link(program) == -1) {
303 glDeleteShader(vertex_shader);
304 glDeleteShader(fragment_shader);
311void gl_uniformColor(GLint location,
const glColour *
c)
313 glUniform4f(location,
c->r,
c->g,
c->b,
c->a);
316void gl_uniformAColor(GLint location,
const glColour *
c, GLfloat a)
318 glUniform4f(location,
c->r,
c->g,
c->b, a);
321void gl_uniformMat4( GLint location,
const mat4 *m )
323 glUniformMatrix4fv(location, 1, GL_FALSE, m->ptr );
330static int gl_log_says_anything(
const char* log )
332 const char *junk[] = {
341 for (
size_t i = 0; i*
sizeof(junk[0]) <
sizeof(junk); i++)
342 if (!strncmp(log, junk[i], strlen(junk[i]))) {
343 log += strlen(junk[i]);
int logprintf(FILE *stream, int newline, const char *fmt,...)
Like fprintf, but automatically teed to log files (and line-terminated if newline is true).
Header file with generic functions and naev-specifics.
void * ndata_read(const char *path, size_t *filesize)
Reads a file from the ndata (will be NUL terminated).
static char buf[NEWS_MAX_LENGTH]
int asprintf(char **strp, const char *fmt,...)
Like sprintf(), but it allocates a large-enough string and returns the pointer in the first argument....
char * strnstr(const char *haystack, const char *needle, size_t size)
A bounded version of strstr. Conforms to BSD semantics.