Search
lxdream.org :: lxdream/src/tools/genglsl.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/tools/genglsl.c
changeset 1151:e1848ca9b5b1
prev1130:5f56fc931112
next1153:00e507e4025c
author nkeynes
date Wed Dec 08 18:33:23 2010 +1000 (11 years ago)
permissions -rw-r--r--
last change Updated pt_BR translation from Arthonis
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@1130
    24
#include <errno.h>
nkeynes@405
    25
#include <stdio.h>
nkeynes@405
    26
#include <stdlib.h>
nkeynes@1130
    27
#include <string.h>
nkeynes@1130
    28
#include <glib/gstrfuncs.h>
nkeynes@1130
    29
#include <glib/glist.h>
nkeynes@1130
    30
nkeynes@1130
    31
#define MAX_LINE 4096
nkeynes@1130
    32
#define DEF_ALLOC_SIZE 4096
nkeynes@1130
    33
#define MAX_SHADERS 128
nkeynes@1130
    34
nkeynes@1130
    35
typedef enum {
nkeynes@1130
    36
    VERTEX_SHADER = 0,
nkeynes@1130
    37
    FRAGMENT_SHADER = 1
nkeynes@1130
    38
} shader_type_t;
nkeynes@1130
    39
nkeynes@1151
    40
typedef struct uniform {
nkeynes@1151
    41
    const char *name;
nkeynes@1151
    42
    const char *var_name;
nkeynes@1151
    43
} *uniform_t;
nkeynes@1151
    44
nkeynes@1130
    45
typedef struct shader {
nkeynes@1130
    46
    shader_type_t type;
nkeynes@1130
    47
    const char *name;
nkeynes@1130
    48
    char *body;
nkeynes@1151
    49
    GList *uniforms;
nkeynes@1130
    50
} *shader_t;
nkeynes@1130
    51
nkeynes@1130
    52
typedef struct program {
nkeynes@1130
    53
    const char *name;
nkeynes@1130
    54
    gchar **shader_names;
nkeynes@1130
    55
} *program_t;
nkeynes@1130
    56
nkeynes@1130
    57
typedef struct glsldata {
nkeynes@1130
    58
    const char *filename;
nkeynes@1130
    59
    unsigned max_shaders;
nkeynes@1130
    60
    GList *shaders;
nkeynes@1130
    61
    GList *programs;
nkeynes@1130
    62
} *glsldata_t;
nkeynes@1130
    63
nkeynes@1130
    64
