nkeynes@405: /** nkeynes@561: * $Id$ nkeynes@405: * nkeynes@1130: * Tool to take an input .glsl file and write out a corresponding .c and .h nkeynes@1130: * file based on the content. The .glsl file contains a number of shaders nkeynes@1130: * marked with either #fragment or #vertex nkeynes@1130: * a C file with appropriate escaping, as well as program definitions nkeynes@1130: * written as #program = ... nkeynes@405: * nkeynes@1234: * Copyright (c) 2007-2012 Nathan Keynes. nkeynes@405: * nkeynes@405: * This program is free software; you can redistribute it and/or modify nkeynes@405: * it under the terms of the GNU General Public License as published by nkeynes@405: * the Free Software Foundation; either version 2 of the License, or nkeynes@405: * (at your option) any later version. nkeynes@405: * nkeynes@405: * This program is distributed in the hope that it will be useful, nkeynes@405: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@405: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@405: * GNU General Public License for more details. nkeynes@405: */ nkeynes@405: nkeynes@1130: #include nkeynes@1207: #include nkeynes@1130: #include nkeynes@405: #include nkeynes@405: #include nkeynes@1130: #include nkeynes@1234: #include nkeynes@1296: #include nkeynes@1235: #include "../../config.h" nkeynes@1130: nkeynes@1130: #define MAX_LINE 4096 nkeynes@1130: #define DEF_ALLOC_SIZE 4096 nkeynes@1130: #define MAX_SHADERS 128 nkeynes@1130: nkeynes@1130: typedef enum { nkeynes@1130: VERTEX_SHADER = 0, nkeynes@1130: FRAGMENT_SHADER = 1 nkeynes@1130: } shader_type_t; nkeynes@1130: nkeynes@1207: typedef struct variable { nkeynes@1207: gboolean uniform; /* TRUE = uniform, FALSE = attribute */ nkeynes@1207: const char *name; nkeynes@1207: const char *type; nkeynes@1207: } *variable_t; nkeynes@1207: nkeynes@1130: typedef struct shader { nkeynes@1130: shader_type_t type; nkeynes@1130: const char *name; nkeynes@1130: char *body; nkeynes@1207: GList *variables; nkeynes@1130: } *shader_t; nkeynes@1130: nkeynes@1130: typedef struct program { nkeynes@1130: const char *name; nkeynes@1130: gchar **shader_names; nkeynes@1207: GList *shaders; nkeynes@1207: GList *variables; nkeynes@1130: } *program_t; nkeynes@1130: nkeynes@1130: typedef struct glsldata { nkeynes@1130: const char *filename; nkeynes@1130: unsigned max_shaders; nkeynes@1130: GList *shaders; nkeynes@1130: GList *programs; nkeynes@1130: } *glsldata_t; nkeynes@1130: nkeynes@1207: #define isident(c) (isalnum(c)||(c)=='_') nkeynes@1207: nkeynes@1207: static void parseVarDecl( shader_t shader, gboolean uniform, char *input ) nkeynes@1207: { nkeynes@1207: unsigned i; nkeynes@1207: char *p = g_strstrip(input); nkeynes@1207: for( i=0; isident(p[i]); i++) nkeynes@1207: if( p[i] == 0 ) { nkeynes@1207: fprintf( stderr, "Error: unable to parse variable decl '%s'\n", p ); nkeynes@1207: return; /* incomplete decl? */ nkeynes@1207: } nkeynes@1207: char *type = g_strndup(p, i); nkeynes@1207: p = g_strstrip(input+i); nkeynes@1207: for( i=0; isident(p[i]); i++) nkeynes@1207: if( p[i] == 0 ) { nkeynes@1207: fprintf( stderr, "Error: unable to parse variable decl '%s'\n", p ); nkeynes@1207: return; /* incomplete decl? */ nkeynes@1207: } nkeynes@1207: char *name = g_strndup(p, i); nkeynes@1207: variable_t var = g_malloc0(sizeof(struct variable)); nkeynes@1207: var->uniform = uniform; nkeynes@1207: var->type = type; nkeynes@1207: var->name = name; nkeynes@1207: shader->variables = g_list_append(shader->variables,var); nkeynes@1207: } nkeynes@1207: nkeynes@1207: static shader_t findShader( GList *shaders, const char *name ) nkeynes@1207: { nkeynes@1207: GList *ptr = shaders; nkeynes@1207: while( ptr != NULL ) { nkeynes@1207: shader_t shader = ptr->data; nkeynes@1207: if( strcmp(shader->name, name) == 0 ) nkeynes@1207: return shader; nkeynes@1207: ptr = ptr->next; nkeynes@1207: } nkeynes@1207: return NULL; nkeynes@1207: } nkeynes@1207: nkeynes@1207: static gboolean addProgramVariable( program_t program, variable_t variable ) nkeynes@1207: { nkeynes@1207: GList *ptr = program->variables; nkeynes@1207: while( ptr != NULL ) { nkeynes@1207: variable_t varp = ptr->data; nkeynes@1207: if( strcmp(varp->name, variable->name) == 0 ) { nkeynes@1207: if( varp->uniform == variable->uniform && strcmp(varp->type, variable->type) == 0 ) nkeynes@1207: return TRUE; /* All ok */ nkeynes@1207: fprintf( stderr, "Error: Variable type mismatch on '%s'\n", variable->name ); nkeynes@1207: return FALSE; nkeynes@1207: } nkeynes@1207: ptr = ptr->next; nkeynes@1207: } nkeynes@1207: program->variables = g_list_append(program->variables, variable); nkeynes@1207: return TRUE; nkeynes@1207: } nkeynes@1207: nkeynes@1207: static void linkPrograms( glsldata_t data ) nkeynes@1207: { nkeynes@1207: GList *program_ptr = data->programs; nkeynes@1207: unsigned i; nkeynes@1207: while( program_ptr != NULL ) { nkeynes@1207: program_t program = program_ptr->data; nkeynes@1207: for( i=0; program->shader_names[i] != NULL; i++ ) { nkeynes@1207: shader_t shader = findShader(data->shaders, program->shader_names[i]); nkeynes@1207: if( shader == NULL ) { nkeynes@1207: fprintf( stderr, "Error: unable to resolve shader '%s'\n", program->shader_names[i] );\ nkeynes@1207: } else { nkeynes@1207: GList *varptr = shader->variables; nkeynes@1207: while( varptr != NULL ) { nkeynes@1207: addProgramVariable(program, varptr->data); nkeynes@1207: varptr = varptr->next; nkeynes@1207: } nkeynes@1207: } nkeynes@1207: } nkeynes@1207: program_ptr = program_ptr->next; nkeynes@1207: } nkeynes@1207: nkeynes@1207: } nkeynes@1207: nkeynes@1235: static GList *temp_filenames = NULL; nkeynes@1207: nkeynes@1235: static void cleanup_tempfiles(void) nkeynes@1235: { nkeynes@1235: while( temp_filenames != NULL ) { nkeynes@1235: unlink( (char *)temp_filenames->data ); nkeynes@1235: g_free(temp_filenames->data); nkeynes@1235: temp_filenames = temp_filenames->next; nkeynes@1235: } nkeynes@1235: } nkeynes@1235: nkeynes@1235: /** nkeynes@1235: * Preprocess the input file and return a temporary filename containing the result nkeynes@1235: */ nkeynes@1235: static FILE *preprocessInput( const char *filename, GList *cpp_opts ) nkeynes@1235: { nkeynes@1235: char tmpname[] = "/tmp/genglsl.XXXXXXXX"; nkeynes@1235: int fd = mkstemp(tmpname); nkeynes@1235: if( fd == -1 ) { nkeynes@1235: fprintf( stderr, "Error: unable to get a temporary filename (%s)\n", strerror(errno) ); nkeynes@1235: exit(2); nkeynes@1235: } nkeynes@1235: char *quoted_filename = g_shell_quote(filename); nkeynes@1235: nkeynes@1235: int nOpts = g_list_length(cpp_opts); nkeynes@1235: gchar *quoted_opts_arr[nOpts]; nkeynes@1235: int length = 0, count=0; nkeynes@1235: for( GList *ptr = cpp_opts; ptr != NULL; ptr = ptr->next ) { nkeynes@1235: quoted_opts_arr[count] = g_shell_quote((gchar *)ptr->data); nkeynes@1235: length += strlen(quoted_opts_arr[count++]) + 1; nkeynes@1235: } nkeynes@1235: gchar quoted_cpp_opts[length]; nkeynes@1235: quoted_cpp_opts[0] = '\0'; nkeynes@1235: for( count=0; count %s", nkeynes@1235: BUILD_SED_PROG, quoted_filename, BUILD_CPP_PROG, quoted_cpp_opts, tmpname ); nkeynes@1235: if( system(command) != 0 ) { nkeynes@1235: fprintf( stderr, "Error: unable to run preprocessor command '%s' (%s)\n", command, strerror(errno) ); nkeynes@1235: exit(2); nkeynes@1235: } nkeynes@1235: nkeynes@1235: temp_filenames = g_list_append(temp_filenames, g_strdup(tmpname)); nkeynes@1235: return fdopen(fd, "r"); nkeynes@1235: } nkeynes@1235: nkeynes@1235: static void readInput( const char *filename, GList *cpp_opts, glsldata_t result ) nkeynes@1130: { nkeynes@1130: char buf[MAX_LINE]; nkeynes@1130: size_t current_size = 0, current_posn = 0; nkeynes@1130: unsigned i; nkeynes@1130: nkeynes@1235: nkeynes@1235: FILE *f = preprocessInput(filename, cpp_opts ); nkeynes@1130: if( f == NULL ) { nkeynes@1130: fprintf( stderr, "Error: unable to open input file '%s': %s\n", filename, strerror(errno) ); nkeynes@1234: exit(2); nkeynes@1130: } nkeynes@1130: nkeynes@1130: shader_t shader = NULL; nkeynes@1234: if( result->filename == NULL ) { nkeynes@1234: result->filename = g_strdup(filename); nkeynes@1234: } else { nkeynes@1234: const gchar *tmp = result->filename; nkeynes@1234: result->filename = g_strdup_printf("%s, %s", tmp, filename); nkeynes@1234: g_free((gchar *)tmp); nkeynes@1234: } nkeynes@1130: nkeynes@1130: while( fgets(buf, sizeof(buf), f) != NULL ) { nkeynes@1130: if( strlen(buf) == 0 ) nkeynes@1130: continue; nkeynes@1130: nkeynes@1235: if( buf[0] == '#' ) { nkeynes@1235: char *p = buf+1; nkeynes@1235: if( strncmp(p, "pragma ", 7) == 0 ) { nkeynes@1235: p += 7; nkeynes@1130: } nkeynes@1235: if( strncmp(p, "vertex ", 7) == 0 ) { nkeynes@1235: shader = g_malloc0(sizeof(struct shader)); nkeynes@1235: assert( shader != NULL ); nkeynes@1235: shader->type = VERTEX_SHADER; nkeynes@1235: shader->name = strdup(g_strstrip(p+7)); nkeynes@1235: shader->body = malloc(DEF_ALLOC_SIZE); nkeynes@1235: shader->body[0] = '\0'; nkeynes@1235: current_size = DEF_ALLOC_SIZE; nkeynes@1235: current_posn = 0; nkeynes@1235: result->shaders = g_list_append(result->shaders, shader); nkeynes@1235: } else if( strncmp( p, "fragment ", 9 ) == 0 ) { nkeynes@1235: shader = g_malloc0(sizeof(struct shader)); nkeynes@1235: assert( shader != NULL ); nkeynes@1235: shader->type = FRAGMENT_SHADER; nkeynes@1235: shader->name = strdup(g_strstrip(p+9)); nkeynes@1235: shader->body = malloc(DEF_ALLOC_SIZE); nkeynes@1235: shader->body[0] = '\0'; nkeynes@1235: current_size = DEF_ALLOC_SIZE; nkeynes@1235: current_posn = 0; nkeynes@1235: result->shaders = g_list_append(result->shaders, shader); nkeynes@1235: } else if( strncmp( p, "program ", 8 ) == 0 ) { nkeynes@1235: shader = NULL; nkeynes@1235: program_t program = g_malloc0(sizeof(struct program)); nkeynes@1235: char *rest = p+8; nkeynes@1235: char *equals = strchr(rest, '='); nkeynes@1235: if( equals == NULL ) { nkeynes@1235: fprintf( stderr, "Error: invalid program line %s\n", buf ); nkeynes@1235: exit(2); nkeynes@1235: } nkeynes@1235: *equals = '\0'; nkeynes@1235: program->name = g_strdup(g_strstrip(rest)); nkeynes@1235: program->shader_names = g_strsplit_set(g_strstrip(equals+1), " \t\r,", 0); nkeynes@1235: result->programs = g_list_append(result->programs, program); nkeynes@1235: for(i=0;program->shader_names[i] != NULL; i++ ); nkeynes@1235: if( i > result->max_shaders ) nkeynes@1235: result->max_shaders = i; nkeynes@1235: } nkeynes@1235: /* Else discard any other # lines */ nkeynes@1130: } else if( shader != NULL ) { nkeynes@1130: size_t len = strlen(buf); nkeynes@1130: if( current_posn + len > current_size ) { nkeynes@1130: shader->body = realloc(shader->body, current_size*2); nkeynes@1130: assert( shader->body != NULL ); nkeynes@1130: current_size *= 2; nkeynes@1130: } nkeynes@1130: strcpy( shader->body + current_posn, buf ); nkeynes@1130: current_posn += len; nkeynes@1207: char *line = g_strstrip(buf); nkeynes@1207: if( strncmp( line, "uniform ", 8 ) == 0 ) { nkeynes@1207: parseVarDecl(shader, TRUE, line+8); nkeynes@1207: } else if( strncmp( line, "attribute ", 10 ) == 0 ) { nkeynes@1207: parseVarDecl(shader, FALSE, line+10); nkeynes@1207: } nkeynes@1130: } nkeynes@1130: } nkeynes@1130: nkeynes@1130: fclose(f); nkeynes@1130: } nkeynes@405: nkeynes@405: /** nkeynes@405: * Copy input to output, quoting " characters as we go. nkeynes@405: */ nkeynes@1130: static void writeCString( FILE *out, const char *str ) nkeynes@405: { nkeynes@1130: const char *p = str; nkeynes@405: nkeynes@1130: while( *p != 0 ) { nkeynes@1130: if( *p == '\"' ) { nkeynes@736: fputc( '\\', out ); nkeynes@1130: } else if( *p == '\n' ) { nkeynes@736: fputs( "\\n\\", out ); nkeynes@736: } nkeynes@1130: fputc( *p, out ); nkeynes@1130: p++; nkeynes@1130: } nkeynes@1130: } nkeynes@1130: nkeynes@1207: static const char *sl_type_map[][3] = { nkeynes@1207: {"int", "int", "int *"}, nkeynes@1229: {"float", "float", "float *"}, nkeynes@1207: {"short", "short", "short *"}, nkeynes@1207: {"sampler", "int", "int *"}, nkeynes@1207: {"vec", "GLfloat *", "GLfloat *"}, nkeynes@1207: {"mat", "GLfloat *", "GLfloat *"}, nkeynes@1207: {NULL, NULL} nkeynes@1207: }; nkeynes@1207: nkeynes@1207: static const char *getCType( const char *sl_type, gboolean isUniform ) { nkeynes@1207: for( unsigned i=0; sl_type_map[i][0] != NULL; i++ ) { nkeynes@1207: if( strncmp(sl_type_map[i][0], sl_type, strlen(sl_type_map[i][0])) == 0 ) { nkeynes@1207: if( isUniform ) { nkeynes@1207: return sl_type_map[i][1]; nkeynes@1207: } else { nkeynes@1207: return sl_type_map[i][2]; nkeynes@1207: } nkeynes@1207: } nkeynes@1207: } nkeynes@1207: return "void *"; nkeynes@1207: } nkeynes@1207: nkeynes@1130: static void writeHeader( FILE *out, glsldata_t data ) nkeynes@1130: { nkeynes@1130: fprintf( out, "/*\n * This file automatically generated by genglsl from %s\n */\n", data->filename ); nkeynes@1130: } nkeynes@1130: nkeynes@1130: static void writeInterface( const char *filename, glsldata_t data ) nkeynes@1130: { nkeynes@1130: FILE *f = fopen(filename, "wo"); nkeynes@1130: if( f == NULL ) { nkeynes@1130: fprintf( stderr, "Error: Unable to write interface file '%s': %s\n", filename, strerror(errno) ); nkeynes@1130: exit(1); nkeynes@1130: } nkeynes@1130: nkeynes@1130: writeHeader( f, data ); nkeynes@1130: fprintf( f, "#ifndef lxdream_glsl_H\n#define lxdream_glsl_H 1\n\n" ); nkeynes@1130: nkeynes@1130: fprintf( f, "typedef enum {\n" ); nkeynes@1130: const char *last_name = NULL; nkeynes@1130: int count = 0; nkeynes@1130: GList *shader_ptr; nkeynes@1130: for( shader_ptr = data->shaders; shader_ptr != NULL; shader_ptr = shader_ptr->next ) { nkeynes@1130: count++; nkeynes@1130: shader_t shader = (shader_t)shader_ptr->data; nkeynes@1130: fprintf( f, " %s,\n", shader->name ); nkeynes@1130: last_name = shader->name; nkeynes@1130: } nkeynes@1130: fprintf( f, "} shader_id;\n\n" ); nkeynes@1130: nkeynes@1130: if( last_name == NULL ) nkeynes@1130: last_name = "NULL"; nkeynes@1130: fprintf( f, "#define GLSL_LAST_SHADER %s\n", last_name ); nkeynes@1130: fprintf( f, "#define GLSL_NUM_SHADERS %d\n", count ); nkeynes@1130: fprintf( f, "#define GLSL_NO_SHADER -1\n\n" ); nkeynes@1130: fprintf( f, "#define GLSL_VERTEX_SHADER 1\n" ); nkeynes@1130: fprintf( f, "#define GLSL_FRAGMENT_SHADER 2\n" ); nkeynes@1130: nkeynes@1130: count = 0; nkeynes@1130: GList *program_ptr; nkeynes@1130: for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) { nkeynes@1130: count++; nkeynes@1130: } nkeynes@1207: fprintf( f, "#define GLSL_NUM_PROGRAMS %d\n", count ); nkeynes@1130: nkeynes@1207: for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) { nkeynes@1207: program_t program = program_ptr->data; nkeynes@1207: GList *var_ptr; nkeynes@1207: fprintf( f, "void glsl_use_%s();\n", program->name ); nkeynes@1207: for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) { nkeynes@1207: variable_t var = var_ptr->data; nkeynes@1207: if( var->uniform ) { nkeynes@1207: fprintf( f, "void glsl_set_%s_%s(%s value); /* uniform %s %s */ \n", program->name, var->name, getCType(var->type,var->uniform), var->type, var->name ); nkeynes@1207: } else { nkeynes@1208: fprintf( f, "void glsl_set_%s_%s_pointer(%s ptr, GLint stride); /* attribute %s %s */ \n", program->name, var->name, getCType(var->type,var->uniform), var->type, var->name); nkeynes@1209: if( strcmp(var->type,"vec4") == 0 ) { /* Special case */ nkeynes@1240: fprintf( f, "void glsl_set_%s_%s_vec2_pointer(%s ptr, GLint stride); /* attribute %s %s */ \n", program->name, var->name, getCType(var->type,var->uniform), var->type, var->name); nkeynes@1209: fprintf( f, "void glsl_set_%s_%s_vec3_pointer(%s ptr, GLint stride); /* attribute %s %s */ \n", program->name, var->name, getCType(var->type,var->uniform), var->type, var->name); nkeynes@1209: } nkeynes@1207: } nkeynes@1207: } nkeynes@1207: } nkeynes@1130: nkeynes@1258: fprintf( f, "void glsl_clear_shader();\n" ); nkeynes@1258: nkeynes@1130: fprintf( f, "#endif /* !lxdream_glsl_H */\n" ); nkeynes@1130: nkeynes@1130: fclose(f); nkeynes@1130: } nkeynes@1130: nkeynes@1130: static void writeSource( const char *filename, glsldata_t data ) nkeynes@1130: { nkeynes@1130: FILE *f = fopen(filename, "wo"); nkeynes@1130: if( f == NULL ) { nkeynes@1130: fprintf( stderr, "Error: Unable to write interface file '%s': %s\n", filename, strerror(errno) ); nkeynes@1130: exit(1); nkeynes@1130: } nkeynes@1130: nkeynes@1130: writeHeader( f, data ); nkeynes@1130: fprintf( f, "struct shader_def {\n int type;\n const char *source;\n};\n" ); nkeynes@1130: nkeynes@1130: fprintf( f, "const struct shader_def shader_source[] = {\n" ); nkeynes@1130: GList *shader_ptr; nkeynes@1130: for( shader_ptr = data->shaders; shader_ptr != NULL; shader_ptr = shader_ptr->next ) { nkeynes@1130: shader_t shader = (shader_t)shader_ptr->data; nkeynes@1130: fprintf( f, " {%s,\"", (shader->type == VERTEX_SHADER ? "GLSL_VERTEX_SHADER" : "GLSL_FRAGMENT_SHADER") ); nkeynes@1130: writeCString( f, shader->body ); nkeynes@1130: fprintf( f, "\"},\n" ); nkeynes@1130: } nkeynes@1130: fprintf( f, " {GLSL_NO_SHADER,NULL}};\n\n" ); nkeynes@1130: nkeynes@1130: fprintf( f, "const int program_list[][%d] = {\n", data->max_shaders+1 ); nkeynes@1130: GList *program_ptr; nkeynes@1207: GList *var_ptr; nkeynes@1130: unsigned i; nkeynes@1130: for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) { nkeynes@1130: program_t program = (program_t)program_ptr->data; nkeynes@1130: fprintf( f, " {" ); nkeynes@1130: for( i=0; program->shader_names[i] != NULL; i++ ) { nkeynes@1130: fprintf(f, "%s,", program->shader_names[i] ); nkeynes@1130: } nkeynes@1130: fprintf( f, "GLSL_NO_SHADER},\n" ); nkeynes@1130: } nkeynes@1130: fprintf( f, " {GLSL_NO_SHADER}};\n" ); nkeynes@1130: nkeynes@1207: /* per-program functions */ nkeynes@1207: for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) { nkeynes@1207: program_t program = program_ptr->data; nkeynes@1207: fprintf( f, "\nstatic gl_program_t prog_%s_id;\n",program->name ); nkeynes@1207: for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) { nkeynes@1207: variable_t var = var_ptr->data; nkeynes@1207: fprintf( f, "static GLint var_%s_%s_loc;\n", program->name, var->name); nkeynes@1207: } nkeynes@1207: nkeynes@1207: } nkeynes@1207: for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) { nkeynes@1207: program_t program = program_ptr->data; nkeynes@1208: fprintf( f, "\nstatic void glsl_cleanup_%s() {\n", program->name ); nkeynes@1208: for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) { nkeynes@1208: variable_t var = var_ptr->data; nkeynes@1208: if( !var->uniform ) { nkeynes@1208: fprintf( f, " glsl_disable_attrib(var_%s_%s_loc);\n", program->name, var->name ); nkeynes@1208: } nkeynes@1208: } nkeynes@1208: fprintf( f, "}\n"); nkeynes@1208: nkeynes@1208: fprintf( f, "\nvoid glsl_use_%s() {\n", program->name ); nkeynes@1208: fprintf( f, " glsl_use_program(prog_%s_id);\n", program->name ); nkeynes@1229: fprintf( f, " glsl_set_cleanup_fn(glsl_cleanup_%s);\n", program->name ); nkeynes@1208: for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) { nkeynes@1208: variable_t var = var_ptr->data; nkeynes@1208: if( !var->uniform ) { nkeynes@1208: fprintf( f, " glsl_enable_attrib(var_%s_%s_loc);\n", program->name, var->name ); nkeynes@1208: } nkeynes@1208: } nkeynes@1208: fprintf( f, "}\n"); nkeynes@1208: nkeynes@1207: nkeynes@1207: for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) { nkeynes@1207: variable_t var = var_ptr->data; nkeynes@1207: if( var->uniform ) { nkeynes@1207: fprintf( f, "void glsl_set_%s_%s(%s value){ /* uniform %s %s */ \n", program->name, var->name, getCType(var->type,var->uniform), var->type, var->name ); nkeynes@1207: fprintf( f, " glsl_set_uniform_%s(var_%s_%s_loc,value);\n}\n", var->type, program->name, var->name ); nkeynes@1207: } else { nkeynes@1207: fprintf( f, "void glsl_set_%s_%s_pointer(%s ptr, GLsizei stride){ /* attribute %s %s */ \n", program->name, var->name, getCType(var->type,var->uniform), var->type, var->name); nkeynes@1207: fprintf( f, " glsl_set_attrib_%s(var_%s_%s_loc,stride, ptr);\n}\n", var->type, program->name, var->name ); nkeynes@1209: if( strcmp(var->type,"vec4") == 0 ) { /* Special case to load vec3 arrays into a vec4 */ nkeynes@1209: fprintf( f, "void glsl_set_%s_%s_vec3_pointer(%s ptr, GLsizei stride){ /* attribute %s %s */ \n", program->name, var->name, getCType(var->type,var->uniform), var->type, var->name); nkeynes@1209: fprintf( f, " glsl_set_attrib_vec3(var_%s_%s_loc,stride, ptr);\n}\n", program->name, var->name ); nkeynes@1240: fprintf( f, "void glsl_set_%s_%s_vec2_pointer(%s ptr, GLsizei stride){ /* attribute %s %s */ \n", program->name, var->name, getCType(var->type,var->uniform), var->type, var->name); nkeynes@1240: fprintf( f, " glsl_set_attrib_vec2(var_%s_%s_loc,stride, ptr);\n}\n", program->name, var->name ); nkeynes@1209: } nkeynes@1207: } nkeynes@1207: } nkeynes@1207: } nkeynes@1207: nkeynes@1258: fprintf( f, "\nvoid glsl_clear_shader() {\n" ); nkeynes@1258: fprintf( f, " glsl_run_cleanup_fn();\n glsl_use_program(0);\n}\n" ); nkeynes@1258: nkeynes@1207: fprintf( f, "\nstatic void glsl_init_programs( gl_program_t *ids ) {\n" ); nkeynes@1207: for( program_ptr = data->programs, i=0; program_ptr != NULL; program_ptr = program_ptr->next, i++ ) { nkeynes@1207: program_t program = program_ptr->data; nkeynes@1207: nkeynes@1207: fprintf( f, " prog_%s_id = ids[%d];\n\n", program->name, i ); nkeynes@1207: for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) { nkeynes@1207: variable_t var = var_ptr->data; nkeynes@1207: if( var->uniform ) { nkeynes@1207: fprintf( f, " var_%s_%s_loc = glsl_get_uniform_location(prog_%s_id, \"%s\");\n", program->name, var->name, program->name, var->name ); nkeynes@1207: } else { nkeynes@1207: fprintf( f, " var_%s_%s_loc = glsl_get_attrib_location(prog_%s_id, \"%s\");\n", program->name, var->name, program->name, var->name ); nkeynes@1207: } nkeynes@1207: } nkeynes@1207: } nkeynes@1258: nkeynes@1207: fprintf( f, "}\n" ); nkeynes@1207: nkeynes@1130: fclose(f); nkeynes@1130: } nkeynes@1130: nkeynes@1234: static const char *makeExtension(const char *basename, const char *ext) nkeynes@1130: { nkeynes@1130: const char *oldext = strrchr(basename, '.'); nkeynes@1130: if( oldext == NULL ) { nkeynes@1130: return g_strdup_printf("%s%s", basename, ext); nkeynes@1130: } else { nkeynes@1169: return g_strdup_printf("%.*s%s", (int)(oldext-basename), basename, ext); nkeynes@405: } nkeynes@405: } nkeynes@405: nkeynes@1235: static char *option_list = "hi:I:D:U:o:"; nkeynes@1234: static struct option long_option_list[] = { nkeynes@1234: { "help", no_argument, NULL, 'h' }, nkeynes@1235: { "interface", required_argument, NULL, 'i' }, nkeynes@1234: { "output", required_argument, NULL, 'o' }, nkeynes@1234: { NULL, 0, 0, 0 } }; nkeynes@1234: nkeynes@1234: static void usage() { nkeynes@1234: fprintf( stderr, "Usage: genglsl [-o output.def] [-i output.h]\n"); nkeynes@1234: } nkeynes@405: int main( int argc, char *argv[] ) nkeynes@405: { nkeynes@1234: const char *output_file = NULL; nkeynes@1234: const char *iface_file = NULL; nkeynes@1235: GList *cpp_opts = NULL; nkeynes@1234: int opt; nkeynes@1234: nkeynes@1234: while( (opt = getopt_long( argc, argv, option_list, long_option_list, NULL )) != -1 ) { nkeynes@1234: switch( opt ) { nkeynes@1234: case 'h': nkeynes@1234: usage(); nkeynes@1234: exit(0); nkeynes@1234: break; nkeynes@1235: case 'D': case 'I': case 'U': nkeynes@1235: cpp_opts = g_list_append(cpp_opts, g_strdup_printf( "-%c%s", opt, optarg )); nkeynes@1235: break; nkeynes@1234: case 'i': nkeynes@1234: if( iface_file != NULL ) { nkeynes@1234: fprintf( stderr, "Error: at most one interface file can be supplied\n" ); nkeynes@1234: usage(); nkeynes@1234: exit(1); nkeynes@1234: } nkeynes@1234: iface_file = optarg; nkeynes@1234: break; nkeynes@1234: case 'o': nkeynes@1234: if( output_file != NULL ) { nkeynes@1234: fprintf( stderr, "Error: at most one output file can be supplied\n" ); nkeynes@1234: usage(); nkeynes@1234: exit(1); nkeynes@1234: } nkeynes@1234: output_file = optarg; nkeynes@1234: } nkeynes@1234: } nkeynes@1234: nkeynes@1234: if( optind == argc ) { nkeynes@1234: usage(); nkeynes@736: exit(1); nkeynes@405: } nkeynes@405: nkeynes@1234: if( output_file == NULL ) { nkeynes@1234: output_file = makeExtension(argv[optind], ".def"); nkeynes@1234: } nkeynes@1234: if( iface_file == NULL ) { nkeynes@1234: iface_file = makeExtension(output_file, ".h"); nkeynes@405: } nkeynes@405: nkeynes@1235: atexit(cleanup_tempfiles); nkeynes@1234: glsldata_t data = g_malloc0(sizeof(struct glsldata)); nkeynes@1234: while( optind < argc ) { nkeynes@1235: readInput(argv[optind++], cpp_opts, data); nkeynes@405: } nkeynes@1234: linkPrograms(data); nkeynes@405: nkeynes@1234: writeSource( output_file, data ); nkeynes@1234: writeInterface( iface_file, data ); nkeynes@405: return 0; nkeynes@405: }