Search
lxdream.org :: lxdream/src/tools/genglsl.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/tools/genglsl.c
changeset 1130:5f56fc931112
prev968:6fb1481859a4
next1151:e1848ca9b5b1
author nkeynes
date Fri Sep 17 20:08:50 2010 +1000 (11 years ago)
permissions -rw-r--r--
last change Refactor shader management to support multiple programs, which are all
defined in the shaders.glsl, rather than split up into one file per
fragment.
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@1130
    40
typedef struct shader {
nkeynes@1130
    41
    shader_type_t type;
nkeynes@1130
    42
    const char *name;
nkeynes@1130
    43
    char *body;
nkeynes@1130
    44
} *shader_t;
nkeynes@1130
    45
nkeynes@1130
    46
typedef struct program {
nkeynes@1130
    47
    const char *name;
nkeynes@1130
    48
    gchar **shader_names;
nkeynes@1130
    49
} *program_t;
nkeynes@1130
    50
nkeynes@1130
    51
typedef struct glsldata {
nkeynes@1130
    52
    const char *filename;
nkeynes@1130
    53
    unsigned max_shaders;
nkeynes@1130
    54
    GList *shaders;
nkeynes@1130
    55
    GList *programs;
nkeynes@1130
    56
} *glsldata_t;
nkeynes@1130
    57
nkeynes@1130
    58
static struct glsldata *readInput( const char *filename )
nkeynes@1130
    59
{
nkeynes@1130
    60
    char buf[MAX_LINE];
nkeynes@1130
    61
    size_t current_size = 0, current_posn = 0;
nkeynes@1130
    62
    unsigned i;
nkeynes@1130
    63
nkeynes@1130
    64
    FILE *f = fopen( filename, "ro" );
nkeynes@1130
    65
    if( f == NULL ) {
nkeynes@1130
    66
        fprintf( stderr, "Error: unable to open input file '%s': %s\n", filename, strerror(errno) );
nkeynes@1130
    67
        exit(1);
nkeynes@1130
    68
    }
nkeynes@1130
    69
nkeynes@1130
    70
    shader_t shader = NULL;
nkeynes@1130
    71
    glsldata_t result = malloc(sizeof(struct glsldata));
nkeynes@1130
    72
    assert( result != NULL );
nkeynes@1130
    73
    result->filename = strdup(filename);
nkeynes@1130
    74
    result->shaders = NULL;
nkeynes@1130
    75
    result->programs = NULL;
nkeynes@1130
    76
    result->max_shaders = 0;
nkeynes@1130
    77
nkeynes@1130
    78
    while( fgets(buf, sizeof(buf), f) != NULL ) {
nkeynes@1130
    79
        if( strlen(buf) == 0 )
nkeynes@1130
    80
            continue;
nkeynes@1130
    81
nkeynes@1130
    82
        if( strncmp(buf, "#vertex ", 8) == 0 ) {
nkeynes@1130
    83
            shader = malloc(sizeof(struct shader));
nkeynes@1130
    84
            assert( shader != NULL );
nkeynes@1130
    85
            shader->type = VERTEX_SHADER;
nkeynes@1130
    86
            shader->name = strdup(g_strstrip(buf+8));
nkeynes@1130
    87
            shader->body = malloc(DEF_ALLOC_SIZE);
nkeynes@1130
    88
            shader->body[0] = '\0';
nkeynes@1130
    89
            current_size = DEF_ALLOC_SIZE;
nkeynes@1130
    90
            current_posn = 0;
nkeynes@1130
    91
            result->shaders = g_list_append(result->shaders, shader);
nkeynes@1130
    92
        } else if( strncmp( buf, "#fragment ", 10 ) == 0 ) {
nkeynes@1130
    93
            shader = malloc(sizeof(struct shader));
nkeynes@1130
    94
            assert( shader != NULL );
nkeynes@1130
    95
            shader->type = FRAGMENT_SHADER;
nkeynes@1130
    96
            shader->name = strdup(g_strstrip(buf+10));
nkeynes@1130
    97
            shader->body = malloc(DEF_ALLOC_SIZE);
nkeynes@1130
    98
            shader->body[0] = '\0';
nkeynes@1130
    99
            current_size = DEF_ALLOC_SIZE;
nkeynes@1130
   100
            current_posn = 0;
nkeynes@1130
   101
            result->shaders = g_list_append(result->shaders, shader);
nkeynes@1130
   102
        } else if( strncmp( buf, "#program ", 9 ) == 0 ) {
nkeynes@1130
   103
            shader = NULL;
nkeynes@1130
   104
            program_t program = malloc(sizeof(struct program));
nkeynes@1130
   105
            char *rest = buf+9;
nkeynes@1130
   106
            char *equals = strchr(rest, '=');
nkeynes@1130
   107
            if( equals == NULL ) {
nkeynes@1130
   108
                fprintf( stderr, "Error: invalid program line %s\n", buf );
nkeynes@1130
   109
                exit(2);
nkeynes@1130
   110
            }
nkeynes@1130
   111
            *equals = '\0';
nkeynes@1130
   112
            program->name = g_strdup(g_strstrip(rest));
nkeynes@1130
   113
            program->shader_names = g_strsplit_set(g_strstrip(equals+1), " \t\r,", 0);
nkeynes@1130
   114
            result->programs = g_list_append(result->programs, program);
nkeynes@1130
   115
            for(i=0;program->shader_names[i] != NULL; i++ );
nkeynes@1130
   116
            if( i > result->max_shaders )
nkeynes@1130
   117
                result->max_shaders = i;
nkeynes@1130
   118
        } else if( shader != NULL ) {
nkeynes@1130
   119
            size_t len = strlen(buf);
nkeynes@1130
   120
            if( current_posn + len > current_size ) {
nkeynes@1130
   121
                shader->body = realloc(shader->body, current_size*2);
nkeynes@1130
   122
                assert( shader->body != NULL );
nkeynes@1130
   123
                current_size *= 2;
nkeynes@1130
   124
            }
nkeynes@1130
   125
            strcpy( shader->body + current_posn, buf );
nkeynes@1130
   126
            current_posn += len;
nkeynes@1130
   127
        }
nkeynes@1130
   128
    }
nkeynes@1130
   129
nkeynes@1130
   130
    fclose(f);
nkeynes@1130
   131
    return result;
nkeynes@1130
   132
}
nkeynes@405
   133
