18static char *gl_shader_preprocess(
size_t *size,
const char *fbuf,
19 size_t fbufsize,
const char *prepend,
20 const char *filename );
21static char *gl_shader_loadfile(
const char *filename,
size_t *size,
22 const char *prepend );
23static GLuint gl_shader_compile( GLuint type,
const char *buf, GLint length,
24 const char *filename );
25static int gl_program_link( GLuint program );
26static GLuint gl_program_make( GLuint vertex_shader, GLuint fragment_shader,
27 GLuint geometry_shader );
28static int gl_log_says_anything(
const char *log );
39static char *gl_shader_loadfile(
const char *filename,
size_t *size,
48 snprintf( path,
sizeof( path ), GLSL_PATH
"%s", filename );
51 WARN( _(
"Shader '%s' not found." ), path );
54 buf = gl_shader_preprocess( size, fbuf, fbufsize, prepend, filename );
70static char *gl_shader_preprocess(
size_t *size,
const char *fbuf,
71 size_t fbufsize,
const char *prepend,
72 const char *filename )
74 size_t i, bufsize, ibufsize;
75 char *buf, *ibuf, *newbuf;
76 char include[
PATH_MAX -
sizeof( GLSL_PATH ) - 1];
77 const char *substart, *subs, *subss, *keyword;
81 if ( prepend != NULL ) {
83 SDL_asprintf( &buf,
"%s%s", prepend, fbuf ) + 1 ;
97 while ( ( substart =
strnstr( subs, keyword, bufsize - ( subs - buf ) ) ) !=
99 subs = substart + strlen( keyword ) + 1;
101 int whitespaceonly = 1;
103 while ( &substart[off] != buf ) {
105 if ( ( substart[off] ==
'\n' ) || ( substart[off] ==
'\r' ) )
107 else if ( isspace( substart[off] ) )
114 if ( !whitespaceonly ) {
119 subss =
strnstr( subs,
"\"", bufsize - ( subs - buf ) );
120 if ( subss == NULL ) {
121 WARN( _(
"Invalid #include syntax in '%s%s'!" ), GLSL_PATH, filename );
125 while ( isprint( *subs ) && ( i <
sizeof( include ) ) &&
127 include[i++] = *subs;
130 if ( *subs !=
'"' ) {
131 WARN( _(
"Invalid #include syntax in '%s%s'!" ), GLSL_PATH, filename );
137 ibuf = gl_shader_loadfile( include, &ibufsize, NULL );
140 newbuf = malloc( bufsize + ibufsize );
142 len = substart - buf;
143 strncpy( &newbuf[offset], buf, len );
146 strncpy( &newbuf[offset], ibuf, len );
149 len = bufsize - ( subs - buf );
150 strncpy( &newbuf[offset], subs, bufsize - ( subs - buf ) );
152 newbuf[offset] =
'\0';
155 subs = &newbuf[subs - buf];
173static GLuint gl_shader_compile( GLuint type,
const char *buf, GLint length,
174 const char *filename )
177 GLint compile_status, log_length;
180 shader = glCreateShader( type );
181 glShaderSource( shader, 1, (
const char **)&buf, &length );
182 glCompileShader( shader );
185 glGetShaderiv( shader, GL_COMPILE_STATUS, &compile_status );
186 glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &log_length );
187 if ( log_length > 0 ) {
188 char *log = malloc( log_length + 1 );
189 glGetShaderInfoLog( shader, log_length, &log_length, log );
190 if ( gl_log_says_anything( log ) ) {
191 logprintf( stderr, 0, _(
"File: %s" ), filename );
193 WARN(
"compile_status==%d: %s: [[\n%s\n]]", compile_status, filename,
197 if ( compile_status == GL_FALSE )
210static int gl_program_link( GLuint program )
212 GLint link_status, log_length;
214 glLinkProgram( program );
217 glGetProgramiv( program, GL_LINK_STATUS, &link_status );
218 glGetProgramiv( program, GL_INFO_LOG_LENGTH, &log_length );
219 if ( log_length > 0 ) {
220 char *log = malloc( log_length + 1 );
221 glGetProgramInfoLog( program, log_length, &log_length, log );
222 if ( gl_log_says_anything( log ) )
223 WARN(
"link_status==%d: [[\n%s\n]]", link_status, log );
225 if ( link_status == GL_FALSE )
232GLuint gl_program_vert_frag_geom(
const char *vert,
const char *frag,
235 return gl_program_backend( vert, frag, geom, NULL );
238GLuint gl_program_vert_frag(
const char *vert,
const char *frag )
240 return gl_program_backend( vert, frag, NULL, NULL );
251GLuint gl_program_backend(
const char *vertfile,
const char *fragfile,
252 const char *geomfile,
const char *prependtext )
254 char *vert_str, *frag_str, prepend[STRMAX];
255 size_t vert_size, frag_size;
256 GLuint vertex_shader, fragment_shader, geometry_shader, program;
258 snprintf( prepend,
sizeof( prepend ) - 1,
259 "#version %d\n\n#define GLSL_VERSION %d\n",
gl_screen.glsl,
261 if ( gl_has( OPENGL_SUBROUTINES ) )
262 strncat( prepend,
"#define HAS_GL_ARB_shader_subroutine 1\n",
263 sizeof( prepend ) - strlen( prepend ) - 1 );
264 if ( prependtext != NULL )
265 strncat( prepend, prependtext,
266 sizeof( prepend ) - strlen( prepend ) - 1 );
268 vert_str = gl_shader_loadfile( vertfile, &vert_size, prepend );
269 frag_str = gl_shader_loadfile( fragfile, &frag_size, prepend );
272 gl_shader_compile( GL_VERTEX_SHADER, vert_str, vert_size, vertfile );
274 gl_shader_compile( GL_FRAGMENT_SHADER, frag_str, frag_size, fragfile );
279 if ( geomfile != NULL ) {
281 char *geom_str = gl_shader_loadfile( geomfile, &geom_size, prepend );
283 gl_shader_compile( GL_GEOMETRY_SHADER, geom_str, geom_size, geomfile );
288 program = gl_program_make( vertex_shader, fragment_shader, geometry_shader );
290 WARN( _(
"Failed to link vertex shader '%s' and fragment shader '%s'!" ),
291 vertfile, fragfile );
305GLuint gl_program_vert_frag_string(
const char *vert,
size_t vert_size,
306 const char *frag,
size_t frag_size )
308 GLuint vertex_shader, fragment_shader;
312 vbuf = gl_shader_preprocess( &vlen, vert, vert_size, NULL, NULL );
313 fbuf = gl_shader_preprocess( &flen, frag, frag_size, NULL, NULL );
316 vertex_shader = gl_shader_compile( GL_VERTEX_SHADER, vbuf, vlen, NULL );
317 fragment_shader = gl_shader_compile( GL_FRAGMENT_SHADER, fbuf, flen, NULL );
324 return gl_program_make( vertex_shader, fragment_shader, 0 );
335static GLuint gl_program_make( GLuint vertex_shader, GLuint fragment_shader,
336 GLuint geometry_shader )
339 if ( vertex_shader != 0 && fragment_shader != 0 ) {
340 program = glCreateProgram();
341 glAttachShader( program, vertex_shader );
342 glAttachShader( program, fragment_shader );
343 if ( geometry_shader != 0 )
344 glAttachShader( program, geometry_shader );
346 if ( gl_program_link( program ) == -1 ) {
351 glDeleteShader( vertex_shader );
352 glDeleteShader( fragment_shader );
353 if ( geometry_shader != 0 )
354 glDeleteShader( geometry_shader );
362void gl_uniformColour( GLint location,
const glColour *
c )
364 glUniform4f( location,
c->r,
c->g,
c->b,
c->a );
367void gl_uniformAColour( GLint location,
const glColour *
c, GLfloat a )
369 glUniform4f( location,
c->r,
c->g,
c->b, a );
372void gl_uniformMat4( GLint location,
const mat4 *m )
374 glUniformMatrix4fv( location, 1, GL_FALSE, m->ptr );
382static int gl_log_says_anything(
const char *log )
384 const char *junk[] = {
390 if ( isspace( *log ) ) {
394 for (
size_t i = 0; i *
sizeof( junk[0] ) <
sizeof( junk ); i++ )
395 if ( !strncmp( log, junk[i], strlen( junk[i] ) ) ) {
396 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).
void print_with_line_numbers(const char *str)
Prints to stderr with line numbers.
char * strnstr(const char *haystack, const char *needle, size_t size)
A bounded version of strstr. Conforms to BSD semantics.