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 Fri May 29 18:47:05 2015 +1000 (6 years ago)
permissions -rw-r--r--
last change Fix test case
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@1234
    10
 * Copyright (c) 2007-2012 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@1234
    29
#include <getopt.h>
nkeynes@1296
    30
#include <glib.h>
nkeynes@1235
    31
#include "../../config.h"
nkeynes@1130
    32
nkeynes@1130
    33
#define MAX_LINE 4096
nkeynes@1130
    34
#define DEF_ALLOC_SIZE 4096
nkeynes@1130
    35
#define MAX_SHADERS 128
nkeynes@1130
    36
nkeynes@1130
    37
typedef enum {
nkeynes@1130
    38
    VERTEX_SHADER = 0,
nkeynes@1130
    39
    FRAGMENT_SHADER = 1
nkeynes@1130
    40
} shader_type_t;
nkeynes@1130
    41
nkeynes@1207
    42
typedef struct variable {
nkeynes@1207
    43
    gboolean uniform; /* TRUE = uniform, FALSE = attribute */
nkeynes@1207
    44
    const char *name;
nkeynes@1207
    45
    const char *type;
nkeynes@1207
    46
} *variable_t;
nkeynes@1207
    47
nkeynes@1130
    48
typedef struct shader {
nkeynes@1130
    49
    shader_type_t type;
nkeynes@1130
    50
    const char *name;
nkeynes@1130
    51
    char *body;
nkeynes@1207
    52
    GList *variables;
nkeynes@1130
    53
} *shader_t;
nkeynes@1130
    54
nkeynes@1130
    55
typedef struct program {
nkeynes@1130
    56
    const char *name;
nkeynes@1130
    57
    gchar **shader_names;
nkeynes@1207
    58
    GList *shaders;
nkeynes@1207
    59
    GList *variables;
nkeynes@1130
    60
} *program_t;
nkeynes@1130
    61
nkeynes@1130
    62
typedef struct glsldata {
nkeynes@1130
    63
    const char *filename;
nkeynes@1130
    64
    unsigned max_shaders;
nkeynes@1130
    65
    GList *shaders;
nkeynes@1130
    66
    GList *programs;
nkeynes@1130
    67
} *glsldata_t;
nkeynes@1130
    68
nkeynes@1207
    69
#define isident(c) (isalnum(c)||(c)=='_')
nkeynes@1207
    70
nkeynes@1207
    71
static void parseVarDecl( shader_t shader, gboolean uniform, char *input )
nkeynes@1207
    72
{
nkeynes@1207
    73
    unsigned i;
nkeynes@1207
    74
    char *p = g_strstrip(input);
nkeynes@1207
    75
    for( i=0; isident(p[i]); i++)
nkeynes@1207
    76
    if( p[i] == 0 ) {
nkeynes@1207
    77
        fprintf( stderr, "Error: unable to parse variable decl '%s'\n", p );
nkeynes@1207
    78
        return; /* incomplete decl? */
nkeynes@1207
    79
    }
nkeynes@1207
    80
    char *type = g_strndup(p, i);
nkeynes@1207
    81
    p = g_strstrip(input+i);
nkeynes@1207
    82
    for( i=0; isident(p[i]); i++)
nkeynes@1207
    83
    if( p[i] == 0 ) {
nkeynes@1207
    84
        fprintf( stderr, "Error: unable to parse variable decl '%s'\n", p );
nkeynes@1207
    85
        return; /* incomplete decl? */
nkeynes@1207
    86
    }
nkeynes@1207
    87
    char *name = g_strndup(p, i);
nkeynes@1207
    88
    variable_t var = g_malloc0(sizeof(struct variable));
nkeynes@1207
    89
    var->uniform = uniform;
nkeynes@1207
    90
    var->type = type;
nkeynes@1207
    91
    var->name = name;
nkeynes@1207
    92
    shader->variables = g_list_append(shader->variables,var);
nkeynes@1207
    93
}
nkeynes@1207
    94
nkeynes@1207
    95
static shader_t findShader( GList *shaders, const char *name )
nkeynes@1207
    96
{
nkeynes@1207
    97
    GList *ptr = shaders;
nkeynes@1207
    98
    while( ptr != NULL ) {
nkeynes@1207
    99
        shader_t shader = ptr->data;
nkeynes@1207
   100
        if( strcmp(shader->name, name) == 0 )
nkeynes@1207
   101
            return shader;
nkeynes@1207
   102
        ptr = ptr->next;
nkeynes@1207
   103
    }
nkeynes@1207
   104
    return NULL;
nkeynes@1207
   105
}
nkeynes@1207
   106