nkeynes@405
   134
/**
nkeynes@405
   135
 * Copy input to output, quoting " characters as we go.
nkeynes@405
   136
 */
nkeynes@1130
   137
static void writeCString( FILE *out, const char *str )
nkeynes@405
   138
{
nkeynes@1130
   139
    const char *p = str;
nkeynes@405
   140
nkeynes@1130
   141
    while( *p != 0 ) {
nkeynes@1130
   142
        if( *p == '\"' ) {
nkeynes@736
   143
            fputc( '\\', out );
nkeynes@1130
   144
        } else if( *p == '\n' ) {
nkeynes@736
   145
            fputs( "\\n\\", out );
nkeynes@736
   146
        }
nkeynes@1130
   147
        fputc( *p, out );
nkeynes@1130
   148
        p++;
nkeynes@1130
   149
    }
nkeynes@1130
   150
}
nkeynes@1130
   151
nkeynes@1130
   152
static void writeHeader( FILE *out, glsldata_t data )
nkeynes@1130
   153
{
nkeynes@1130
   154
    fprintf( out, "/*\n * This file automatically generated by genglsl from %s\n */\n", data->filename );
nkeynes@1130
   155
}
nkeynes@1130
   156
nkeynes@1130
   157
static void writeInterface( const char *filename, glsldata_t data )
nkeynes@1130
   158
{
nkeynes@1130
   159
    FILE *f = fopen(filename, "wo");
nkeynes@1130
   160
    if( f == NULL ) {
nkeynes@1130
   161
        fprintf( stderr, "Error: Unable to write interface file '%s': %s\n", filename, strerror(errno) );
nkeynes@1130
   162
        exit(1);
nkeynes@1130
   163
    }
nkeynes@1130
   164
nkeynes@1130
   165
    writeHeader( f, data );
nkeynes@1130
   166
    fprintf( f, "#ifndef lxdream_glsl_H\n#define lxdream_glsl_H 1\n\n" );
nkeynes@1130
   167
nkeynes@1130
   168
    fprintf( f, "typedef enum {\n" );
nkeynes@1130
   169
    const char *last_name = NULL;
nkeynes@1130
   170
    int count = 0;
nkeynes@1130
   171
    GList *shader_ptr;
nkeynes@1130
   172
    for( shader_ptr = data->shaders; shader_ptr != NULL; shader_ptr = shader_ptr->next ) {
nkeynes@1130
   173
        count++;
nkeynes@1130
   174
        shader_t shader = (shader_t)shader_ptr->data;
nkeynes@1130
   175
        fprintf( f, "    %s,\n", shader->name );
nkeynes@1130
   176
        last_name = shader->name;
nkeynes@1130
   177
    }
nkeynes@1130
   178
    fprintf( f, "} shader_id;\n\n" );
nkeynes@1130
   179
nkeynes@1130
   180
    if( last_name == NULL )
nkeynes@1130
   181
        last_name = "NULL";
nkeynes@1130
   182
    fprintf( f, "#define GLSL_LAST_SHADER %s\n", last_name );
nkeynes@1130
   183
    fprintf( f, "#define GLSL_NUM_SHADERS %d\n", count );
nkeynes@1130
   184
    fprintf( f, "#define GLSL_NO_SHADER -1\n\n" );
nkeynes@1130
   185
    fprintf( f, "#define GLSL_VERTEX_SHADER 1\n" );
nkeynes@1130
   186
    fprintf( f, "#define GLSL_FRAGMENT_SHADER 2\n" );
nkeynes@1130
   187
nkeynes@1130
   188
    fprintf( f, "typedef enum {\n" );
nkeynes@1130
   189
    last_name = NULL;
nkeynes@1130
   190
    count = 0;
nkeynes@1130
   191
    GList *program_ptr;
nkeynes@1130
   192
    for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
nkeynes@1130
   193
        count++;
nkeynes@1130
   194
        program_t program = (program_t)program_ptr->data;
nkeynes@1130
   195
        fprintf( f, "    %s,\n", program->name );
nkeynes@1130
   196
        last_name = program->name;
nkeynes@1130
   197
    }