static struct glsldata *readInput( const char *filename )
nkeynes@1130
    65
{
nkeynes@1130
    66
    char buf[MAX_LINE];
nkeynes@1130
    67
    size_t current_size = 0, current_posn = 0;
nkeynes@1130
    68
    unsigned i;
nkeynes@1130
    69
nkeynes@1130
    70
    FILE *f = fopen( filename, "ro" );
nkeynes@1130
    71
    if( f == NULL ) {
nkeynes@1130
    72
        fprintf( stderr, "Error: unable to open input file '%s': %s\n", filename, strerror(errno) );
nkeynes@1130
    73
        exit(1);
nkeynes@1130
    74
    }
nkeynes@1130
    75
nkeynes@1130
    76
    shader_t shader = NULL;
nkeynes@1130
    77
    glsldata_t result = malloc(sizeof(struct glsldata));
nkeynes@1130
    78
    assert( result != NULL );
nkeynes@1130
    79
    result->filename = strdup(filename);
nkeynes@1130
    80
    result->shaders = NULL;
nkeynes@1130
    81
    result->programs = NULL;
nkeynes@1130
    82
    result->max_shaders = 0;
nkeynes@1130
    83
nkeynes@1130
    84
    while( fgets(buf, sizeof(buf), f) != NULL ) {
nkeynes@1130
    85
        if( strlen(buf) == 0 )
nkeynes@1130
    86
            continue;
nkeynes@1130
    87
nkeynes@1130
    88
        if( strncmp(buf, "#vertex ", 8) == 0 ) {
nkeynes@1130
    89
            shader = malloc(sizeof(struct shader));
nkeynes@1130
    90
            assert( shader != NULL );
nkeynes@1130
    91
            shader->type = VERTEX_SHADER;
nkeynes@1130
    92
            shader->name = strdup(g_strstrip(buf+8));
nkeynes@1130
    93
            shader->body = malloc(DEF_ALLOC_SIZE);
nkeynes@1130
    94
            shader->body[0] = '\0';
nkeynes@1151
    95
            shader->uniforms = 0;
nkeynes@1130
    96
            current_size = DEF_ALLOC_SIZE;
nkeynes@1130
    97
            current_posn = 0;
nkeynes@1130
    98
            result->shaders = g_list_append(result->shaders, shader);
nkeynes@1130
    99
        } else if( strncmp( buf, "#fragment ", 10 ) == 0 ) {
nkeynes@1130
   100
            shader = malloc(sizeof(struct shader));
nkeynes@1130
   101
            assert( shader != NULL );
nkeynes@1130
   102
            shader->type = FRAGMENT_SHADER;
nkeynes@1130
   103
            shader->name = strdup(g_strstrip(buf+10));
nkeynes@1130
   104
            shader->body = malloc(DEF_ALLOC_SIZE);
nkeynes@1130
   105
            shader->body[0] = '\0';
nkeynes@1151
   106
            shader->uniforms = 0;
nkeynes@1130
   107
            current_size = DEF_ALLOC_SIZE;
nkeynes@1130
   108
            current_posn = 0;
nkeynes@1130
   109
            result->shaders = g_list_append(result->shaders, shader);
nkeynes@1130
   110
        } else if( strncmp( buf, "#program ", 9 ) == 0 ) {
nkeynes@1130
   111
            shader = NULL;
nkeynes@1130
   112
            program_t program = malloc(sizeof(struct program));
nkeynes@1151
   113
            assert( program != NULL );
nkeynes@1130
   114
            char *rest = buf+9;
nkeynes@1130
   115
            char *equals = strchr(rest, '=');
nkeynes@1130
   116
            if( equals == NULL ) {
nkeynes@1130
   117
                fprintf( stderr, "Error: invalid program line %s\n", buf );
nkeynes@1130
   118
                exit(2);
nkeynes@1130
   119
            }
nkeynes@1130
   120
            *equals = '\0';
nkeynes@1130
   121
            program->name = g_strdup(g_strstrip(rest));
nkeynes@1130
   122
            program->shader_names = g_strsplit_set(g_strstrip(equals+1), " \t\r,", 0);
nkeynes@1130
   123
            result->programs = g_list_append(result->programs, program);
nkeynes@1130
   124
            for(i=0;program->shader_names[i] != NULL; i++ );
nkeynes@1130
   125
            if( i > result->max_shaders )
nkeynes@1130
   126
                result->max_shaders = i;
nkeynes@1151
   127
        } else if( strncmp( buf, "#uniform ", 9 ) == 0 ) {
nkeynes@1151
   128
            uniform_t uniform = malloc(sizeof(struct uniform));
nkeynes@1151
   129
            assert( uniform != NULL );
nkeynes@1151
   130
            if( shader == NULL ) {
nkeynes@1151
   131
                fprintf( stderr, "Error: #uniform specified outside of shader: %s\n", buf );
nkeynes@1151
   132
                exit(2);
nkeynes@1151
   133
            }
nkeynes@1151
   134
            char *rest = buf+9;
nkeynes@1151
   135
            char *equals = strchr(rest, '=');
nkeynes@1151
   136
            if( equals == NULL ) {
nkeynes@1151
   137
                fprintf( stderr, "Error: invalid program line %s\n", buf );
nkeynes@1151
   138
                exit(2);
nkeynes@1151
   139
            }
nkeynes@1151
   140
            *equals = '\0';
nkeynes@1151
   141
            uniform->name = g_strdup(g_strstrip(rest));
nkeynes@1151
   142
            uniform->var_name = g_strdup(g_strstrip(equals+1));
nkeynes@1151
   143
            shader->uniforms = g_list_append(shader->uniforms, uniform);
nkeynes@1130
   144
        } else if( shader != NULL ) {
nkeynes@1130
   145
            size_t len = strlen(buf);
nkeynes@1130
   146
            if( current_posn + len > current_size ) {
nkeynes@1130
   147
                shader->body = realloc(shader->body, current_size*2);
nkeynes@1130
   148
                assert( shader->body != NULL );
nkeynes@1130
   149
                current_size *= 2;
nkeynes@1130
   150
            }
nkeynes@1130
   151
            strcpy( shader->body + current_posn, buf );
nkeynes@1130
   152
            current_posn += len;
nkeynes@1130
   153
        }
nkeynes@1130
   154
    }
nkeynes@1130
   155
nkeynes@1130
   156
    fclose(f);
nkeynes@1130
   157
    return result;
nkeynes@1130
   158
}
nkeynes@405
   159
