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
view annotate diff log raw
     1 /**
     2  * $Id$
     3  *
     4  * Tool to take an input .glsl file and write out a corresponding .c and .h
     5  * file based on the content. The .glsl file contains a number of shaders
     6  * marked with either #fragment <name> or #vertex <name>
     7  * a C file with appropriate escaping, as well as program definitions
     8  * written as #program <name> = <shader1> <shader2> ... <shaderN>
     9  *
    10  * Copyright (c) 2007-2010 Nathan Keynes.
    11  *
    12  * This program is free software; you can redistribute it and/or modify
    13  * it under the terms of the GNU General Public License as published by
    14  * the Free Software Foundation; either version 2 of the License, or
    15  * (at your option) any later version.
    16  *
    17  * This program is distributed in the hope that it will be useful,
    18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    20  * GNU General Public License for more details.
    21  */
    23 #include <assert.h>
    24 #include <errno.h>
    25 #include <stdio.h>
    26 #include <stdlib.h>
    27 #include <string.h>
    28 #include <glib/gstrfuncs.h>
    29 #include <glib/glist.h>
    31 #define MAX_LINE 4096
    32 #define DEF_ALLOC_SIZE 4096
    33 #define MAX_SHADERS 128
    35 typedef enum {
    36     VERTEX_SHADER = 0,
    37     FRAGMENT_SHADER = 1
    38 } shader_type_t;
    40 typedef struct uniform {
    41     const char *name;
    42     const char *var_name;
    43 } *uniform_t;
    45 typedef struct shader {
    46     shader_type_t type;
    47     const char *name;
    48     char *body;
    49     GList *uniforms;
    50 } *shader_t;
    52 typedef struct program {
    53     const char *name;
    54     gchar **shader_names;
    55 } *program_t;
    57 typedef struct glsldata {
    58     const char *filename;
    59     unsigned max_shaders;
    60     GList *shaders;
    61     GList *programs;
    62 } *glsldata_t;
    64 static struct glsldata *readInput( const char *filename )
    65 {
    66     char buf[MAX_LINE];
    67     size_t current_size = 0, current_posn = 0;
    68     unsigned i;
    70     FILE *f = fopen( filename, "ro" );
    71     if( f == NULL ) {
    72         fprintf( stderr, "Error: unable to open input file '%s': %s\n", filename, strerror(errno) );
    73         exit(1);
    74     }
    76     shader_t shader = NULL;
    77     glsldata_t result = malloc(sizeof(struct glsldata));
    78     assert( result != NULL );
    79     result->filename = strdup(filename);
    80     result->shaders = NULL;
    81     result->programs = NULL;
    82     result->max_shaders = 0;
    84     while( fgets(buf, sizeof(buf), f) != NULL ) {
    85         if( strlen(buf) == 0 )
    86             continue;
    88         if( strncmp(buf, "#vertex ", 8) == 0 ) {
    89             shader = malloc(sizeof(struct shader));
    90             assert( shader != NULL );
    91             shader->type = VERTEX_SHADER;
    92             shader->name = strdup(g_strstrip(buf+8));
    93             shader->body = malloc(DEF_ALLOC_SIZE);
    94             shader->body[0] = '\0';
    95             shader->uniforms = 0;
    96             current_size = DEF_ALLOC_SIZE;
    97             current_posn = 0;
    98             result->shaders = g_list_append(result->shaders, shader);
    99         } else if( strncmp( buf, "#fragment ", 10 ) == 0 ) {
   100             shader = malloc(sizeof(struct shader));
   101             assert( shader != NULL );
   102             shader->type = FRAGMENT_SHADER;
   103             shader->name = strdup(g_strstrip(buf+10));
   104             shader->body = malloc(DEF_ALLOC_SIZE);
   105             shader->body[0] = '\0';
   106             shader->uniforms = 0;
   107             current_size = DEF_ALLOC_SIZE;
   108             current_posn = 0;
   109             result->shaders = g_list_append(result->shaders, shader);
   110         } else if( strncmp( buf, "#program ", 9 ) == 0 ) {
   111             shader = NULL;
   112             program_t program = malloc(sizeof(struct program));
   113             assert( program != NULL );
   114             char *rest = buf+9;
   115             char *equals = strchr(rest, '=');
   116             if( equals == NULL ) {
   117                 fprintf( stderr, "Error: invalid program line %s\n", buf );
   118                 exit(2);
   119             }
   120             *equals = '\0';
   121             program->name = g_strdup(g_strstrip(rest));
   122             program->shader_names = g_strsplit_set(g_strstrip(equals+1), " \t\r,", 0);
   123             result->programs = g_list_append(result->programs, program);
   124             for(i=0;program->shader_names[i] != NULL; i++ );
   125             if( i > result->max_shaders )
   126                 result->max_shaders = i;
   127         } else if( strncmp( buf, "#uniform ", 9 ) == 0 ) {
   128             uniform_t uniform = malloc(sizeof(struct uniform));
   129             assert( uniform != NULL );
   130             if( shader == NULL ) {
   131                 fprintf( stderr, "Error: #uniform specified outside of shader: %s\n", buf );
   132                 exit(2);
   133             }
   134             char *rest = buf+9;
   135             char *equals = strchr(rest, '=');
   136             if( equals == NULL ) {
   137                 fprintf( stderr, "Error: invalid program line %s\n", buf );
   138                 exit(2);
   139             }
   140             *equals = '\0';
   141             uniform->name = g_strdup(g_strstrip(rest));
   142             uniform->var_name = g_strdup(g_strstrip(equals+1));
   143             shader->uniforms = g_list_append(shader->uniforms, uniform);
   144         } else if( shader != NULL ) {
   145             size_t len = strlen(buf);
   146             if( current_posn + len > current_size ) {
   147                 shader->body = realloc(shader->body, current_size*2);
   148                 assert( shader->body != NULL );
   149                 current_size *= 2;
   150             }
   151             strcpy( shader->body + current_posn, buf );
   152             current_posn += len;
   153         }
   154     }
   156     fclose(f);
   157     return result;
   158 }
   160 /**
   161  * Copy input to output, quoting " characters as we go.
   162  */
   163 static void writeCString( FILE *out, const char *str )
   164 {
   165     const char *p = str;
   167     while( *p != 0 ) {
   168         if( *p == '\"' ) {
   169             fputc( '\\', out );
   170         } else if( *p == '\n' ) {
   171             fputs( "\\n\\", out );
   172         }
   173         fputc( *p, out );
   174         p++;
   175     }
   176 }
   178 static uniform_t find_uniform_name( GList *list, const char *name )
   179 {
   180     GList *ptr;
   181     for( ptr = list; ptr != NULL; ptr = ptr->next ) {
   182         uniform_t data = (uniform_t)list->data;
   183         if( strcmp( data->name, name ) == 0 )
   184             return data;
   185     }
   186     return NULL;
   187 }
   189 static void writeHeader( FILE *out, glsldata_t data )
   190 {
   191     fprintf( out, "/*\n * This file automatically generated by genglsl from %s\n */\n", data->filename );
   192 }
   194 static void writeInterface( const char *filename, glsldata_t data )
   195 {
   196     FILE *f = fopen(filename, "wo");
   197     if( f == NULL ) {
   198         fprintf( stderr, "Error: Unable to write interface file '%s': %s\n", filename, strerror(errno) );
   199         exit(1);
   200     }
   202     writeHeader( f, data );
   203     fprintf( f, "#ifndef lxdream_glsl_H\n#define lxdream_glsl_H 1\n\n" );
   205     fprintf( f, "typedef enum {\n" );
   206     const char *last_name = NULL;
   207     int count = 0;
   208     GList *unique_uniforms;
   209     int uniform_count = 0;
   210     GList *shader_ptr;
   211     for( shader_ptr = data->shaders; shader_ptr != NULL; shader_ptr = shader_ptr->next ) {
   212         count++;
   213         shader_t shader = (shader_t)shader_ptr->data;
   214         fprintf( f, "    %s,\n", shader->name );
   215         last_name = shader->name;
   216         GList *uniform_ptr;
   217         for( uniform_ptr = shader->uniforms; uniform_ptr != NULL; uniform_ptr = uniform_ptr->next ) {
   218             uniform_t uniform = (uniform_t)uniform_ptr->data;
   219             if( find_uniform_name(unique_uniforms, uniform->name) == NULL ) {
   220                 unique_uniforms = g_list_append( unique_uniforms, uniform );
   221                 uniform_count++;
   222             }
   223         }
   224     }
   225     fprintf( f, "} shader_id;\n\n" );
   227     if( last_name == NULL )
   228         last_name = "NULL";
   229     fprintf( f, "#define GLSL_LAST_SHADER %s\n", last_name );
   230     fprintf( f, "#define GLSL_NUM_SHADERS %d\n", count );
   231     fprintf( f, "#define GLSL_NO_SHADER -1\n\n" );
   232     fprintf( f, "#define GLSL_VERTEX_SHADER 1\n" );
   233     fprintf( f, "#define GLSL_FRAGMENT_SHADER 2\n" );
   234     fprintf( f, "#define GLSL_NUM_UNIFORMS %d\n", uniform_count );
   236     fprintf( f, "typedef enum {\n" );
   237     last_name = NULL;
   238     count = 0;
   239     GList *program_ptr;
   240     for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
   241         count++;
   242         program_t program = (program_t)program_ptr->data;
   243         fprintf( f, "    %s,\n", program->name );
   244         last_name = program->name;
   245     }
   246     fprintf( f, "} program_id;\n\n" );
   248     if( last_name == NULL )
   249         last_name = "NULL";
   250     fprintf( f, "#define GLSL_LAST_PROGRAM %s\n", last_name );
   251     fprintf( f, "#define GLSL_NUM_PROGRAMS %d\n", count );
   252     fprintf( f, "#define GLSL_NO_PROGRAM -1\n\n" );
   254     fprintf( f, "int glsl_load_programs();\n" );
   255     fprintf( f, "void glsl_use_program_id( program_id );\n" );
   257     fprintf( f, "#endif /* !lxdream_glsl_H */\n" );
   259     fclose(f);
   260 }
   262 static void writeSource( const char *filename, glsldata_t data )
   263 {
   264     FILE *f = fopen(filename, "wo");
   265     if( f == NULL ) {
   266         fprintf( stderr, "Error: Unable to write interface file '%s': %s\n", filename, strerror(errno) );
   267         exit(1);
   268     }
   270     writeHeader( f, data );
   271     fprintf( f, "struct shader_def {\n    int type;\n    const char *source;\n};\n" );
   273     fprintf( f, "const struct shader_def shader_source[] = {\n" );
   274     GList *shader_ptr;
   275     for( shader_ptr = data->shaders; shader_ptr != NULL; shader_ptr = shader_ptr->next ) {
   276         shader_t shader = (shader_t)shader_ptr->data;
   277         fprintf( f, "    {%s,\"", (shader->type == VERTEX_SHADER ? "GLSL_VERTEX_SHADER" : "GLSL_FRAGMENT_SHADER") );
   278         writeCString( f, shader->body );
   279         fprintf( f, "\"},\n" );
   280     }
   281     fprintf( f, "    {GLSL_NO_SHADER,NULL}};\n\n" );
   283     fprintf( f, "const int program_list[][%d] = {\n", data->max_shaders+1 );
   284     GList *program_ptr;
   285     unsigned i;
   286     for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
   287         program_t program = (program_t)program_ptr->data;
   288         fprintf( f, "    {" );
   289         for( i=0; program->shader_names[i] != NULL; i++ ) {
   290             fprintf(f, "%s,", program->shader_names[i] );
   291         }
   292         fprintf( f, "GLSL_NO_SHADER},\n" );
   293     }
   294     fprintf( f, "    {GLSL_NO_SHADER}};\n" );
   296     fclose(f);
   297 }
   299 const char *makeExtension(const char *basename, const char *ext)
   300 {
   301     const char *oldext = strrchr(basename, '.');
   302     if( oldext == NULL ) {
   303         return g_strdup_printf("%s%s", basename, ext);
   304     } else {
   305         return g_strdup_printf("%.*s%s", oldext-basename, basename, ext);
   306     }
   307 }
   309 int main( int argc, char *argv[] )
   310 {
   311     if( argc < 2 ) {
   312         fprintf( stderr, "Usage: genglsl <glsl-source-file> [output.c [output.h]]\n");
   313         exit(1);
   314     }
   316     glsldata_t data = readInput(argv[1]);
   318     const char *sourcefile, *ifacefile;
   319     if( argc > 2 ) {
   320         sourcefile = argv[2];
   321     } else {
   322         sourcefile = makeExtension(argv[1], ".def");
   323     }
   325     if( argc > 3 ) {
   326         ifacefile = argv[3];
   327     } else {
   328         ifacefile = makeExtension(sourcefile, ".h");
   329     }
   331     writeSource( sourcefile, data );
   332     writeInterface( ifacefile, data );
   333     return 0;
   334 }
.