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@1130: * Copyright (c) 2007-2010 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@1130: #include nkeynes@1130: #include 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@1207: nkeynes@1130: static struct glsldata *readInput( const char *filename ) 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@1130: FILE *f = fopen( filename, "ro" ); nkeynes@1130: if( f == NULL ) { nkeynes@1130: fprintf( stderr, "Error: unable to open input file '%s': %s\n", filename, strerror(errno) ); nkeynes@1130: exit(1); nkeynes@1130: } nkeynes@1130: nkeynes@1130: shader_t shader = NULL; nkeynes@1207: glsldata_t result = g_malloc0(sizeof(struct glsldata)); nkeynes@1130: assert( result != NULL ); nkeynes@1130: result->filename = strdup(filename); nkeynes@1130: nkeynes@1130: while( fgets(buf, sizeof(buf), f) != NULL ) { nkeynes@1130: if( strlen(buf) == 0 ) nkeynes@1130: continue; nkeynes@1130: nkeynes@1130: if( strncmp(buf, "#vertex ", 8) == 0 ) { nkeynes@1207: shader = g_malloc0(sizeof(struct shader)); nkeynes@1130: assert( shader != NULL ); nkeynes@1130: shader->type = VERTEX_SHADER; nkeynes@1130: shader->name = strdup(g_strstrip(buf+8)); nkeynes@1130: shader->body = malloc(DEF_ALLOC_SIZE); nkeynes@1130: shader->body[0] = '\0'; nkeynes@1130: current_size = DEF_ALLOC_SIZE; nkeynes@1130: current_posn = 0; nkeynes@1130: result->shaders = g_list_append(result->shaders, shader); nkeynes@1130: } else if( strncmp( buf, "#fragment ", 10 ) == 0 ) { nkeynes@1207: shader = g_malloc0(sizeof(struct shader)); nkeynes@1130: assert( shader != NULL ); nkeynes@1130: shader->type = FRAGMENT_SHADER; nkeynes@1130: shader->name = strdup(g_strstrip(buf+10)); nkeynes@1130: shader->body = malloc(DEF_ALLOC_SIZE); nkeynes@1130: shader->body[0] = '\0'; nkeynes@1130: current_size = DEF_ALLOC_SIZE; nkeynes@1130: current_posn = 0; nkeynes@1130: result->shaders = g_list_append(result->shaders, shader); nkeynes@1130: } else if( strncmp( buf, "#program ", 9 ) == 0 ) { nkeynes@1130: shader = NULL; nkeynes@1207: program_t program = g_malloc0(sizeof(struct program)); nkeynes@1130: char *rest = buf+9; nkeynes@1130: char *equals = strchr(rest, '='); nkeynes@1130: if( equals == NULL ) { nkeynes@1130: fprintf( stderr, "Error: invalid program line %s\n", buf ); nkeynes@1130: exit(2); nkeynes@1130: } nkeynes@1130: *equals = '\0'; nkeynes@1130: program->name = g_strdup(g_strstrip(rest)); nkeynes@1130: program->shader_names = g_strsplit_set(g_strstrip(equals+1), " \t\r,", 0); nkeynes@1130: result->programs = g_list_append(result->programs, program); nkeynes@1130: for(i=0;program->shader_names[i] != NULL; i++ ); nkeynes@1130: if( i > result->max_shaders ) nkeynes@1130: result->max_shaders = i; 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@1207: linkPrograms(result); nkeynes@1130: return result; 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@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@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@1209: } nkeynes@1207: } nkeynes@1207: } nkeynes@1207: } nkeynes@1207: 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@1207: fprintf( f, "}\n" ); nkeynes@1207: nkeynes@1130: fclose(f); nkeynes@1130: } nkeynes@1130: nkeynes@1130: 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@405: int main( int argc, char *argv[] ) nkeynes@405: { nkeynes@1130: if( argc < 2 ) { nkeynes@1130: fprintf( stderr, "Usage: genglsl [output.c [output.h]]\n"); nkeynes@736: exit(1); nkeynes@405: } nkeynes@405: nkeynes@1130: glsldata_t data = readInput(argv[1]); nkeynes@1130: nkeynes@1130: const char *sourcefile, *ifacefile; nkeynes@1130: if( argc > 2 ) { nkeynes@1130: sourcefile = argv[2]; nkeynes@1130: } else { nkeynes@1130: sourcefile = makeExtension(argv[1], ".def"); nkeynes@405: } nkeynes@405: nkeynes@1130: if( argc > 3 ) { nkeynes@1130: ifacefile = argv[3]; nkeynes@1130: } else { nkeynes@1130: ifacefile = makeExtension(sourcefile, ".h"); nkeynes@405: } nkeynes@405: nkeynes@1130: writeSource( sourcefile, data ); nkeynes@1130: writeInterface( ifacefile, data ); nkeynes@405: return 0; nkeynes@405: }