nkeynes@405
   160
/**
nkeynes@405
   161
 * Copy input to output, quoting " characters as we go.
nkeynes@405
   162
 */
nkeynes@1130
   163
static void writeCString( FILE *out, const char *str )
nkeynes@405
   164
{
nkeynes@1130
   165
    const char *p = str;
nkeynes@405
   166
nkeynes@1130
   167
    while( *p != 0 ) {
nkeynes@1130
   168
        if( *p == '\"' ) {
nkeynes@736
   169
            fputc( '\\', out );
nkeynes@1130
   170
        } else if( *p == '\n' ) {
nkeynes@736
   171
            fputs( "\\n\\", out );
nkeynes@736
   172
        }
nkeynes@1130
   173
        fputc( *p, out );
nkeynes@1130
   174
        p++;
nkeynes@1130
   175
    }
nkeynes@1130
   176
}
nkeynes@1130
   177
nkeynes@1151
   178
static uniform_t find_uniform_name( GList *list, const char *name )
nkeynes@1151
   179
{
nkeynes@1151
   180
    GList *ptr;
nkeynes@1151
   181
    for( ptr = list; ptr != NULL; ptr = ptr->next ) {
nkeynes@1151
   182
        uniform_t data = (uniform_t)list->data;
nkeynes@1151
   183
        if( strcmp( data->name, name ) == 0 )
nkeynes@1151
   184
            return data;
nkeynes@1151
   185
    }
nkeynes@1151
   186
    return NULL;
nkeynes@1151
   187
}
nkeynes@1151
   188
nkeynes@1130
   189
static void writeHeader( FILE *out, glsldata_t data )
nkeynes@1130
   190
{
nkeynes@1130
   191
    fprintf( out, "/*\n * This file automatically generated by genglsl from %s\n */\n", data->filename );
nkeynes@1130
   192
}
nkeynes@1130
   193
nkeynes@1130
   194
