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>
10 * Copyright (c) 2007-2010 Nathan Keynes.
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.
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.
28 #include <glib/gstrfuncs.h>
29 #include <glib/glist.h>
32 #define DEF_ALLOC_SIZE 4096
33 #define MAX_SHADERS 128
40 typedef struct shader {
46 typedef struct program {
51 typedef struct glsldata {
58 static struct glsldata *readInput( const char *filename )
61 size_t current_size = 0, current_posn = 0;
64 FILE *f = fopen( filename, "ro" );
66 fprintf( stderr, "Error: unable to open input file '%s': %s\n", filename, strerror(errno) );
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 )
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;
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;
101 result->shaders = g_list_append(result->shaders, shader);
102 } else if( strncmp( buf, "#program ", 9 ) == 0 ) {
104 program_t program = malloc(sizeof(struct program));
106 char *equals = strchr(rest, '=');
107 if( equals == NULL ) {
108 fprintf( stderr, "Error: invalid program line %s\n", buf );
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 );
125 strcpy( shader->body + current_posn, buf );
135 * Copy input to output, quoting " characters as we go.
137 static void writeCString( FILE *out, const char *str )
144 } else if( *p == '\n' ) {
145 fputs( "\\n\\", out );
152 static void writeHeader( FILE *out, glsldata_t data )
154 fprintf( out, "/*\n * This file automatically generated by genglsl from %s\n */\n", data->filename );
157 static void writeInterface( const char *filename, glsldata_t data )
159 FILE *f = fopen(filename, "wo");
161 fprintf( stderr, "Error: Unable to write interface file '%s': %s\n", filename, strerror(errno) );
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;
172 for( shader_ptr = data->shaders; shader_ptr != NULL; shader_ptr = shader_ptr->next ) {
174 shader_t shader = (shader_t)shader_ptr->data;
175 fprintf( f, " %s,\n", shader->name );
176 last_name = shader->name;
178 fprintf( f, "} shader_id;\n\n" );
180 if( 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" );
192 for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
194 program_t program = (program_t)program_ptr->data;
195 fprintf( f, " %s,\n", program->name );
196 last_name = program->name;
198 fprintf( f, "} program_id;\n\n" );
200 if( 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" );
214 static void writeSource( const char *filename, glsldata_t data )
216 FILE *f = fopen(filename, "wo");
218 fprintf( stderr, "Error: Unable to write interface file '%s': %s\n", filename, strerror(errno) );
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" );
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" );
233 fprintf( f, " {GLSL_NO_SHADER,NULL}};\n\n" );
235 fprintf( f, "const int program_list[][%d] = {\n", data->max_shaders+1 );
238 for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
239 program_t program = (program_t)program_ptr->data;
241 for( i=0; program->shader_names[i] != NULL; i++ ) {
242 fprintf(f, "%s,", program->shader_names[i] );
244 fprintf( f, "GLSL_NO_SHADER},\n" );
246 fprintf( f, " {GLSL_NO_SHADER}};\n" );
251 const char *makeExtension(const char *basename, const char *ext)
253 const char *oldext = strrchr(basename, '.');
254 if( oldext == NULL ) {
255 return g_strdup_printf("%s%s", basename, ext);
257 return g_strdup_printf("%.*s%s", (int)(oldext-basename), basename, ext);
261 int main( int argc, char *argv[] )
264 fprintf( stderr, "Usage: genglsl <glsl-source-file> [output.c [output.h]]\n");
268 glsldata_t data = readInput(argv[1]);
270 const char *sourcefile, *ifacefile;
272 sourcefile = argv[2];
274 sourcefile = makeExtension(argv[1], ".def");
280 ifacefile = makeExtension(sourcefile, ".h");
283 writeSource( sourcefile, data );
284 writeInterface( ifacefile, data );
.