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