static void writeInterface( const char *filename, glsldata_t data )
nkeynes@1130
   195
{
nkeynes@1130
   196
    FILE *f = fopen(filename, "wo");
nkeynes@1130
   197
    if( f == NULL ) {
nkeynes@1130
   198
        fprintf( stderr, "Error: Unable to write interface file '%s': %s\n", filename, strerror(errno) );
nkeynes@1130
   199
        exit(1);
nkeynes@1130
   200
    }
nkeynes@1130
   201
nkeynes@1130
   202
    writeHeader( f, data );
nkeynes@1130
   203
    fprintf( f, "#ifndef lxdream_glsl_H\n#define lxdream_glsl_H 1\n\n" );
nkeynes@1130
   204
nkeynes@1130
   205
    fprintf( f, "typedef enum {\n" );
nkeynes@1130
   206
    const char *last_name = NULL;
nkeynes@1130
   207
    int count = 0;
nkeynes@1151
   208
    GList *unique_uniforms;
nkeynes@1151
   209
    int uniform_count = 0;
nkeynes@1130
   210
    GList *shader_ptr;
nkeynes@1130
   211
    for( shader_ptr = data->shaders; shader_ptr != NULL; shader_ptr = shader_ptr->next ) {
nkeynes@1130
   212
        count++;
nkeynes@1130
   213
        shader_t shader = (shader_t)shader_ptr->data;
nkeynes@1130
   214
        fprintf( f, "    %s,\n", shader->name );
nkeynes@1130
   215
        last_name = shader->name;
nkeynes@1151
   216
        GList *uniform_ptr;
nkeynes@1151
   217
        for( uniform_ptr = shader->uniforms; uniform_ptr != NULL; uniform_ptr = uniform_ptr->next ) {
nkeynes@1151
   218
            uniform_t uniform = (uniform_t)uniform_ptr->data;
nkeynes@1151
   219
            if( find_uniform_name(unique_uniforms, uniform->name) == NULL ) {
nkeynes@1151
   220
                unique_uniforms = g_list_append( unique_uniforms, uniform );
nkeynes@1151
   221
                uniform_count++;
nkeynes@1151
   222
            }
nkeynes@1151
   223
        }
nkeynes@1130
   224
    }
nkeynes@1130
   225
    fprintf( f, "} shader_id;\n\n" );
nkeynes@1130
   226
nkeynes@1130
   227
    if( last_name == NULL )
nkeynes@1130
   228
        last_name = "NULL";
nkeynes@1130
   229
    fprintf( f, "#define GLSL_LAST_SHADER %s\n", last_name );
nkeynes@1130
   230
    fprintf( f, "#define GLSL_NUM_SHADERS %d\n", count );
nkeynes@1130
   231
    fprintf( f, "#define GLSL_NO_SHADER -1\n\n" );
nkeynes@1130
   232
    fprintf( f, "#define GLSL_VERTEX_SHADER 1\n" );
nkeynes@1130
   233
    fprintf( f, "#define GLSL_FRAGMENT_SHADER 2\n" );
nkeynes@1151
   234
    fprintf( f, "#define GLSL_NUM_UNIFORMS %d\n", uniform_count );
nkeynes@1130
   235
nkeynes@1130
   236
    fprintf( f, "typedef enum {\n" );
nkeynes@1130
   237
    last_name = NULL;
nkeynes@1130
   238
    count = 0;
nkeynes@1130
   239
    GList *program_ptr;
nkeynes@1130
   240
    for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
nkeynes@1130
   241
        count++;
nkeynes@1130
   242
        program_t program = (program_t)program_ptr->data;
nkeynes@1130
   243
        fprintf( f, "    %s,\n", program->name );
nkeynes@1130
   244
        last_name = program->name;
nkeynes@1130
   245
    }
nkeynes@1130
   246
    fprintf( f, "} program_id;\n\n" );
nkeynes@1130
   247
nkeynes@1130
   248
    if( last_name == NULL )
nkeynes@1130
   249
        last_name = "NULL";
nkeynes@1130
   250
    fprintf( f, "#define GLSL_LAST_PROGRAM %s\n", last_name );
nkeynes@1130
   251
    fprintf( f, "#define GLSL_NUM_PROGRAMS %d\n", count );
nkeynes@1130
   252
    fprintf( f, "#define GLSL_NO_PROGRAM -1\n\n" );
nkeynes@1130
   253
nkeynes@1130
   254
    fprintf( f, "int glsl_load_programs();\n" );
nkeynes@1130
   255
    fprintf( f, "void glsl_use_program_id( program_id );\n" );
nkeynes@1130
   256
nkeynes@1130
   257
    fprintf( f, "#endif /* !lxdream_glsl_H */\n" );
nkeynes@1130
   258
nkeynes@1130
   259
    fclose(f);
nkeynes@1130
   260
}
nkeynes@1130
   261
nkeynes@1130
   262
