Search
lxdream.org :: lxdream/src/tools/genglsl.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/tools/genglsl.c
changeset 1209:e606e65eaf54
prev1208:6955202d6408
next1229:dc935eee9767
author nkeynes
date Sun Feb 12 16:30:26 2012 +1000 (12 years ago)
permissions -rw-r--r--
last change Add -Werror for mregparm check, so it actually fails if mregparm isn't
accepted
file annotate diff log raw
nkeynes@405
     1
/**
nkeynes@561
     2
 * $Id$
nkeynes@405
     3
 *
nkeynes@1130
     4
 * Tool to take an input .glsl file and write out a corresponding .c and .h
nkeynes@1130
     5
 * file based on the content. The .glsl file contains a number of shaders
nkeynes@1130
     6
 * marked with either #fragment <name> or #vertex <name>
nkeynes@1130
     7
 * a C file with appropriate escaping, as well as program definitions
nkeynes@1130
     8
 * written as #program <name> = <shader1> <shader2> ... <shaderN>
nkeynes@405
     9
 *
nkeynes@1130
    10
 * Copyright (c) 2007-2010 Nathan Keynes.
nkeynes@405
    11
 *
nkeynes@405
    12
 * This program is free software; you can redistribute it and/or modify
nkeynes@405
    13
 * it under the terms of the GNU General Public License as published by
nkeynes@405
    14
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@405
    15
 * (at your option) any later version.
nkeynes@405
    16
 *
nkeynes@405
    17
 * This program is distributed in the hope that it will be useful,
nkeynes@405
    18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@405
    19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@405
    20
 * GNU General Public License for more details.
nkeynes@405
    21
 */
nkeynes@405
    22
nkeynes@1130
    23
#include <assert.h>
nkeynes@1207
    24
#include <ctype.h>
nkeynes@1130
    25
#include <errno.h>
nkeynes@405
    26
#include <stdio.h>
nkeynes@405
    27
#include <stdlib.h>
nkeynes@1130
    28
#include <string.h>
nkeynes@1130
    29
#include <glib/gstrfuncs.h>
nkeynes@1130
    30
#include <glib/glist.h>
nkeynes@1130
    31
nkeynes@1130
    32
#define MAX_LINE 4096
nkeynes@1130
    33
#define DEF_ALLOC_SIZE 4096
nkeynes@1130
    34
#define MAX_SHADERS 128
nkeynes@1130
    35
nkeynes@1130
    36
typedef enum {
nkeynes@1130
    37
    VERTEX_SHADER = 0,
nkeynes@1130
    38
    FRAGMENT_SHADER = 1
nkeynes@1130
    39
} shader_type_t;
nkeynes@1130
    40
nkeynes@1207
    41
typedef struct variable {
nkeynes@1207
    42
    gboolean uniform; /* TRUE = uniform, FALSE = attribute */
nkeynes@1207
    43
    const char *name;
nkeynes@1207
    44
    const char *type;
nkeynes@1207
    45
} *variable_t;
nkeynes@1207
    46
nkeynes@1130
    47
typedef struct shader {
nkeynes@1130
    48
    shader_type_t type;
nkeynes@1130
    49
    const char *name;
nkeynes@1130
    50
    char *body;
nkeynes@1207
    51
    GList *variables;
nkeynes@1130
    52
} *shader_t;
nkeynes@1130
    53
nkeynes@1130
    54
typedef struct program {
nkeynes@1130
    55
    const char *name;
nkeynes@1130
    56
    gchar **shader_names;
nkeynes@1207
    57
    GList *shaders;
nkeynes@1207
    58
    GList *variables;
nkeynes@1130
    59
} *program_t;
nkeynes@1130
    60
nkeynes@1130
    61
typedef struct glsldata {
nkeynes@1130
    62
    const char *filename;
nkeynes@1130
    63
    unsigned max_shaders;
nkeynes@1130
    64
    GList *shaders;
nkeynes@1130
    65
    GList *programs;
nkeynes@1130
    66
} *glsldata_t;
nkeynes@1130
    67
nkeynes@1207
    68
#define isident(c) (isalnum(c)||(c)=='_')
nkeynes@1207
    69
nkeynes@1207
    70