nkeynes@1207
   107
static gboolean addProgramVariable( program_t program, variable_t variable )
nkeynes@1207
   108
{
nkeynes@1207
   109
    GList *ptr = program->variables;
nkeynes@1207
   110
    while( ptr != NULL ) {
nkeynes@1207
   111
        variable_t varp = ptr->data;
nkeynes@1207
   112
        if( strcmp(varp->name, variable->name) == 0 ) {
nkeynes@1207
   113
            if( varp->uniform == variable->uniform && strcmp(varp->type, variable->type) == 0 )
nkeynes@1207
   114
                return TRUE; /* All ok */
nkeynes@1207
   115
            fprintf( stderr, "Error: Variable type mismatch on '%s'\n", variable->name );
nkeynes@1207
   116
            return FALSE;
nkeynes@1207
   117
        }
nkeynes@1207
   118
        ptr = ptr->next;
nkeynes@1207
   119
    }
nkeynes@1207
   120
    program->variables = g_list_append(program->variables, variable);
nkeynes@1207
   121
    return TRUE;
nkeynes@1207
   122
}
nkeynes@1207
   123
nkeynes@1207
   124
static void linkPrograms( glsldata_t data )
nkeynes@1207
   125
{
nkeynes@1207
   126
    GList *program_ptr = data->programs;
nkeynes@1207
   127
    unsigned i;
nkeynes@1207
   128
    while( program_ptr != NULL ) {
nkeynes@1207
   129
        program_t program = program_ptr->data;
nkeynes@1207
   130
        for( i=0; program->shader_names[i] != NULL; i++ ) {
nkeynes@1207
   131
            shader_t shader = findShader(data->shaders, program->shader_names[i]);
nkeynes@1207
   132
            if( shader == NULL ) {
nkeynes@1207
   133
                fprintf( stderr, "Error: unable to resolve shader '%s'\n", program->shader_names[i] );\
nkeynes@1207
   134
            } else {
nkeynes@1207
   135
                GList *varptr = shader->variables;
nkeynes@1207
   136
                while( varptr != NULL ) {
nkeynes@1207
   137
                    addProgramVariable(program, varptr->data);
nkeynes@1207
   138
                    varptr = varptr->next;
nkeynes@1207
   139
                }
nkeynes@1207
   140
            }
nkeynes@1207
   141
        }
nkeynes@1207
   142
        program_ptr = program_ptr->next;
nkeynes@1207
   143
    }
nkeynes@1207
   144
nkeynes@1207
   145
}
nkeynes@1207
   146
nkeynes@1235
   147
static GList *temp_filenames = NULL;
nkeynes@1207
   148
nkeynes@1235
   149
static void cleanup_tempfiles(void)
nkeynes@1235
   150
{
nkeynes@1235
   151
   while( temp_filenames != NULL ) {
nkeynes@1235
   152
       unlink( (char *)temp_filenames->data );
nkeynes@1235
   153
       g_free(temp_filenames->data);
nkeynes@1235
   154
       temp_filenames = temp_filenames->next;
nkeynes@1235
   155
   }
nkeynes@1235
   156
}
nkeynes@1235
   157
nkeynes@1235
   158
/**
nkeynes@1235
   159
 * Preprocess the input file and return a temporary filename containing the result
nkeynes@1235
   160
 */
nkeynes@1235
   161
