Search
lxdream.org :: lxdream/src/tools/genglsl.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/tools/genglsl.c
changeset 1296:30ecee61f811
prev1288:fdb8f59143c7
author nkeynes
date Sat Jan 26 14:00:48 2013 +1000 (8 years ago)
permissions -rw-r--r--
last change Change glib includes to #include <glib.h> rather than the individual
headers, as recent glib versions are breaking on this
view annotate diff log raw
     1 /**
     2  * $Id$
     3  *
     4  * Tool to take an input .glsl file and write out a corresponding .c and .h
     5  * file based on the content. The .glsl file contains a number of shaders
     6  * marked with either #fragment <name> or #vertex <name>
     7  * a C file with appropriate escaping, as well as program definitions
     8  * written as #program <name> = <shader1> <shader2> ... <shaderN>
     9  *
    10  * Copyright (c) 2007-2012 Nathan Keynes.
    11  *
    12  * This program is free software; you can redistribute it and/or modify
    13  * it under the terms of the GNU General Public License as published by
    14  * the Free Software Foundation; either version 2 of the License, or
    15  * (at your option) any later version.
    16  *
    17  * This program is distributed in the hope that it will be useful,
    18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    20  * GNU General Public License for more details.
    21  */
    23 #include <assert.h>
    24 #include <ctype.h>
    25 #include <errno.h>
    26 #include <stdio.h>
    27 #include <stdlib.h>
    28 #include <string.h>
    29 #include <getopt.h>
    30 #include <glib.h>
    31 #include "../../config.h"
    33 #define MAX_LINE 4096
    34 #define DEF_ALLOC_SIZE 4096
    35 #define MAX_SHADERS 128
    37 typedef enum {
    38     VERTEX_SHADER = 0,
    39     FRAGMENT_SHADER = 1
    40 } shader_type_t;
    42 typedef struct variable {
    43     gboolean uniform; /* TRUE = uniform, FALSE = attribute */
    44     const char *name;
    45     const char *type;
    46 } *variable_t;
    48 typedef struct shader {
    49     shader_type_t type;
    50     const char *name;
    51     char *body;
    52     GList *variables;
    53 } *shader_t;
    55 typedef struct program {
    56     const char *name;
    57     gchar **shader_names;
    58     GList *shaders;
    59     GList *variables;
    60 } *program_t;
    62 typedef struct glsldata {
    63     const char *filename;
    64     unsigned max_shaders;
    65     GList *shaders;
    66     GList *programs;
    67 } *glsldata_t;
    69 #define isident(c) (isalnum(c)||(c)=='_')
    71 static void parseVarDecl( shader_t shader, gboolean uniform, char *input )
    72 {
    73     unsigned i;
    74     char *p = g_strstrip(input);
    75     for( i=0; isident(p[i]); i++)
    76     if( p[i] == 0 ) {
    77         fprintf( stderr, "Error: unable to parse variable decl '%s'\n", p );
    78         return; /* incomplete decl? */
    79     }
    80     char *type = g_strndup(p, i);
    81     p = g_strstrip(input+i);
    82     for( i=0; isident(p[i]); i++)
    83     if( p[i] == 0 ) {
    84         fprintf( stderr, "Error: unable to parse variable decl '%s'\n", p );
    85         return; /* incomplete decl? */
    86     }
    87     char *name = g_strndup(p, i);
    88     variable_t var = g_malloc0(sizeof(struct variable));
    89     var->uniform = uniform;
    90     var->type = type;
    91     var->name = name;
    92     shader->variables = g_list_append(shader->variables,var);
    93 }
    95 static shader_t findShader( GList *shaders, const char *name )
    96 {
    97     GList *ptr = shaders;
    98     while( ptr != NULL ) {
    99         shader_t shader = ptr->data;
   100         if( strcmp(shader->name, name) == 0 )
   101             return shader;
   102         ptr = ptr->next;
   103     }
   104     return NULL;
   105 }
   107 static gboolean addProgramVariable( program_t program, variable_t variable )
   108 {
   109     GList *ptr = program->variables;
   110     while( ptr != NULL ) {
   111         variable_t varp = ptr->data;
   112         if( strcmp(varp->name, variable->name) == 0 ) {
   113             if( varp->uniform == variable->uniform && strcmp(varp->type, variable->type) == 0 )
   114                 return TRUE; /* All ok */
   115             fprintf( stderr, "Error: Variable type mismatch on '%s'\n", variable->name );
   116             return FALSE;
   117         }
   118         ptr = ptr->next;
   119     }
   120     program->variables = g_list_append(program->variables, variable);
   121     return TRUE;
   122 }
   124 static void linkPrograms( glsldata_t data )
   125 {
   126     GList *program_ptr = data->programs;
   127     unsigned i;
   128     while( program_ptr != NULL ) {
   129         program_t program = program_ptr->data;
   130         for( i=0; program->shader_names[i] != NULL; i++ ) {
   131             shader_t shader = findShader(data->shaders, program->shader_names[i]);
   132             if( shader == NULL ) {
   133                 fprintf( stderr, "Error: unable to resolve shader '%s'\n", program->shader_names[i] );\
   134             } else {
   135                 GList *varptr = shader->variables;
   136                 while( varptr != NULL ) {
   137                     addProgramVariable(program, varptr->data);
   138                     varptr = varptr->next;
   139                 }
   140             }
   141         }
   142         program_ptr = program_ptr->next;
   143     }
   145 }
   147 static GList *temp_filenames = NULL;
   149 static void cleanup_tempfiles(void)
   150 {
   151    while( temp_filenames != NULL ) {
   152        unlink( (char *)temp_filenames->data );
   153        g_free(temp_filenames->data);
   154        temp_filenames = temp_filenames->next;
   155    }
   156 }
   158 /**
   159  * Preprocess the input file and return a temporary filename containing the result
   160  */
   161 static FILE *preprocessInput( const char *filename, GList *cpp_opts )
   162 {
   163     char tmpname[] = "/tmp/genglsl.XXXXXXXX";
   164     int fd = mkstemp(tmpname);
   165     if( fd == -1 ) {
   166         fprintf( stderr, "Error: unable to get a temporary filename (%s)\n", strerror(errno) );
   167         exit(2);
   168     }
   169     char *quoted_filename = g_shell_quote(filename);
   171     int nOpts = g_list_length(cpp_opts);
   172     gchar *quoted_opts_arr[nOpts];
   173     int length = 0, count=0;
   174     for( GList *ptr = cpp_opts; ptr != NULL; ptr = ptr->next ) {
   175         quoted_opts_arr[count] = g_shell_quote((gchar *)ptr->data);
   176         length += strlen(quoted_opts_arr[count++]) + 1;
   177     }
   178     gchar quoted_cpp_opts[length];
   179     quoted_cpp_opts[0] = '\0';
   180     for( count=0; count<nOpts; count++ ) {
   181         if( count != 0 )
   182             strcat(quoted_cpp_opts, " ");
   183         strcat(quoted_cpp_opts, quoted_opts_arr[count]);
   184         g_free(quoted_opts_arr[count++]);
   185     }
   187     const char *command = g_strdup_printf("%s -e 's/^#program/#pragma program/' -e 's/^#fragment/#pragma fragment/' -e 's/#vertex/#pragma vertex/' %s | %s %s - > %s",
   188             BUILD_SED_PROG, quoted_filename, BUILD_CPP_PROG, quoted_cpp_opts, tmpname );
   189     if( system(command) != 0 ) {
   190         fprintf( stderr, "Error: unable to run preprocessor command '%s' (%s)\n",  command, strerror(errno) );
   191         exit(2);
   192     }
   194     temp_filenames = g_list_append(temp_filenames, g_strdup(tmpname));
   195     return fdopen(fd, "r");
   196 }
   198 static void readInput( const char *filename, GList *cpp_opts, glsldata_t result )
   199 {
   200     char buf[MAX_LINE];
   201     size_t current_size = 0, current_posn = 0;
   202     unsigned i;
   205     FILE *f = preprocessInput(filename, cpp_opts );
   206     if( f == NULL ) {
   207         fprintf( stderr, "Error: unable to open input file '%s': %s\n", filename, strerror(errno) );
   208         exit(2);
   209     }
   211     shader_t shader = NULL;
   212     if( result->filename == NULL ) {
   213         result->filename = g_strdup(filename);
   214     } else {
   215         const gchar *tmp = result->filename;
   216         result->filename = g_strdup_printf("%s, %s", tmp, filename);
   217         g_free((gchar *)tmp);
   218     }
   220     while( fgets(buf, sizeof(buf), f) != NULL ) {
   221         if( strlen(buf) == 0 )
   222             continue;
   224         if( buf[0] == '#' ) {
   225             char *p = buf+1;
   226             if( strncmp(p, "pragma ", 7) == 0 ) {
   227                 p += 7;
   228             }
   229             if( strncmp(p, "vertex ", 7) == 0 ) {
   230                 shader = g_malloc0(sizeof(struct shader));
   231                 assert( shader != NULL );
   232                 shader->type = VERTEX_SHADER;
   233                 shader->name = strdup(g_strstrip(p+7));
   234                 shader->body = malloc(DEF_ALLOC_SIZE);
   235                 shader->body[0] = '\0';
   236                 current_size = DEF_ALLOC_SIZE;
   237                 current_posn = 0;
   238                 result->shaders = g_list_append(result->shaders, shader);
   239             } else if( strncmp( p, "fragment ", 9 ) == 0 ) {
   240                 shader = g_malloc0(sizeof(struct shader));
   241                 assert( shader != NULL );
   242                 shader->type = FRAGMENT_SHADER;
   243                 shader->name = strdup(g_strstrip(p+9));
   244                 shader->body = malloc(DEF_ALLOC_SIZE);
   245                 shader->body[0] = '\0';
   246                 current_size = DEF_ALLOC_SIZE;
   247                 current_posn = 0;
   248                 result->shaders = g_list_append(result->shaders, shader);
   249             } else if( strncmp( p, "program ", 8 ) == 0 ) {
   250                 shader = NULL;
   251                 program_t program = g_malloc0(sizeof(struct program));
   252                 char *rest = p+8;
   253                 char *equals = strchr(rest, '=');
   254                 if( equals == NULL ) {
   255                     fprintf( stderr, "Error: invalid program line %s\n", buf );
   256                     exit(2);
   257                 }
   258                 *equals = '\0';
   259                 program->name = g_strdup(g_strstrip(rest));
   260                 program->shader_names = g_strsplit_set(g_strstrip(equals+1), " \t\r,", 0);
   261                 result->programs = g_list_append(result->programs, program);
   262                 for(i=0;program->shader_names[i] != NULL; i++ );
   263                 if( i > result->max_shaders )
   264                     result->max_shaders = i;
   265             }
   266             /* Else discard any other # lines */
   267         } else if( shader != NULL ) {
   268             size_t len = strlen(buf);
   269             if( current_posn + len > current_size ) {
   270                 shader->body = realloc(shader->body, current_size*2);
   271                 assert( shader->body != NULL );
   272                 current_size *= 2;
   273             }
   274             strcpy( shader->body + current_posn, buf );
   275             current_posn += len;
   276             char *line = g_strstrip(buf);
   277             if( strncmp( line, "uniform ", 8 ) == 0 ) {
   278                 parseVarDecl(shader, TRUE, line+8);
   279             } else if( strncmp( line, "attribute ", 10 ) == 0 ) {
   280                 parseVarDecl(shader, FALSE, line+10);
   281             }
   282         }
   283     }
   285     fclose(f);
   286 }
   288 /**
   289  * Copy input to output, quoting " characters as we go.
   290  */
   291 static void writeCString( FILE *out, const char *str )
   292 {
   293     const char *p = str;
   295     while( *p != 0 ) {
   296         if( *p == '\"' ) {
   297             fputc( '\\', out );
   298         } else if( *p == '\n' ) {
   299             fputs( "\\n\\", out );
   300         }
   301         fputc( *p, out );
   302         p++;
   303     }
   304 }
   306 static const char *sl_type_map[][3] = {
   307         {"int", "int", "int *"},
   308         {"float", "float", "float *"},
   309         {"short", "short", "short *"},
   310         {"sampler", "int", "int *"},
   311         {"vec", "GLfloat *", "GLfloat *"},
   312         {"mat", "GLfloat *", "GLfloat *"},
   313         {NULL, NULL}
   314 };
   316 static const char *getCType( const char *sl_type, gboolean isUniform ) {
   317     for( unsigned i=0; sl_type_map[i][0] != NULL; i++ ) {
   318         if( strncmp(sl_type_map[i][0], sl_type, strlen(sl_type_map[i][0])) == 0 ) {
   319             if( isUniform ) {
   320                 return sl_type_map[i][1];
   321             } else {
   322                 return sl_type_map[i][2];
   323             }
   324         }
   325     }
   326     return "void *";
   327 }
   329 static void writeHeader( FILE *out, glsldata_t data )
   330 {
   331     fprintf( out, "/*\n * This file automatically generated by genglsl from %s\n */\n", data->filename );
   332 }
   334 static void writeInterface( const char *filename, glsldata_t data )
   335 {
   336     FILE *f = fopen(filename, "wo");
   337     if( f == NULL ) {
   338         fprintf( stderr, "Error: Unable to write interface file '%s': %s\n", filename, strerror(errno) );
   339         exit(1);
   340     }
   342     writeHeader( f, data );
   343     fprintf( f, "#ifndef lxdream_glsl_H\n#define lxdream_glsl_H 1\n\n" );
   345     fprintf( f, "typedef enum {\n" );
   346     const char *last_name = NULL;
   347     int count = 0;
   348     GList *shader_ptr;
   349     for( shader_ptr = data->shaders; shader_ptr != NULL; shader_ptr = shader_ptr->next ) {
   350         count++;
   351         shader_t shader = (shader_t)shader_ptr->data;
   352         fprintf( f, "    %s,\n", shader->name );
   353         last_name = shader->name;
   354     }
   355     fprintf( f, "} shader_id;\n\n" );
   357     if( last_name == NULL )
   358         last_name = "NULL";
   359     fprintf( f, "#define GLSL_LAST_SHADER %s\n", last_name );
   360     fprintf( f, "#define GLSL_NUM_SHADERS %d\n", count );
   361     fprintf( f, "#define GLSL_NO_SHADER -1\n\n" );
   362     fprintf( f, "#define GLSL_VERTEX_SHADER 1\n" );
   363     fprintf( f, "#define GLSL_FRAGMENT_SHADER 2\n" );
   365     count = 0;
   366     GList *program_ptr;
   367     for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
   368         count++;
   369     }
   370     fprintf( f, "#define GLSL_NUM_PROGRAMS %d\n", count );
   372     for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
   373         program_t program = program_ptr->data;
   374         GList *var_ptr;
   375         fprintf( f, "void glsl_use_%s();\n", program->name );
   376         for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
   377             variable_t var = var_ptr->data;
   378             if( var->uniform ) {
   379                 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 );
   380             } else {
   381                 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);
   382                 if( strcmp(var->type,"vec4") == 0 ) { /* Special case */
   383                     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);
   384                     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);
   385                 }
   386             }
   387         }
   388     }
   390     fprintf( f, "void glsl_clear_shader();\n" );
   392     fprintf( f, "#endif /* !lxdream_glsl_H */\n" );
   394     fclose(f);
   395 }
   397 static void writeSource( const char *filename, glsldata_t data )
   398 {
   399     FILE *f = fopen(filename, "wo");
   400     if( f == NULL ) {
   401         fprintf( stderr, "Error: Unable to write interface file '%s': %s\n", filename, strerror(errno) );
   402         exit(1);
   403     }
   405     writeHeader( f, data );
   406     fprintf( f, "struct shader_def {\n    int type;\n    const char *source;\n};\n" );
   408     fprintf( f, "const struct shader_def shader_source[] = {\n" );
   409     GList *shader_ptr;
   410     for( shader_ptr = data->shaders; shader_ptr != NULL; shader_ptr = shader_ptr->next ) {
   411         shader_t shader = (shader_t)shader_ptr->data;
   412         fprintf( f, "    {%s,\"", (shader->type == VERTEX_SHADER ? "GLSL_VERTEX_SHADER" : "GLSL_FRAGMENT_SHADER") );
   413         writeCString( f, shader->body );
   414         fprintf( f, "\"},\n" );
   415     }
   416     fprintf( f, "    {GLSL_NO_SHADER,NULL}};\n\n" );
   418     fprintf( f, "const int program_list[][%d] = {\n", data->max_shaders+1 );
   419     GList *program_ptr;
   420     GList *var_ptr;
   421     unsigned i;
   422     for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
   423         program_t program = (program_t)program_ptr->data;
   424         fprintf( f, "    {" );
   425         for( i=0; program->shader_names[i] != NULL; i++ ) {
   426             fprintf(f, "%s,", program->shader_names[i] );
   427         }
   428         fprintf( f, "GLSL_NO_SHADER},\n" );
   429     }
   430     fprintf( f, "    {GLSL_NO_SHADER}};\n" );
   432     /* per-program functions */
   433     for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
   434         program_t program = program_ptr->data;
   435         fprintf( f, "\nstatic gl_program_t prog_%s_id;\n",program->name );
   436         for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
   437             variable_t var = var_ptr->data;
   438             fprintf( f, "static GLint var_%s_%s_loc;\n", program->name, var->name);
   439         }
   441     }
   442     for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
   443         program_t program = program_ptr->data;
   444         fprintf( f, "\nstatic void glsl_cleanup_%s() {\n", program->name );
   445         for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
   446             variable_t var = var_ptr->data;
   447             if( !var->uniform ) {
   448                 fprintf( f, "    glsl_disable_attrib(var_%s_%s_loc);\n", program->name, var->name );
   449             }
   450         }
   451         fprintf( f, "}\n");
   453         fprintf( f, "\nvoid glsl_use_%s() {\n", program->name );
   454         fprintf( f, "    glsl_use_program(prog_%s_id);\n", program->name );
   455         fprintf( f, "    glsl_set_cleanup_fn(glsl_cleanup_%s);\n", program->name );
   456         for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
   457             variable_t var = var_ptr->data;
   458             if( !var->uniform ) {
   459                 fprintf( f, "    glsl_enable_attrib(var_%s_%s_loc);\n", program->name, var->name );
   460             }
   461         }
   462         fprintf( f, "}\n");
   465         for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
   466             variable_t var = var_ptr->data;
   467             if( var->uniform ) {
   468                 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 );
   469                 fprintf( f, "    glsl_set_uniform_%s(var_%s_%s_loc,value);\n}\n", var->type, program->name, var->name );
   470             } else {
   471                 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);
   472                 fprintf( f, "    glsl_set_attrib_%s(var_%s_%s_loc,stride, ptr);\n}\n", var->type, program->name, var->name );
   473                 if( strcmp(var->type,"vec4") == 0 ) { /* Special case to load vec3 arrays into a vec4 */
   474                     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);
   475                     fprintf( f, "    glsl_set_attrib_vec3(var_%s_%s_loc,stride, ptr);\n}\n", program->name, var->name );
   476                     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);
   477                     fprintf( f, "    glsl_set_attrib_vec2(var_%s_%s_loc,stride, ptr);\n}\n", program->name, var->name );
   478                 }
   479             }
   480         }
   481     }
   483     fprintf( f, "\nvoid glsl_clear_shader() {\n" );
   484     fprintf( f, "    glsl_run_cleanup_fn();\n    glsl_use_program(0);\n}\n" );
   486     fprintf( f, "\nstatic void glsl_init_programs( gl_program_t *ids ) {\n" );
   487     for( program_ptr = data->programs, i=0; program_ptr != NULL; program_ptr = program_ptr->next, i++ ) {
   488         program_t program = program_ptr->data;
   490         fprintf( f, "    prog_%s_id = ids[%d];\n\n", program->name, i );
   491         for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
   492             variable_t var = var_ptr->data;
   493             if( var->uniform ) {
   494                 fprintf( f, "    var_%s_%s_loc = glsl_get_uniform_location(prog_%s_id, \"%s\");\n", program->name, var->name, program->name, var->name );
   495             } else {
   496                 fprintf( f, "    var_%s_%s_loc = glsl_get_attrib_location(prog_%s_id, \"%s\");\n", program->name, var->name, program->name, var->name );
   497             }
   498         }
   499     }
   501     fprintf( f, "}\n" );
   503     fclose(f);
   504 }
   506 static const char *makeExtension(const char *basename, const char *ext)
   507 {
   508     const char *oldext = strrchr(basename, '.');
   509     if( oldext == NULL ) {
   510         return g_strdup_printf("%s%s", basename, ext);
   511     } else {
   512         return g_strdup_printf("%.*s%s", (int)(oldext-basename), basename, ext);
   513     }
   514 }
   516 static char *option_list = "hi:I:D:U:o:";
   517 static struct option long_option_list[] = {
   518         { "help", no_argument, NULL, 'h' },
   519         { "interface", required_argument, NULL, 'i' },
   520         { "output", required_argument, NULL, 'o' },
   521         { NULL, 0, 0, 0 } };
   523 static void usage() {
   524     fprintf( stderr, "Usage: genglsl <glsl-source-list> [-o output.def] [-i output.h]\n");
   525 }
   526 int main( int argc, char *argv[] )
   527 {
   528     const char *output_file = NULL;
   529     const char *iface_file = NULL;
   530     GList *cpp_opts = NULL;
   531     int opt;
   533     while( (opt = getopt_long( argc, argv, option_list, long_option_list, NULL )) != -1 ) {
   534         switch( opt ) {
   535         case 'h':
   536             usage();
   537             exit(0);
   538             break;
   539         case 'D': case 'I': case 'U':
   540             cpp_opts = g_list_append(cpp_opts, g_strdup_printf( "-%c%s", opt, optarg ));
   541             break;
   542         case 'i':
   543             if( iface_file != NULL ) {
   544                 fprintf( stderr, "Error: at most one interface file can be supplied\n" );
   545                 usage();
   546                 exit(1);
   547             }
   548             iface_file = optarg;
   549             break;
   550         case 'o':
   551             if( output_file != NULL ) {
   552                 fprintf( stderr, "Error: at most one output file can be supplied\n" );
   553                 usage();
   554                 exit(1);
   555             }
   556             output_file = optarg;
   557         }
   558     }
   560     if( optind == argc ) {
   561         usage();
   562         exit(1);
   563     }
   565     if( output_file == NULL ) {
   566         output_file = makeExtension(argv[optind], ".def");
   567     }
   568     if( iface_file == NULL ) {
   569         iface_file = makeExtension(output_file, ".h");
   570     }
   572     atexit(cleanup_tempfiles);
   573     glsldata_t data = g_malloc0(sizeof(struct glsldata));
   574     while( optind < argc ) {
   575         readInput(argv[optind++], cpp_opts, data);
   576     }
   577     linkPrograms(data);
   579     writeSource( output_file, data );
   580     writeInterface( iface_file, data );
   581     return 0;
   582 }
.