nkeynes@1130
   198
    fprintf( f, "} program_id;\n\n" );
nkeynes@1130
   199
nkeynes@1130
   200
    if( last_name == NULL )
nkeynes@1130
   201
        last_name = "NULL";
nkeynes@1130
   202
    fprintf( f, "#define GLSL_LAST_PROGRAM %s\n", last_name );
nkeynes@1130
   203
    fprintf( f, "#define GLSL_NUM_PROGRAMS %d\n", count );
nkeynes@1130
   204
    fprintf( f, "#define GLSL_NO_PROGRAM -1\n\n" );
nkeynes@1130
   205
nkeynes@1130
   206
    fprintf( f, "int glsl_load_programs();\n" );
nkeynes@1130
   207
    fprintf( f, "void glsl_use_program_id( program_id );\n" );
nkeynes@1130
   208
nkeynes@1130
   209
    fprintf( f, "#endif /* !lxdream_glsl_H */\n" );
nkeynes@1130
   210
nkeynes@1130
   211
    fclose(f);
nkeynes@1130
   212
}
nkeynes@1130
   213
nkeynes@1130
   214
static void writeSource( const char *filename, glsldata_t data )
nkeynes@1130
   215
{
nkeynes@1130
   216
    FILE *f = fopen(filename, "wo");
nkeynes@1130
   217
    if( f == NULL ) {
nkeynes@1130
   218
        fprintf( stderr, "Error: Unable to write interface file '%s': %s\n", filename, strerror(errno) );
nkeynes@1130
   219
        exit(1);
nkeynes@1130
   220
    }
nkeynes@1130
   221
nkeynes@1130
   222
    writeHeader( f, data );
nkeynes@1130
   223
    fprintf( f, "struct shader_def {\n    int type;\n    const char *source;\n};\n" );
nkeynes@1130
   224
nkeynes@1130
   225
    fprintf( f, "const struct shader_def shader_source[] = {\n" );
nkeynes@1130
   226
    GList *shader_ptr;
nkeynes@1130
   227
    for( shader_ptr = data->shaders; shader_ptr != NULL; shader_ptr = shader_ptr->next ) {
nkeynes@1130
   228
        shader_t shader = (shader_t)shader_ptr->data;
nkeynes@1130
   229
        fprintf( f, "    {%s,\"", (shader->type == VERTEX_SHADER ? "GLSL_VERTEX_SHADER" : "GLSL_FRAGMENT_SHADER") );
nkeynes@1130
   230
        writeCString( f, shader->body );
nkeynes@1130
   231
        fprintf( f, "\"},\n" );
nkeynes@1130
   232
    }
nkeynes@1130
   233
    fprintf( f, "    {GLSL_NO_SHADER,NULL}};\n\n" );
nkeynes@1130
   234
nkeynes@1130
   235
    fprintf( f, "const int program_list[][%d] = {\n", data->max_shaders+1 );
nkeynes@1130
   236
    GList *program_ptr;
nkeynes@1130
   237
    unsigned i;
nkeynes@1130
   238
    for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
nkeynes@1130
   239
        program_t program = (program_t)program_ptr->data;
nkeynes@1130
   240
        fprintf( f, "    {" );
nkeynes@1130
   241
        for( i=0; program->shader_names[i] != NULL; i++ ) {
nkeynes@1130
   242
            fprintf(f, "%s,", program->shader_names[i] );
nkeynes@1130
   243
        }
nkeynes@1130
   244
        fprintf( f, "GLSL_NO_SHADER},\n" );
nkeynes@1130
   245
    }