static FILE *preprocessInput( const char *filename, GList *cpp_opts )
nkeynes@1235
   162
{
nkeynes@1235
   163
    char tmpname[] = "/tmp/genglsl.XXXXXXXX";
nkeynes@1235
   164
    int fd = mkstemp(tmpname);
nkeynes@1235
   165
    if( fd == -1 ) {
nkeynes@1235
   166
        fprintf( stderr, "Error: unable to get a temporary filename (%s)\n", strerror(errno) );
nkeynes@1235
   167
        exit(2);
nkeynes@1235
   168
    }
nkeynes@1235
   169
    char *quoted_filename = g_shell_quote(filename);
nkeynes@1235
   170
nkeynes@1235
   171
    int nOpts = g_list_length(cpp_opts);
nkeynes@1235
   172
    gchar *quoted_opts_arr[nOpts];
nkeynes@1235
   173
    int length = 0, count=0;
nkeynes@1235
   174
    for( GList *ptr = cpp_opts; ptr != NULL; ptr = ptr->next ) {
nkeynes@1235
   175
        quoted_opts_arr[count] = g_shell_quote((gchar *)ptr->data);
nkeynes@1235
   176
        length += strlen(quoted_opts_arr[count++]) + 1;
nkeynes@1235
   177
    }
nkeynes@1235
   178
    gchar quoted_cpp_opts[length];
nkeynes@1235
   179
    quoted_cpp_opts[0] = '\0';
nkeynes@1235
   180
    for( count=0; count<nOpts; count++ ) {
nkeynes@1235
   181
        if( count != 0 )
nkeynes@1235
   182
            strcat(quoted_cpp_opts, " ");
nkeynes@1235
   183
        strcat(quoted_cpp_opts, quoted_opts_arr[count]);
nkeynes@1235
   184
        g_free(quoted_opts_arr[count++]);
nkeynes@1235
   185
    }
nkeynes@1235
   186
nkeynes@1288
   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",
nkeynes@1235
   188
            BUILD_SED_PROG, quoted_filename, BUILD_CPP_PROG, quoted_cpp_opts, tmpname );
nkeynes@1235
   189
    if( system(command) != 0 ) {
nkeynes@1235
   190
        fprintf( stderr, "Error: unable to run preprocessor command '%s' (%s)\n",  command, strerror(errno) );
nkeynes@1235
   191
        exit(2);
nkeynes@1235
   192
    }
nkeynes@1235
   193
nkeynes@1235
   194
    temp_filenames = g_list_append(temp_filenames, g_strdup(tmpname));
nkeynes@1235
   195
    return fdopen(fd, "r");
nkeynes@1235
   196
}
nkeynes@1235
   197
nkeynes@1235
   198