static void parseVarDecl( shader_t shader, gboolean uniform, char *input )
nkeynes@1207
    71
{
nkeynes@1207
    72
    unsigned i;
nkeynes@1207
    73
    char *p = g_strstrip(input);
nkeynes@1207
    74
    for( i=0; isident(p[i]); i++)
nkeynes@1207
    75
    if( p[i] == 0 ) {
nkeynes@1207
    76
        fprintf( stderr, "Error: unable to parse variable decl '%s'\n", p );
nkeynes@1207
    77
        return; /* incomplete decl? */
nkeynes@1207
    78
    }
nkeynes@1207
    79
    char *type = g_strndup(p, i);
nkeynes@1207
    80
    p = g_strstrip(input+i);
nkeynes@1207
    81
    for( i=0; isident(p[i]); i++)
nkeynes@1207
    82
    if( p[i] == 0 ) {
nkeynes@1207
    83
        fprintf( stderr, "Error: unable to parse variable decl '%s'\n", p );
nkeynes@1207
    84
        return; /* incomplete decl? */
nkeynes@1207
    85
    }
nkeynes@1207
    86
    char *name = g_strndup(p, i);
nkeynes@1207
    87
    variable_t var = g_malloc0(sizeof(struct variable));
nkeynes@1207
    88
    var->uniform = uniform;
nkeynes@1207
    89
    var->type = type;
nkeynes@1207
    90
    var->name = name;
nkeynes@1207
    91
    shader->variables = g_list_append(shader->variables,var);
nkeynes@1207
    92
}
nkeynes@1207
    93
nkeynes@1207
    94
static shader_t findShader( GList *shaders, const char *name )
nkeynes@1207
    95
{
nkeynes@1207
    96
    GList *ptr = shaders;
nkeynes@1207
    97
    while( ptr != NULL ) {
nkeynes@1207
    98
        shader_t shader = ptr->data;
nkeynes@1207
    99
        if( strcmp(shader->name, name) == 0 )
nkeynes@1207
   100
            return shader;
nkeynes@1207
   101
        ptr = ptr->next;
nkeynes@1207
   102
    }
nkeynes@1207
   103
    return NULL;
nkeynes@1207
   104
}
nkeynes@1207
   105
nkeynes@1207
   106
static gboolean addProgramVariable( program_t program, variable_t variable )
nkeynes@1207
   107
{
nkeynes@1207
   108
    GList *ptr = program->variables;
nkeynes@1207
   109
    while( ptr != NULL ) {
nkeynes@1207
   110
        variable_t varp = ptr->data;
nkeynes@1207
   111
        if( strcmp(varp->name, variable->name) == 0 ) {
nkeynes@1207
   112
            if( varp->uniform == variable->uniform && strcmp(varp->type, variable->type) == 0 )
nkeynes@1207
   113
                return TRUE; /* All ok */
nkeynes@1207
   114
            fprintf( stderr, "Error: Variable type mismatch on '%s'\n", variable->name );
nkeynes@1207
   115
            return FALSE;
nkeynes@1207
   116
        }
nkeynes@1207
   117
        ptr = ptr->next;
nkeynes@1207
   118
    }
nkeynes@1207
   119
    program->variables = g_list_append(program->variables, variable);
nkeynes@1207
   120
    return TRUE;
nkeynes@1207
   121
}
nkeynes@1207
   122
nkeynes@1207
   123
static void linkPrograms( glsldata_t data )
nkeynes@1207
   124
{
nkeynes@1207
   125
    GList *program_ptr = data->programs;
nkeynes@1207
   126
    unsigned i;
nkeynes@1207
   127
    while( program_ptr != NULL ) {
nkeynes@1207
   128
        program_t program = program_ptr->data;
nkeynes@1207
   129
        for( i=0; program->shader_names[i] != NULL; i++ ) {
nkeynes@1207
   130
            shader_t shader = findShader(data->shaders, program->shader_names[i]);
nkeynes@1207
   131
            if( shader == NULL ) {
nkeynes@1207
   132
                fprintf( stderr, "Error: unable to resolve shader '%s'\n", program->shader_names[i] );\
nkeynes@1207
   133
            } else {
nkeynes@1207
   134
                GList *varptr = shader->variables;
nkeynes@1207
   135
                while( varptr != NULL ) {
nkeynes@1207
   136
                    addProgramVariable(program, varptr->data);
nkeynes@1207
   137
                    varptr = varptr->next;
nkeynes@1207
   138
                }
nkeynes@1207
   139
            }
nkeynes@1207
   140
        }
nkeynes@1207
   141
        program_ptr = program_ptr->next;
nkeynes@1207
   142
    }
nkeynes@1207
   143
nkeynes@1207
   144
}
nkeynes@1207
   145