nkeynes@1130
   246
    fprintf( f, "    {GLSL_NO_SHADER}};\n" );
nkeynes@1130
   247
nkeynes@1130
   248
    fclose(f);
nkeynes@1130
   249
}
nkeynes@1130
   250
nkeynes@1130
   251
const char *makeExtension(const char *basename, const char *ext)
nkeynes@1130
   252
{
nkeynes@1130
   253
    const char *oldext = strrchr(basename, '.');
nkeynes@1130
   254
    if( oldext == NULL ) {
nkeynes@1130
   255
        return g_strdup_printf("%s%s", basename, ext);
nkeynes@1130
   256
    } else {
nkeynes@1130
   257
        return g_strdup_printf("%.*s%s", oldext-basename, basename, ext);
nkeynes@405
   258
    }
nkeynes@405
   259
}
nkeynes@405
   260
nkeynes@405
   261
int main( int argc, char *argv[] )
nkeynes@405
   262
{
nkeynes@1130
   263
    if( argc < 2 ) {
nkeynes@1130
   264
        fprintf( stderr, "Usage: genglsl <glsl-source-file> [output.c [output.h]]\n");
nkeynes@736
   265
        exit(1);
nkeynes@405
   266
    }
nkeynes@405
   267
nkeynes@1130
   268
    glsldata_t data = readInput(argv[1]);
nkeynes@1130
   269
nkeynes@1130
   270
    const char *sourcefile, *ifacefile;
nkeynes@1130
   271
    if( argc > 2 ) {
nkeynes@1130
   272
        sourcefile = argv[2];
nkeynes@1130
   273
    } else {
nkeynes@1130
   274
        sourcefile = makeExtension(argv[1], ".def");
nkeynes@405
   275
    }
nkeynes@405
   276
nkeynes@1130
   277
    if( argc > 3 ) {
nkeynes@1130
   278
        ifacefile = argv[3];
nkeynes@1130
   279
    } else {
nkeynes@1130
   280
        ifacefile = makeExtension(sourcefile, ".h");
nkeynes@405
   281
    }
nkeynes@405
   282
nkeynes@1130
   283
    writeSource( sourcefile, data );
nkeynes@1130
   284
    writeInterface( ifacefile, data );
nkeynes@405
   285
    return 0;
nkeynes@405
   286
}
.