static void readInput( const char *filename, GList *cpp_opts, glsldata_t result )
nkeynes@1130
   199
{
nkeynes@1130
   200
    char buf[MAX_LINE];
nkeynes@1130
   201
    size_t current_size = 0, current_posn = 0;
nkeynes@1130
   202
    unsigned i;
nkeynes@1130
   203
nkeynes@1235
   204
nkeynes@1235
   205
    FILE *f = preprocessInput(filename, cpp_opts );
nkeynes@1130
   206
    if( f == NULL ) {
nkeynes@1130
   207
        fprintf( stderr, "Error: unable to open input file '%s': %s\n", filename, strerror(errno) );
nkeynes@1234
   208
        exit(2);
nkeynes@1130
   209
    }
nkeynes@1130
   210
nkeynes@1130
   211
    shader_t shader = NULL;
nkeynes@1234
   212
    if( result->filename == NULL ) {
nkeynes@1234
   213
        result->filename = g_strdup(filename);
nkeynes@1234
   214
    } else {
nkeynes@1234
   215
        const gchar *tmp = result->filename;
nkeynes@1234
   216
        result->filename = g_strdup_printf("%s, %s", tmp, filename);
nkeynes@1234
   217
        g_free((gchar *)tmp);
nkeynes@1234
   218
    }
nkeynes@1130
   219
nkeynes@1130
   220
    while( fgets(buf, sizeof(buf), f) != NULL ) {
nkeynes@1130
   221
        if( strlen(buf) == 0 )
nkeynes@1130
   222
            continue;
nkeynes@1130
   223
nkeynes@1235
   224
        if( buf[0] == '#' ) {
nkeynes@1235
   225
            char *p = buf+1;
nkeynes@1235
   226
            if( strncmp(p, "pragma ", 7) == 0 ) {
nkeynes@1235
   227
                p += 7;
nkeynes@1130
   228
            }
nkeynes@1235
   229
            if( strncmp(p, "vertex ", 7) == 0 ) {
nkeynes@1235
   230
                shader = g_malloc0(sizeof(struct shader));
nkeynes@1235
   231
                assert( shader != NULL );
nkeynes@1235
   232
                shader->type = VERTEX_SHADER;
nkeynes@1235
   233
                shader->name = strdup(g_strstrip(p+7));
nkeynes@1235
   234
                shader->body = malloc(DEF_ALLOC_SIZE);
nkeynes@1235
   235
                shader->body[0] = '\0';
nkeynes@1235
   236
                current_size = DEF_ALLOC_SIZE;
nkeynes@1235
   237
                current_posn = 0;
nkeynes@1235
   238
                result->shaders = g_list_append(result->shaders, shader);
nkeynes@1235
   239
            } else if( strncmp( p, "fragment ", 9 ) == 0 ) {
nkeynes@1235
   240
                shader = g_malloc0(sizeof(struct shader));
nkeynes@1235
   241
                assert( shader != NULL );
nkeynes@1235
   242
                shader->type = FRAGMENT_SHADER;
nkeynes@1235
   243
                shader->name = strdup(g_strstrip(p+9));
nkeynes@1235
   244
                shader->body = malloc(DEF_ALLOC_SIZE);
nkeynes@1235
   245
                shader->body[0] = '\0';
nkeynes@1235
   246
                current_size = DEF_ALLOC_SIZE;
nkeynes@1235
   247
                current_posn = 0;
nkeynes@1235
   248
                result->shaders = g_list_append(result->shaders, shader);
nkeynes@1235
   249
            } else if( strncmp( p, "program ", 8 ) == 0 ) {
nkeynes@1235
   250
                shader = NULL;
nkeynes@1235
   251
                program_t program = g_malloc0(sizeof(struct program));
nkeynes@1235
   252
                char *rest = p+8;
nkeynes@1235
   253
                char *equals = strchr(rest, '=');
nkeynes@1235
   254
                if( equals == NULL ) {
nkeynes@1235
   255
                    fprintf( stderr, "Error: invalid program line %s\n", buf );
nkeynes@1235
   256
                    exit(2);
nkeynes@1235
   257
                }
nkeynes@1235
   258
                *equals = '\0';
nkeynes@1235
   259
                program->name = g_strdup(g_strstrip(rest));
nkeynes@1235
   260
                program->shader_names = g_strsplit_set(g_strstrip(equals+1), " \t\r,", 0);
nkeynes@1235
   261
                result->programs = g_list_append(result->programs, program);
nkeynes@1235
   262
                for(i=0;program->shader_names[i] != NULL; i++ );
nkeynes@1235
   263
                if( i > result->max_shaders )
nkeynes@1235
   264
                    result->max_shaders = i;
nkeynes@1235
   265
            }
nkeynes@1235
   266
            /* Else discard any other # lines */
nkeynes@1130
   267
        } else if( shader != NULL ) {
nkeynes@1130
   268
            size_t len = strlen(buf);
nkeynes@1130
   269
            if( current_posn + len > current_size ) {
nkeynes@1130
   270
                shader->body = realloc(shader->body, current_size*2);
nkeynes@1130
   271
                assert( shader->body != NULL );
nkeynes@1130
   272
                current_size *= 2;
nkeynes@1130
   273
            }
nkeynes@1130
   274
            strcpy( shader->body + current_posn, buf );
nkeynes@1130
   275
            current_posn += len;
nkeynes@1207
   276
            char *line = g_strstrip(buf);
nkeynes@1207
   277
            if( strncmp( line, "uniform ", 8 ) == 0 ) {
nkeynes@1207
   278
                parseVarDecl(shader, TRUE, line+8);
nkeynes@1207
   279
            } else if( strncmp( line, "attribute ", 10 ) == 0 ) {
nkeynes@1207
   280
                parseVarDecl(shader, FALSE, line+10);
nkeynes@1207
   281
            }
nkeynes@1130
   282
        }
nkeynes@1130
   283
    }
nkeynes@1130
   284
nkeynes@1130
   285
    fclose(f);
nkeynes@1130
   286
}
nkeynes@405
   287
nkeynes@405
   288
/**
nkeynes@405
   289
 * Copy input to output, quoting " characters as we go.
nkeynes@405
   290
 */
nkeynes@1130
   291
static void writeCString( FILE *out, const char *str )
nkeynes@405
   292
{
nkeynes@1130
   293
    const char *p = str;
nkeynes@405
   294
nkeynes@1130
   295
    while( *p != 0 ) {
nkeynes@1130
   296
        if( *p == '\"' ) {
nkeynes@736
   297
            fputc( '\\', out );
nkeynes@1130
   298
        } else if( *p == '\n' ) {
nkeynes@736
   299
            fputs( "\\n\\", out );
nkeynes@736
   300
        }
nkeynes@1130
   301
        fputc( *p, out );
nkeynes@1130
   302
        p++;
nkeynes@1130
   303
    }
nkeynes@1130
   304
}
nkeynes@1130
   305
nkeynes@1207
   306