nkeynes@1207
   146
nkeynes@1130
   147
static struct glsldata *readInput( const char *filename )
nkeynes@1130
   148
{
nkeynes@1130
   149
    char buf[MAX_LINE];
nkeynes@1130
   150
    size_t current_size = 0, current_posn = 0;
nkeynes@1130
   151
    unsigned i;
nkeynes@1130
   152
nkeynes@1130
   153
    FILE *f = fopen( filename, "ro" );
nkeynes@1130
   154
    if( f == NULL ) {
nkeynes@1130
   155
        fprintf( stderr, "Error: unable to open input file '%s': %s\n", filename, strerror(errno) );
nkeynes@1130
   156
        exit(1);
nkeynes@1130
   157
    }
nkeynes@1130
   158
nkeynes@1130
   159
    shader_t shader = NULL;
nkeynes@1207
   160
    glsldata_t result = g_malloc0(sizeof(struct glsldata));
nkeynes@1130
   161
    assert( result != NULL );
nkeynes@1130
   162
    result->filename = strdup(filename);
nkeynes@1130
   163
nkeynes@1130
   164
    while( fgets(buf, sizeof(buf), f) != NULL ) {
nkeynes@1130
   165
        if( strlen(buf) == 0 )
nkeynes@1130
   166
            continue;
nkeynes@1130
   167
nkeynes@1130
   168
        if( strncmp(buf, "#vertex ", 8) == 0 ) {
nkeynes@1207
   169
            shader = g_malloc0(sizeof(struct shader));
nkeynes@1130
   170
            assert( shader != NULL );
nkeynes@1130
   171
            shader->type = VERTEX_SHADER;
nkeynes@1130
   172
            shader->name = strdup(g_strstrip(buf+8));
nkeynes@1130
   173
            shader->body = malloc(DEF_ALLOC_SIZE);
nkeynes@1130
   174
            shader->body[0] = '\0';
nkeynes@1130
   175
            current_size = DEF_ALLOC_SIZE;
nkeynes@1130
   176
            current_posn = 0;
nkeynes@1130
   177
            result->shaders = g_list_append(result->shaders, shader);
nkeynes@1130
   178
        } else if( strncmp( buf, "#fragment ", 10 ) == 0 ) {
nkeynes@1207
   179
            shader = g_malloc0(sizeof(struct shader));
nkeynes@1130
   180
            assert( shader != NULL );
nkeynes@1130
   181
            shader->type = FRAGMENT_SHADER;
nkeynes@1130
   182
            shader->name = strdup(g_strstrip(buf+10));
nkeynes@1130
   183
            shader->body = malloc(DEF_ALLOC_SIZE);
nkeynes@1130
   184
            shader->body[0] = '\0';
nkeynes@1130
   185
            current_size = DEF_ALLOC_SIZE;
nkeynes@1130
   186
            current_posn = 0;
nkeynes@1130
   187
            result->shaders = g_list_append(result->shaders, shader);
nkeynes@1130
   188
        } else if( strncmp( buf, "#program ", 9 ) == 0 ) {
nkeynes@1130
   189
            shader = NULL;
nkeynes@1207
   190
            program_t program = g_malloc0(sizeof(struct program));
nkeynes@1130
   191
            char *rest = buf+9;
nkeynes@1130
   192
            char *equals = strchr(rest, '=');
nkeynes@1130
   193
            if( equals == NULL ) {
nkeynes@1130
   194
                fprintf( stderr, "Error: invalid program line %s\n", buf );
nkeynes@1130
   195
                exit(2);
nkeynes@1130
   196
            }
nkeynes@1130
   197
            *equals = '\0';
nkeynes@1130
   198
            program->name = g_strdup(g_strstrip(rest));
nkeynes@1130
   199
            program->shader_names = g_strsplit_set(g_strstrip(equals+1), " \t\r,", 0);
nkeynes@1130
   200
            result->programs = g_list_append(result->programs, program);
nkeynes@1130
   201
            for(i=0;program->shader_names[i] != NULL; i++ );
nkeynes@1130
   202
            if( i > result->max_shaders )
nkeynes@1130
   203
                result->max_shaders = i;
nkeynes@1130
   204
        } else if( shader != NULL ) {
nkeynes@1130
   205
            size_t len = strlen(buf);
nkeynes@1130
   206
            if( current_posn + len > current_size ) {
nkeynes@1130
   207
                shader->body = realloc(shader->body, current_size*2);
nkeynes@1130
   208
                assert( shader->body != NULL );
nkeynes@1130
   209
                current_size *= 2;
nkeynes@1130
   210
            }
nkeynes@1130
   211
            strcpy( shader->body + current_posn, buf );
nkeynes@1130
   212
            current_posn += len;
nkeynes@1207
   213
            char *line = g_strstrip(buf);
nkeynes@1207
   214
            if( strncmp( line, "uniform ", 8 ) == 0 ) {
nkeynes@1207
   215
                parseVarDecl(shader, TRUE, line+8);
nkeynes@1207
   216
            } else if( strncmp( line, "attribute ", 10 ) == 0 ) {
nkeynes@1207
   217
                parseVarDecl(shader, FALSE, line+10);
nkeynes@1207
   218
            }
nkeynes@1130
   219
        }
nkeynes@1130
   220
    }
nkeynes@1130
   221
nkeynes@1130
   222
    fclose(f);
nkeynes@1207
   223
    linkPrograms(result);
nkeynes@1130
   224
    return result;
nkeynes@1130
   225
}
nkeynes@405
   226