static void writeSource( const char *filename, glsldata_t data )
nkeynes@1130
   263
{
nkeynes@1130
   264
    FILE *f = fopen(filename, "wo");
nkeynes@1130
   265
    if( f == NULL ) {
nkeynes@1130
   266
        fprintf( stderr, "Error: Unable to write interface file '%s': %s\n", filename, strerror(errno) );
nkeynes@1130
   267
        exit(1);
nkeynes@1130
   268
    }
nkeynes@1130
   269
nkeynes@1130
   270
    writeHeader( f, data );
nkeynes@1130
   271
    fprintf( f, "struct shader_def {\n    int type;\n    const char *source;\n};\n" );
nkeynes@1130
   272
nkeynes@1130
   273
    fprintf( f, "const struct shader_def shader_source[] = {\n" );
nkeynes@1130
   274
    GList *shader_ptr;
nkeynes@1130
   275
    for( shader_ptr = data->shaders; shader_ptr != NULL; shader_ptr = shader_ptr->next ) {
nkeynes@1130
   276
        shader_t shader = (shader_t)shader_ptr->data;
nkeynes@1130
   277
        fprintf( f, "    {%s,\"", (shader->type == VERTEX_SHADER ? "GLSL_VERTEX_SHADER" : "GLSL_FRAGMENT_SHADER") );
nkeynes@1130
   278
        writeCString( f, shader->body );
nkeynes@1130
   279
        fprintf( f, "\"},\n" );
nkeynes@1130
   280
    }
nkeynes@1130
   281
    fprintf( f, "    {GLSL_NO_SHADER,NULL}};\n\n" );
nkeynes@1130
   282
nkeynes@1130
   283
    fprintf( f, "const int program_list[][%d] = {\n", data->max_shaders+1 );
nkeynes@1130
   284
    GList *program_ptr;
nkeynes@1130
   285
    unsigned i;
nkeynes@1130
   286
    for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
nkeynes@1130
   287
        program_t program = (program_t)program_ptr->data;
nkeynes@1130
   288
        fprintf( f, "    {" );
nkeynes@1130
   289
        for( i=0; program->shader_names[i] != NULL; i++ ) {
nkeynes@1130
   290
            fprintf(f, "%s,", program->shader_names[i] );
nkeynes@1130
   291
        }
nkeynes@1130
   292
        fprintf( f, "GLSL_NO_SHADER},\n" );
nkeynes@1130
   293
    }
nkeynes@1130
   294
    fprintf( f, "    {GLSL_NO_SHADER}};\n" );
nkeynes@1130
   295
nkeynes@1130
   296
    fclose(f);
nkeynes@1130
   297
}
nkeynes@1130
   298
nkeynes@1130
   299
const char *makeExtension(const char *basename, const char *ext)
nkeynes@1130
   300
{
nkeynes@1130
   301
    const char *oldext = strrchr(basename, '.');
nkeynes@1130
   302
    if( oldext == NULL ) {
nkeynes@1130
   303
        return g_strdup_printf("%s%s", basename, ext);
nkeynes@1130
   304
    } else {
nkeynes@1130
   305
        return g_strdup_printf("%.*s%s", oldext-basename, basename, ext);
nkeynes@405
   306
    }
nkeynes@405
   307
}
nkeynes@405
   308
nkeynes@405
   309
int main( int argc, char *argv[] )
nkeynes@405
   310
{
nkeynes@1130
   311
    if( argc < 2 ) {
nkeynes@1130
   312
        fprintf( stderr, "Usage: genglsl <glsl-source-file> [output.c [output.h]]\n");
nkeynes@736
   313
        exit(1);
nkeynes@405
   314
    }
nkeynes@405
   315
nkeynes@1130
   316
    glsldata_t data = readInput(argv[1]);
nkeynes@1130
   317
nkeynes@1130
   318
    const char *sourcefile, *ifacefile;
nkeynes@1130
   319
    if( argc > 2 ) {
nkeynes@1130
   320
        sourcefile = argv[2];
nkeynes@1130
   321
    } else {
nkeynes@1130
   322
        sourcefile = makeExtension(argv[1], ".def");
nkeynes@405
   323
    }
nkeynes@405
   324
nkeynes@1130
   325
    if( argc > 3 ) {
nkeynes@1130
   326
        ifacefile = argv[3];
nkeynes@1130
   327
    } else {
nkeynes@1130
   328
        ifacefile = makeExtension(sourcefile, ".h");
nkeynes@405
   329
    }
nkeynes@405
   330
nkeynes@1130
   331
    writeSource( sourcefile, data );
nkeynes@1130
   332
    writeInterface( ifacefile, data );
nkeynes@405
   333
    return 0;
nkeynes@405
   334
}
.