static const char *sl_type_map[][3] = {
nkeynes@1207
   307
        {"int", "int", "int *"},
nkeynes@1229
   308
        {"float", "float", "float *"},
nkeynes@1207
   309
        {"short", "short", "short *"},
nkeynes@1207
   310
        {"sampler", "int", "int *"},
nkeynes@1207
   311
        {"vec", "GLfloat *", "GLfloat *"},
nkeynes@1207
   312
        {"mat", "GLfloat *", "GLfloat *"},
nkeynes@1207
   313
        {NULL, NULL}
nkeynes@1207
   314
};
nkeynes@1207
   315
nkeynes@1207
   316
static const char *getCType( const char *sl_type, gboolean isUniform ) {
nkeynes@1207
   317
    for( unsigned i=0; sl_type_map[i][0] != NULL; i++ ) {
nkeynes@1207
   318
        if( strncmp(sl_type_map[i][0], sl_type, strlen(sl_type_map[i][0])) == 0 ) {
nkeynes@1207
   319
            if( isUniform ) {
nkeynes@1207
   320
                return sl_type_map[i][1];
nkeynes@1207
   321
            } else {
nkeynes@1207
   322
                return sl_type_map[i][2];
nkeynes@1207
   323
            }
nkeynes@1207
   324
        }
nkeynes@1207
   325
    }
nkeynes@1207
   326
    return "void *";
nkeynes@1207
   327
}
nkeynes@1207
   328
nkeynes@1130
   329
static void writeHeader( FILE *out, glsldata_t data )
nkeynes@1130
   330
{
nkeynes@1130
   331
    fprintf( out, "/*\n * This file automatically generated by genglsl from %s\n */\n", data->filename );
nkeynes@1130
   332
}
nkeynes@1130
   333
nkeynes@1130
   334
static void writeInterface( const char *filename, glsldata_t data )
nkeynes@1130
   335
{
nkeynes@1130
   336
    FILE *f = fopen(filename, "wo");
nkeynes@1130
   337
    if( f == NULL ) {
nkeynes@1130
   338
        fprintf( stderr, "Error: Unable to write interface file '%s': %s\n", filename, strerror(errno) );
nkeynes@1130
   339
        exit(1);
nkeynes@1130
   340
    }
nkeynes@1130
   341
nkeynes@1130
   342
    writeHeader( f, data );
nkeynes@1130
   343
    fprintf( f, "#ifndef lxdream_glsl_H\n#define lxdream_glsl_H 1\n\n" );
nkeynes@1130
   344
nkeynes@1130
   345
    fprintf( f, "typedef enum {\n" );
nkeynes@1130
   346
    const char *last_name = NULL;
nkeynes@1130
   347
    int count = 0;
nkeynes@1130
   348
    GList *shader_ptr;
nkeynes@1130
   349
    for( shader_ptr = data->shaders; shader_ptr != NULL; shader_ptr = shader_ptr->next ) {
nkeynes@1130
   350
        count++;
nkeynes@1130
   351
        shader_t shader = (shader_t)shader_ptr->data;
nkeynes@1130
   352
        fprintf( f, "    %s,\n", shader->name );
nkeynes@1130
   353
        last_name = shader->name;
nkeynes@1130
   354
    }
nkeynes@1130
   355
    fprintf( f, "} shader_id;\n\n" );
nkeynes@1130
   356
nkeynes@1130
   357
    if( last_name == NULL )
nkeynes@1130
   358
        last_name = "NULL";
nkeynes@1130
   359
    fprintf( f, "#define GLSL_LAST_SHADER %s\n", last_name );
nkeynes@1130
   360
    fprintf( f, "#define GLSL_NUM_SHADERS %d\n", count );
nkeynes@1130
   361
    fprintf( f, "#define GLSL_NO_SHADER -1\n\n" );
nkeynes@1130
   362
    fprintf( f, "#define GLSL_VERTEX_SHADER 1\n" );
nkeynes@1130
   363
    fprintf( f, "#define GLSL_FRAGMENT_SHADER 2\n" );
nkeynes@1130
   364
nkeynes@1130
   365
    count = 0;
nkeynes@1130
   366
    GList *program_ptr;
nkeynes@1130
   367
    for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
nkeynes@1130
   368
        count++;
nkeynes@1130
   369
    }
nkeynes@1207
   370
    fprintf( f, "#define GLSL_NUM_PROGRAMS %d\n", count );
nkeynes@1130
   371
nkeynes@1207
   372
    for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
nkeynes@1207
   373
        program_t program = program_ptr->data;