nkeynes@405
   227
/**
nkeynes@405
   228
 * Copy input to output, quoting " characters as we go.
nkeynes@405
   229
 */
nkeynes@1130
   230
static void writeCString( FILE *out, const char *str )
nkeynes@405
   231
{
nkeynes@1130
   232
    const char *p = str;
nkeynes@405
   233
nkeynes@1130
   234
    while( *p != 0 ) {
nkeynes@1130
   235
        if( *p == '\"' ) {
nkeynes@736
   236
            fputc( '\\', out );
nkeynes@1130
   237
        } else if( *p == '\n' ) {
nkeynes@736
   238
            fputs( "\\n\\", out );
nkeynes@736
   239
        }
nkeynes@1130
   240
        fputc( *p, out );
nkeynes@1130
   241
        p++;
nkeynes@1130
   242
    }
nkeynes@1130
   243
}
nkeynes@1130
   244
nkeynes@1207
   245
static const char *sl_type_map[][3] = {
nkeynes@1207
   246
        {"int", "int", "int *"},
nkeynes@1207
   247
        {"short", "short", "short *"},
nkeynes@1207
   248
        {"sampler", "int", "int *"},
nkeynes@1207
   249
        {"vec", "GLfloat *", "GLfloat *"},
nkeynes@1207
   250
        {"mat", "GLfloat *", "GLfloat *"},
nkeynes@1207
   251
        {NULL, NULL}
nkeynes@1207
   252
};
nkeynes@1207
   253
nkeynes@1207
   254
static const char *getCType( const char *sl_type, gboolean isUniform ) {
nkeynes@1207
   255
    for( unsigned i=0; sl_type_map[i][0] != NULL; i++ ) {
nkeynes@1207
   256
        if( strncmp(sl_type_map[i][0], sl_type, strlen(sl_type_map[i][0])) == 0 ) {
nkeynes@1207
   257
            if( isUniform ) {
nkeynes@1207
   258
                return sl_type_map[i][1];
nkeynes@1207
   259
            } else {
nkeynes@1207
   260
                return sl_type_map[i][2];
nkeynes@1207
   261
            }
nkeynes@1207
   262
        }
nkeynes@1207
   263
    }
nkeynes@1207
   264
    return "void *";
nkeynes@1207
   265
}
nkeynes@1207
   266
nkeynes@1130
   267
static void writeHeader( FILE *out, glsldata_t data )
nkeynes@1130
   268
{
nkeynes@1130
   269
    fprintf( out, "/*\n * This file automatically generated by genglsl from %s\n */\n", data->filename );
nkeynes@1130
   270
}
nkeynes@1130
   271
nkeynes@1130
   272