nkeynes@1207
   374
        GList *var_ptr;
nkeynes@1207
   375
        fprintf( f, "void glsl_use_%s();\n", program->name );
nkeynes@1207
   376
        for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
nkeynes@1207
   377
            variable_t var = var_ptr->data;
nkeynes@1207
   378
            if( var->uniform ) {
nkeynes@1207
   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 );
nkeynes@1207
   380
            } else {
nkeynes@1208
   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);
nkeynes@1209
   382
                if( strcmp(var->type,"vec4") == 0 ) { /* Special case */
nkeynes@1240
   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);
nkeynes@1209
   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);
nkeynes@1209
   385
                }
nkeynes@1207
   386
            }
nkeynes@1207
   387
        }
nkeynes@1207
   388
    }
nkeynes@1130
   389
nkeynes@1258
   390
    fprintf( f, "void glsl_clear_shader();\n" );
nkeynes@1258
   391
nkeynes@1130
   392
    fprintf( f, "#endif /* !lxdream_glsl_H */\n" );
nkeynes@1130
   393
nkeynes@1130
   394
    fclose(f);
nkeynes@1130
   395
}
nkeynes@1130
   396
nkeynes@1130
   397
static void writeSource( const char *filename, glsldata_t data )
nkeynes@1130
   398
{
nkeynes@1130
   399
    FILE *f = fopen(filename, "wo");
nkeynes@1130
   400
    if( f == NULL ) {
nkeynes@1130
   401
        fprintf( stderr, "Error: Unable to write interface file '%s': %s\n", filename, strerror(errno) );
nkeynes@1130
   402
        exit(1);
nkeynes@1130
   403
    }
nkeynes@1130
   404
nkeynes@1130
   405
    writeHeader( f, data );
nkeynes@1130
   406
    fprintf( f, "struct shader_def {\n    int type;\n    const char *source;\n};\n" );
nkeynes@1130
   407
nkeynes@1130
   408
    fprintf( f, "const struct shader_def shader_source[] = {\n" );
nkeynes@1130
   409
    GList *shader_ptr;
nkeynes@1130
   410
    for( shader_ptr = data->shaders; shader_ptr != NULL; shader_ptr = shader_ptr->next ) {
nkeynes@1130
   411
        shader_t shader = (shader_t)shader_ptr->data;
nkeynes@1130
   412
        fprintf( f, "    {%s,\"", (shader->type == VERTEX_SHADER ? "GLSL_VERTEX_SHADER" : "GLSL_FRAGMENT_SHADER") );
nkeynes@1130
   413
        writeCString( f, shader->body );
nkeynes@1130
   414
        fprintf( f, "\"},\n" );
nkeynes@1130
   415
    }
nkeynes@1130
   416
    fprintf( f, "    {GLSL_NO_SHADER,NULL}};\n\n" );
nkeynes@1130
   417
nkeynes@1130
   418
    fprintf( f, "const int program_list[][%d] = {\n", data->max_shaders+1 );
nkeynes@1130
   419
    GList *program_ptr;
nkeynes@1207
   420
    GList *var_ptr;
nkeynes@1130
   421
    unsigned i;
nkeynes@1130
   422
    for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
nkeynes@1130
   423
        program_t program = (program_t)program_ptr->data;
nkeynes@1130
   424
        fprintf( f, "    {" );
nkeynes@1130
   425
        for( i=0; program->shader_names[i] != NULL; i++ ) {
nkeynes@1130
   426
            fprintf(f, "%s,", program->shader_names[i] );
nkeynes@1130
   427
        }
nkeynes@1130
   428
        fprintf( f, "GLSL_NO_SHADER},\n" );
nkeynes@1130
   429
    }
nkeynes@1130
   430
    fprintf( f, "    {GLSL_NO_SHADER}};\n" );
nkeynes@1130
   431
nkeynes@1207
   432
    /* per-program functions */
nkeynes@1207
   433
    for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
nkeynes@1207
   434
        program_t program = program_ptr->data;
nkeynes@1207
   435
        fprintf( f, "\nstatic gl_program_t prog_%s_id;\n",program->name );
nkeynes@1207
   436
        for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
nkeynes@1207
   437
            variable_t var = var_ptr->data;
nkeynes@1207
   438
            fprintf( f, "static GLint var_%s_%s_loc;\n", program->name, var->name);
nkeynes@1207
   439
        }
nkeynes@1207
   440
nkeynes@1207
   441
    }
nkeynes@1207
   442
    for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