static void writeInterface( const char *filename, glsldata_t data )
nkeynes@1130
   273
{
nkeynes@1130
   274
    FILE *f = fopen(filename, "wo");
nkeynes@1130
   275
    if( f == NULL ) {
nkeynes@1130
   276
        fprintf( stderr, "Error: Unable to write interface file '%s': %s\n", filename, strerror(errno) );
nkeynes@1130
   277
        exit(1);
nkeynes@1130
   278
    }
nkeynes@1130
   279
nkeynes@1130
   280
    writeHeader( f, data );
nkeynes@1130
   281
    fprintf( f, "#ifndef lxdream_glsl_H\n#define lxdream_glsl_H 1\n\n" );
nkeynes@1130
   282
nkeynes@1130
   283
    fprintf( f, "typedef enum {\n" );
nkeynes@1130
   284
    const char *last_name = NULL;
nkeynes@1130
   285
    int count = 0;
nkeynes@1130
   286
    GList *shader_ptr;
nkeynes@1130
   287
    for( shader_ptr = data->shaders; shader_ptr != NULL; shader_ptr = shader_ptr->next ) {
nkeynes@1130
   288
        count++;
nkeynes@1130
   289
        shader_t shader = (shader_t)shader_ptr->data;
nkeynes@1130
   290
        fprintf( f, "    %s,\n", shader->name );
nkeynes@1130
   291
        last_name = shader->name;
nkeynes@1130
   292
    }
nkeynes@1130
   293
    fprintf( f, "} shader_id;\n\n" );
nkeynes@1130
   294
nkeynes@1130
   295
    if( last_name == NULL )
nkeynes@1130
   296
        last_name = "NULL";
nkeynes@1130
   297
    fprintf( f, "#define GLSL_LAST_SHADER %s\n", last_name );
nkeynes@1130
   298
    fprintf( f, "#define GLSL_NUM_SHADERS %d\n", count );
nkeynes@1130
   299
    fprintf( f, "#define GLSL_NO_SHADER -1\n\n" );
nkeynes@1130
   300
    fprintf( f, "#define GLSL_VERTEX_SHADER 1\n" );
nkeynes@1130
   301
    fprintf( f, "#define GLSL_FRAGMENT_SHADER 2\n" );
nkeynes@1130
   302
nkeynes@1130
   303
    count = 0;
nkeynes@1130
   304
    GList *program_ptr;
nkeynes@1130
   305
    for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
nkeynes@1130
   306
        count++;
nkeynes@1130
   307
    }
nkeynes@1207
   308
    fprintf( f, "#define GLSL_NUM_PROGRAMS %d\n", count );
nkeynes@1130
   309
nkeynes@1207
   310
    for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
nkeynes@1207
   311
        program_t program = program_ptr->data;
nkeynes@1207
   312
        GList *var_ptr;
nkeynes@1207
   313
        fprintf( f, "void glsl_use_%s();\n", program->name );
nkeynes@1207
   314
        for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
nkeynes@1207
   315
            variable_t var = var_ptr->data;
nkeynes@1207
   316
            if( var->uniform ) {
nkeynes@1207
   317
                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
   318
            } else {
nkeynes@1208
   319
                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
   320
                if( strcmp(var->type,"vec4") == 0 ) { /* Special case */
nkeynes@1209
   321
                    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
   322
                }
nkeynes@1207
   323
            }
nkeynes@1207
   324
        }
nkeynes@1207
   325
    }
nkeynes@1130
   326
nkeynes@1130
   327
    fprintf( f, "#endif /* !lxdream_glsl_H */\n" );
nkeynes@1130
   328
nkeynes@1130
   329
    fclose(f);
nkeynes@1130
   330
}
nkeynes@1130
   331
nkeynes@1130
   332