nkeynes@1207
   443
        program_t program = program_ptr->data;
nkeynes@1208
   444
        fprintf( f, "\nstatic void glsl_cleanup_%s() {\n", program->name );
nkeynes@1208
   445
        for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
nkeynes@1208
   446
            variable_t var = var_ptr->data;
nkeynes@1208
   447
            if( !var->uniform ) {
nkeynes@1208
   448
                fprintf( f, "    glsl_disable_attrib(var_%s_%s_loc);\n", program->name, var->name );
nkeynes@1208
   449
            }
nkeynes@1208
   450
        }
nkeynes@1208
   451
        fprintf( f, "}\n");
nkeynes@1208
   452
nkeynes@1208
   453
        fprintf( f, "\nvoid glsl_use_%s() {\n", program->name );
nkeynes@1208
   454
        fprintf( f, "    glsl_use_program(prog_%s_id);\n", program->name );
nkeynes@1229
   455
        fprintf( f, "    glsl_set_cleanup_fn(glsl_cleanup_%s);\n", program->name );
nkeynes@1208
   456
        for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
nkeynes@1208
   457
            variable_t var = var_ptr->data;
nkeynes@1208
   458
            if( !var->uniform ) {
nkeynes@1208
   459
                fprintf( f, "    glsl_enable_attrib(var_%s_%s_loc);\n", program->name, var->name );
nkeynes@1208
   460
            }
nkeynes@1208
   461
        }
nkeynes@1208
   462
        fprintf( f, "}\n");
nkeynes@1208
   463
nkeynes@1207
   464
nkeynes@1207
   465
        for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
nkeynes@1207
   466
            variable_t var = var_ptr->data;
nkeynes@1207
   467
            if( var->uniform ) {
nkeynes@1207
   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 );
nkeynes@1207
   469
                fprintf( f, "    glsl_set_uniform_%s(var_%s_%s_loc,value);\n}\n", var->type, program->name, var->name );
nkeynes@1207
   470
            } else {
nkeynes@1207
   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);
nkeynes@1207
   472
                fprintf( f, "    glsl_set_attrib_%s(var_%s_%s_loc,stride, ptr);\n}\n", var->type, program->name, var->name );
nkeynes@1209
   473
                if( strcmp(var->type,"vec4") == 0 ) { /* Special case to load vec3 arrays into a vec4 */
nkeynes@1209
   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);
nkeynes@1209
   475
                    fprintf( f, "    glsl_set_attrib_vec3(var_%s_%s_loc,stride, ptr);\n}\n", program->name, var->name );
nkeynes@1240
   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);
nkeynes@1240
   477
                    fprintf( f, "    glsl_set_attrib_vec2(var_%s_%s_loc,stride, ptr);\n}\n", program->name, var->name );
nkeynes@1209
   478
                }
nkeynes@1207
   479
            }
nkeynes@1207
   480
        }
nkeynes@1207
   481
    }
nkeynes@1207
   482
nkeynes@1258
   483
    fprintf( f, "\nvoid glsl_clear_shader() {\n" );
nkeynes@1258
   484
    fprintf( f, "    glsl_run_cleanup_fn();\n    glsl_use_program(0);\n}\n" );
nkeynes@1258
   485
nkeynes@1207
   486
    fprintf( f, "\nstatic void glsl_init_programs( gl_program_t *ids ) {\n" );
nkeynes@1207
   487
    for( program_ptr = data->programs, i=0; program_ptr != NULL; program_ptr = program_ptr->next, i++ ) {
nkeynes@1207
   488
        program_t program = program_ptr->data;
nkeynes@1207
   489
nkeynes@1207
   490
        fprintf( f, "    prog_%s_id = ids[%d];\n\n", program->name, i );
nkeynes@1207
   491
        for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
nkeynes@1207
   492
            variable_t var = var_ptr->data;
nkeynes@1207
   493
            if( var->uniform ) {
nkeynes@1207
   494
                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
   495
            } else {
nkeynes@1207
   496
                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
   497
            }
nkeynes@1207
   498
        }
nkeynes@1207
   499
    }
nkeynes@1258
   500
nkeynes@1207
   501
    fprintf( f, "}\n" );
nkeynes@1207
   502
nkeynes@1130
   503
    fclose(f);
nkeynes@1130
   504
}
nkeynes@1130
   505
nkeynes@1234
   506