static void writeSource( const char *filename, glsldata_t data )
nkeynes@1130
   333
{
nkeynes@1130
   334
    FILE *f = fopen(filename, "wo");
nkeynes@1130
   335
    if( f == NULL ) {
nkeynes@1130
   336
        fprintf( stderr, "Error: Unable to write interface file '%s': %s\n", filename, strerror(errno) );
nkeynes@1130
   337
        exit(1);
nkeynes@1130
   338
    }
nkeynes@1130
   339
nkeynes@1130
   340
    writeHeader( f, data );
nkeynes@1130
   341
    fprintf( f, "struct shader_def {\n    int type;\n    const char *source;\n};\n" );
nkeynes@1130
   342
nkeynes@1130
   343
    fprintf( f, "const struct shader_def shader_source[] = {\n" );
nkeynes@1130
   344
    GList *shader_ptr;
nkeynes@1130
   345
    for( shader_ptr = data->shaders; shader_ptr != NULL; shader_ptr = shader_ptr->next ) {
nkeynes@1130
   346
        shader_t shader = (shader_t)shader_ptr->data;
nkeynes@1130
   347
        fprintf( f, "    {%s,\"", (shader->type == VERTEX_SHADER ? "GLSL_VERTEX_SHADER" : "GLSL_FRAGMENT_SHADER") );
nkeynes@1130
   348
        writeCString( f, shader->body );
nkeynes@1130
   349
        fprintf( f, "\"},\n" );
nkeynes@1130
   350
    }
nkeynes@1130
   351
    fprintf( f, "    {GLSL_NO_SHADER,NULL}};\n\n" );
nkeynes@1130
   352
nkeynes@1130
   353
    fprintf( f, "const int program_list[][%d] = {\n", data->max_shaders+1 );
nkeynes@1130
   354
    GList *program_ptr;
nkeynes@1207
   355
    GList *var_ptr;
nkeynes@1130
   356
    unsigned i;
nkeynes@1130
   357
    for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
nkeynes@1130
   358
        program_t program = (program_t)program_ptr->data;
nkeynes@1130
   359
        fprintf( f, "    {" );
nkeynes@1130
   360
        for( i=0; program->shader_names[i] != NULL; i++ ) {
nkeynes@1130
   361
            fprintf(f, "%s,", program->shader_names[i] );
nkeynes@1130
   362
        }
nkeynes@1130
   363
        fprintf( f, "GLSL_NO_SHADER},\n" );
nkeynes@1130
   364
    }
nkeynes@1130
   365
    fprintf( f, "    {GLSL_NO_SHADER}};\n" );
nkeynes@1130
   366
nkeynes@1207
   367
    /* per-program functions */
nkeynes@1207
   368
    for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
nkeynes@1207
   369
        program_t program = program_ptr->data;
nkeynes@1207
   370
        fprintf( f, "\nstatic gl_program_t prog_%s_id;\n",program->name );
nkeynes@1207
   371
        for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
nkeynes@1207
   372
            variable_t var = var_ptr->data;
nkeynes@1207
   373
            fprintf( f, "static GLint var_%s_%s_loc;\n", program->name, var->name);
nkeynes@1207
   374
        }
nkeynes@1207
   375
nkeynes@1207
   376
    }
nkeynes@1207
   377
    for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
nkeynes@1207
   378
        program_t program = program_ptr->data;
nkeynes@1208
   379
        fprintf( f, "\nstatic void glsl_cleanup_%s() {\n", program->name );
nkeynes@1208
   380
        for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
nkeynes@1208
   381
            variable_t var = var_ptr->data;
nkeynes@1208
   382
            if( !var->uniform ) {
nkeynes@1208
   383
                fprintf( f, "    glsl_disable_attrib(var_%s_%s_loc);\n", program->name, var->name );
nkeynes@1208
   384
            }
nkeynes@1208
   385
        }
nkeynes@1208
   386
        fprintf( f, "}\n");
nkeynes@1208
   387
nkeynes@1208
   388
        fprintf( f, "\nvoid glsl_use_%s() {\n", program->name );
nkeynes@1208
   389
        fprintf( f, "    glsl_use_program(prog_%s_id);\n", program->name );
nkeynes@1208
   390
        for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
nkeynes@1208
   391
            variable_t var = var_ptr->data;
nkeynes@1208
   392
            if( !var->uniform ) {
nkeynes@1208
   393
                fprintf( f, "    glsl_enable_attrib(var_%s_%s_loc);\n", program->name, var->name );
nkeynes@1208
   394
            }
nkeynes@1208
   395
        }
nkeynes@1208
   396
        fprintf( f, "    glsl_set_cleanup_fn(glsl_cleanup_%s);\n", program->name );
nkeynes@1208
   397
        fprintf( f, "}\n");
nkeynes@1208
   398
nkeynes@1207
   399
nkeynes@1207
   400
        for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
nkeynes@1207
   401
            variable_t var = var_ptr->data;
nkeynes@1207
   402
            if( var->uniform ) {
nkeynes@1207
   403
                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
   404
                fprintf( f, "    glsl_set_uniform_%s(var_%s_%s_loc,value);\n}\n", var->type, program->name, var->name );
nkeynes@1207
   405
            } else {
nkeynes@1207
   406
                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
   407
                fprintf( f, "    glsl_set_attrib_%s(var_%s_%s_loc,stride, ptr);\n}\n", var->type, program->name, var->name );
nkeynes@1209
   408
                if( strcmp(var->type,"vec4") == 0 ) { /* Special case to load vec3 arrays into a vec4 */
nkeynes@1209
   409
                    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
   410
                    fprintf( f, "    glsl_set_attrib_vec3(var_%s_%s_loc,stride, ptr);\n}\n", program->name, var->name );
nkeynes@1209
   411
                }
nkeynes@1207
   412
            }
nkeynes@1207
   413
        }
nkeynes@1207
   414
    }
nkeynes@1207
   415
nkeynes@1207
   416
    fprintf( f, "\nstatic void glsl_init_programs( gl_program_t *ids ) {\n" );
nkeynes@1207
   417
    for( program_ptr = data->programs, i=0; program_ptr != NULL; program_ptr = program_ptr->next, i++ ) {
nkeynes@1207
   418
        program_t program = program_ptr->data;
nkeynes@1207
   419
nkeynes@1207
   420
        fprintf( f, "    prog_%s_id = ids[%d];\n\n", program->name, i );
nkeynes@1207
   421
        for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
nkeynes@1207
   422
            variable_t var = var_ptr->data;
nkeynes@1207
   423
            if( var->uniform ) {
nkeynes@1207
   424
                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
   425
            } else {
nkeynes@1207
   426
                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
   427
            }
nkeynes@1207
   428
        }
nkeynes@1207
   429
    }
nkeynes@1207
   430
    fprintf( f, "}\n" );
nkeynes@1207
   431
nkeynes@1130
   432
    fclose(f);
nkeynes@1130
   433
}
nkeynes@1130
   434
nkeynes@1130
   435
const char *makeExtension(const char *basename, const char *ext)
nkeynes@1130
   436
{
nkeynes@1130
   437
    const char *oldext = strrchr(basename, '.');
nkeynes@1130
   438
    if( oldext == NULL ) {
nkeynes@1130
   439
        return g_strdup_printf("%s%s", basename, ext);
nkeynes@1130
   440
    } else {
nkeynes@1169
   441
        return g_strdup_printf("%.*s%s", (int)(oldext-basename), basename, ext);
nkeynes@405
   442
    }
nkeynes@405
   443
}
nkeynes@405
   444
nkeynes@405
   445
int main( int argc, char *argv[] )
nkeynes@405
   446
{
nkeynes@1130
   447
    if( argc < 2 ) {
nkeynes@1130
   448
        fprintf( stderr, "Usage: genglsl <glsl-source-file> [output.c [output.h]]\n");
nkeynes@736
   449
        exit(1);
nkeynes@405
   450
    }
nkeynes@405
   451
nkeynes@1130
   452
    glsldata_t data = readInput(argv[1]);
nkeynes@1130
   453
nkeynes@1130
   454
    const char *sourcefile, *ifacefile;
nkeynes@1130
   455
    if( argc > 2 ) {
nkeynes@1130
   456
        sourcefile = argv[2];
nkeynes@1130
   457
    } else {
nkeynes@1130
   458
        sourcefile = makeExtension(argv[1], ".def");
nkeynes@405
   459
    }
nkeynes@405
   460
nkeynes@1130
   461
    if( argc > 3 ) {
nkeynes@1130
   462
        ifacefile = argv[3];
nkeynes@1130
   463
    } else {
nkeynes@1130
   464
        ifacefile = makeExtension(sourcefile, ".h");
nkeynes@405
   465
    }
nkeynes@405
   466
nkeynes@1130
   467
    writeSource( sourcefile, data );
nkeynes@1130
   468
    writeInterface( ifacefile, data );
nkeynes@405
   469
    return 0;
nkeynes@405
   470
}
.