static const char *makeExtension(const char *basename, const char *ext)
nkeynes@1130
   507
{
nkeynes@1130
   508
    const char *oldext = strrchr(basename, '.');
nkeynes@1130
   509
    if( oldext == NULL ) {
nkeynes@1130
   510
        return g_strdup_printf("%s%s", basename, ext);
nkeynes@1130
   511
    } else {
nkeynes@1169
   512
        return g_strdup_printf("%.*s%s", (int)(oldext-basename), basename, ext);
nkeynes@405
   513
    }
nkeynes@405
   514
}
nkeynes@405
   515
nkeynes@1235
   516
static char *option_list = "hi:I:D:U:o:";
nkeynes@1234
   517
static struct option long_option_list[] = {
nkeynes@1234
   518
        { "help", no_argument, NULL, 'h' },
nkeynes@1235
   519
        { "interface", required_argument, NULL, 'i' },
nkeynes@1234
   520
        { "output", required_argument, NULL, 'o' },
nkeynes@1234
   521
        { NULL, 0, 0, 0 } };
nkeynes@1234
   522
nkeynes@1234
   523
static void usage() {
nkeynes@1234
   524
    fprintf( stderr, "Usage: genglsl <glsl-source-list> [-o output.def] [-i output.h]\n");
nkeynes@1234
   525
}
nkeynes@405
   526
int main( int argc, char *argv[] )
nkeynes@405
   527
{
nkeynes@1234
   528
    const char *output_file = NULL;
nkeynes@1234
   529
    const char *iface_file = NULL;
nkeynes@1235
   530
    GList *cpp_opts = NULL;
nkeynes@1234
   531
    int opt;
nkeynes@1234
   532
nkeynes@1234
   533
    while( (opt = getopt_long( argc, argv, option_list, long_option_list, NULL )) != -1 ) {
nkeynes@1234
   534
        switch( opt ) {
nkeynes@1234
   535
        case 'h':
nkeynes@1234
   536
            usage();
nkeynes@1234
   537
            exit(0);
nkeynes@1234
   538
            break;
nkeynes@1235
   539
        case 'D': case 'I': case 'U':
nkeynes@1235
   540
            cpp_opts = g_list_append(cpp_opts, g_strdup_printf( "-%c%s", opt, optarg ));
nkeynes@1235
   541
            break;
nkeynes@1234
   542
        case 'i':
nkeynes@1234
   543
            if( iface_file != NULL ) {
nkeynes@1234
   544
                fprintf( stderr, "Error: at most one interface file can be supplied\n" );
nkeynes@1234
   545
                usage();
nkeynes@1234
   546
                exit(1);
nkeynes@1234
   547
            }
nkeynes@1234
   548
            iface_file = optarg;
nkeynes@1234
   549
            break;
nkeynes@1234
   550
        case 'o':
nkeynes@1234
   551
            if( output_file != NULL ) {
nkeynes@1234
   552
                fprintf( stderr, "Error: at most one output file can be supplied\n" );
nkeynes@1234
   553
                usage();
nkeynes@1234
   554
                exit(1);
nkeynes@1234
   555
            }
nkeynes@1234
   556
            output_file = optarg;
nkeynes@1234
   557
        }
nkeynes@1234
   558
    }
nkeynes@1234
   559
nkeynes@1234
   560
    if( optind == argc ) {
nkeynes@1234
   561
        usage();
nkeynes@736
   562
        exit(1);
nkeynes@405
   563
    }
nkeynes@405
   564
nkeynes@1234
   565
    if( output_file == NULL ) {
nkeynes@1234
   566
        output_file = makeExtension(argv[optind], ".def");
nkeynes@1234
   567
    }
nkeynes@1234
   568
    if( iface_file == NULL ) {
nkeynes@1234
   569
        iface_file = makeExtension(output_file, ".h");
nkeynes@405
   570
    }
nkeynes@405
   571
nkeynes@1235
   572
    atexit(cleanup_tempfiles);
nkeynes@1234
   573
    glsldata_t data = g_malloc0(sizeof(struct glsldata));
nkeynes@1234
   574
    while( optind < argc ) {
nkeynes@1235
   575
        readInput(argv[optind++], cpp_opts, data);
nkeynes@405
   576
    }
nkeynes@1234
   577
    linkPrograms(data);
nkeynes@405
   578
nkeynes@1234
   579
    writeSource( output_file, data );
nkeynes@1234
   580
    writeInterface( iface_file, data );
nkeynes@405
   581
    return 0;
nkeynes@405
   582
}
.