Search
lxdream.org :: lxdream/src/tools/genglsl.c :: diff
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 (13 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
1.1 --- a/src/tools/genglsl.c Thu Jan 15 11:23:20 2009 +0000
1.2 +++ b/src/tools/genglsl.c Fri Sep 17 20:08:50 2010 +1000
1.3 @@ -1,10 +1,13 @@
1.4 /**
1.5 * $Id$
1.6 *
1.7 - * Trivial tool to take two shader source files and dump them out in
1.8 - * a C file with appropriate escaping.
1.9 + * Tool to take an input .glsl file and write out a corresponding .c and .h
1.10 + * file based on the content. The .glsl file contains a number of shaders
1.11 + * marked with either #fragment <name> or #vertex <name>
1.12 + * a C file with appropriate escaping, as well as program definitions
1.13 + * written as #program <name> = <shader1> <shader2> ... <shaderN>
1.14 *
1.15 - * Copyright (c) 2007 Nathan Keynes.
1.16 + * Copyright (c) 2007-2010 Nathan Keynes.
1.17 *
1.18 * This program is free software; you can redistribute it and/or modify
1.19 * it under the terms of the GNU General Public License as published by
1.20 @@ -17,62 +20,267 @@
1.21 * GNU General Public License for more details.
1.22 */
1.23
1.24 +#include <assert.h>
1.25 +#include <errno.h>
1.26 #include <stdio.h>
1.27 #include <stdlib.h>
1.28 +#include <string.h>
1.29 +#include <glib/gstrfuncs.h>
1.30 +#include <glib/glist.h>
1.31 +
1.32 +#define MAX_LINE 4096
1.33 +#define DEF_ALLOC_SIZE 4096
1.34 +#define MAX_SHADERS 128
1.35 +
1.36 +typedef enum {
1.37 + VERTEX_SHADER = 0,
1.38 + FRAGMENT_SHADER = 1
1.39 +} shader_type_t;
1.40 +
1.41 +typedef struct shader {
1.42 + shader_type_t type;
1.43 + const char *name;
1.44 + char *body;
1.45 +} *shader_t;
1.46 +
1.47 +typedef struct program {
1.48 + const char *name;
1.49 + gchar **shader_names;
1.50 +} *program_t;
1.51 +
1.52 +typedef struct glsldata {
1.53 + const char *filename;
1.54 + unsigned max_shaders;
1.55 + GList *shaders;
1.56 + GList *programs;
1.57 +} *glsldata_t;
1.58 +
1.59 +static struct glsldata *readInput( const char *filename )
1.60 +{
1.61 + char buf[MAX_LINE];
1.62 + size_t current_size = 0, current_posn = 0;
1.63 + unsigned i;
1.64 +
1.65 + FILE *f = fopen( filename, "ro" );
1.66 + if( f == NULL ) {
1.67 + fprintf( stderr, "Error: unable to open input file '%s': %s\n", filename, strerror(errno) );
1.68 + exit(1);
1.69 + }
1.70 +
1.71 + shader_t shader = NULL;
1.72 + glsldata_t result = malloc(sizeof(struct glsldata));
1.73 + assert( result != NULL );
1.74 + result->filename = strdup(filename);
1.75 + result->shaders = NULL;
1.76 + result->programs = NULL;
1.77 + result->max_shaders = 0;
1.78 +
1.79 + while( fgets(buf, sizeof(buf), f) != NULL ) {
1.80 + if( strlen(buf) == 0 )
1.81 + continue;
1.82 +
1.83 + if( strncmp(buf, "#vertex ", 8) == 0 ) {
1.84 + shader = malloc(sizeof(struct shader));
1.85 + assert( shader != NULL );
1.86 + shader->type = VERTEX_SHADER;
1.87 + shader->name = strdup(g_strstrip(buf+8));
1.88 + shader->body = malloc(DEF_ALLOC_SIZE);
1.89 + shader->body[0] = '\0';
1.90 + current_size = DEF_ALLOC_SIZE;
1.91 + current_posn = 0;
1.92 + result->shaders = g_list_append(result->shaders, shader);
1.93 + } else if( strncmp( buf, "#fragment ", 10 ) == 0 ) {
1.94 + shader = malloc(sizeof(struct shader));
1.95 + assert( shader != NULL );
1.96 + shader->type = FRAGMENT_SHADER;
1.97 + shader->name = strdup(g_strstrip(buf+10));
1.98 + shader->body = malloc(DEF_ALLOC_SIZE);
1.99 + shader->body[0] = '\0';
1.100 + current_size = DEF_ALLOC_SIZE;
1.101 + current_posn = 0;
1.102 + result->shaders = g_list_append(result->shaders, shader);
1.103 + } else if( strncmp( buf, "#program ", 9 ) == 0 ) {
1.104 + shader = NULL;
1.105 + program_t program = malloc(sizeof(struct program));
1.106 + char *rest = buf+9;
1.107 + char *equals = strchr(rest, '=');
1.108 + if( equals == NULL ) {
1.109 + fprintf( stderr, "Error: invalid program line %s\n", buf );
1.110 + exit(2);
1.111 + }
1.112 + *equals = '\0';
1.113 + program->name = g_strdup(g_strstrip(rest));
1.114 + program->shader_names = g_strsplit_set(g_strstrip(equals+1), " \t\r,", 0);
1.115 + result->programs = g_list_append(result->programs, program);
1.116 + for(i=0;program->shader_names[i] != NULL; i++ );
1.117 + if( i > result->max_shaders )
1.118 + result->max_shaders = i;
1.119 + } else if( shader != NULL ) {
1.120 + size_t len = strlen(buf);
1.121 + if( current_posn + len > current_size ) {
1.122 + shader->body = realloc(shader->body, current_size*2);
1.123 + assert( shader->body != NULL );
1.124 + current_size *= 2;
1.125 + }
1.126 + strcpy( shader->body + current_posn, buf );
1.127 + current_posn += len;
1.128 + }
1.129 + }
1.130 +
1.131 + fclose(f);
1.132 + return result;
1.133 +}
1.134
1.135 /**
1.136 * Copy input to output, quoting " characters as we go.
1.137 */
1.138 -static void writeShader( FILE *out, FILE *in )
1.139 +static void writeCString( FILE *out, const char *str )
1.140 {
1.141 - int ch;
1.142 + const char *p = str;
1.143
1.144 - while( (ch = fgetc(in)) != EOF ) {
1.145 - if( ch == '\"' ) {
1.146 + while( *p != 0 ) {
1.147 + if( *p == '\"' ) {
1.148 fputc( '\\', out );
1.149 - } else if( ch == '\n') {
1.150 + } else if( *p == '\n' ) {
1.151 fputs( "\\n\\", out );
1.152 }
1.153 - fputc( ch, out );
1.154 + fputc( *p, out );
1.155 + p++;
1.156 + }
1.157 +}
1.158 +
1.159 +static void writeHeader( FILE *out, glsldata_t data )
1.160 +{
1.161 + fprintf( out, "/*\n * This file automatically generated by genglsl from %s\n */\n", data->filename );
1.162 +}
1.163 +
1.164 +static void writeInterface( const char *filename, glsldata_t data )
1.165 +{
1.166 + FILE *f = fopen(filename, "wo");
1.167 + if( f == NULL ) {
1.168 + fprintf( stderr, "Error: Unable to write interface file '%s': %s\n", filename, strerror(errno) );
1.169 + exit(1);
1.170 + }
1.171 +
1.172 + writeHeader( f, data );
1.173 + fprintf( f, "#ifndef lxdream_glsl_H\n#define lxdream_glsl_H 1\n\n" );
1.174 +
1.175 + fprintf( f, "typedef enum {\n" );
1.176 + const char *last_name = NULL;
1.177 + int count = 0;
1.178 + GList *shader_ptr;
1.179 + for( shader_ptr = data->shaders; shader_ptr != NULL; shader_ptr = shader_ptr->next ) {
1.180 + count++;
1.181 + shader_t shader = (shader_t)shader_ptr->data;
1.182 + fprintf( f, " %s,\n", shader->name );
1.183 + last_name = shader->name;
1.184 + }
1.185 + fprintf( f, "} shader_id;\n\n" );
1.186 +
1.187 + if( last_name == NULL )
1.188 + last_name = "NULL";
1.189 + fprintf( f, "#define GLSL_LAST_SHADER %s\n", last_name );
1.190 + fprintf( f, "#define GLSL_NUM_SHADERS %d\n", count );
1.191 + fprintf( f, "#define GLSL_NO_SHADER -1\n\n" );
1.192 + fprintf( f, "#define GLSL_VERTEX_SHADER 1\n" );
1.193 + fprintf( f, "#define GLSL_FRAGMENT_SHADER 2\n" );
1.194 +
1.195 + fprintf( f, "typedef enum {\n" );
1.196 + last_name = NULL;
1.197 + count = 0;
1.198 + GList *program_ptr;
1.199 + for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
1.200 + count++;
1.201 + program_t program = (program_t)program_ptr->data;
1.202 + fprintf( f, " %s,\n", program->name );
1.203 + last_name = program->name;
1.204 + }
1.205 + fprintf( f, "} program_id;\n\n" );
1.206 +
1.207 + if( last_name == NULL )
1.208 + last_name = "NULL";
1.209 + fprintf( f, "#define GLSL_LAST_PROGRAM %s\n", last_name );
1.210 + fprintf( f, "#define GLSL_NUM_PROGRAMS %d\n", count );
1.211 + fprintf( f, "#define GLSL_NO_PROGRAM -1\n\n" );
1.212 +
1.213 + fprintf( f, "int glsl_load_programs();\n" );
1.214 + fprintf( f, "void glsl_use_program_id( program_id );\n" );
1.215 +
1.216 + fprintf( f, "#endif /* !lxdream_glsl_H */\n" );
1.217 +
1.218 + fclose(f);
1.219 +}
1.220 +
1.221 +static void writeSource( const char *filename, glsldata_t data )
1.222 +{
1.223 + FILE *f = fopen(filename, "wo");
1.224 + if( f == NULL ) {
1.225 + fprintf( stderr, "Error: Unable to write interface file '%s': %s\n", filename, strerror(errno) );
1.226 + exit(1);
1.227 + }
1.228 +
1.229 + writeHeader( f, data );
1.230 + fprintf( f, "struct shader_def {\n int type;\n const char *source;\n};\n" );
1.231 +
1.232 + fprintf( f, "const struct shader_def shader_source[] = {\n" );
1.233 + GList *shader_ptr;
1.234 + for( shader_ptr = data->shaders; shader_ptr != NULL; shader_ptr = shader_ptr->next ) {
1.235 + shader_t shader = (shader_t)shader_ptr->data;
1.236 + fprintf( f, " {%s,\"", (shader->type == VERTEX_SHADER ? "GLSL_VERTEX_SHADER" : "GLSL_FRAGMENT_SHADER") );
1.237 + writeCString( f, shader->body );
1.238 + fprintf( f, "\"},\n" );
1.239 + }
1.240 + fprintf( f, " {GLSL_NO_SHADER,NULL}};\n\n" );
1.241 +
1.242 + fprintf( f, "const int program_list[][%d] = {\n", data->max_shaders+1 );
1.243 + GList *program_ptr;
1.244 + unsigned i;
1.245 + for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
1.246 + program_t program = (program_t)program_ptr->data;
1.247 + fprintf( f, " {" );
1.248 + for( i=0; program->shader_names[i] != NULL; i++ ) {
1.249 + fprintf(f, "%s,", program->shader_names[i] );
1.250 + }
1.251 + fprintf( f, "GLSL_NO_SHADER},\n" );
1.252 + }
1.253 + fprintf( f, " {GLSL_NO_SHADER}};\n" );
1.254 +
1.255 + fclose(f);
1.256 +}
1.257 +
1.258 +const char *makeExtension(const char *basename, const char *ext)
1.259 +{
1.260 + const char *oldext = strrchr(basename, '.');
1.261 + if( oldext == NULL ) {
1.262 + return g_strdup_printf("%s%s", basename, ext);
1.263 + } else {
1.264 + return g_strdup_printf("%.*s%s", oldext-basename, basename, ext);
1.265 }
1.266 }
1.267
1.268 int main( int argc, char *argv[] )
1.269 {
1.270 - if( argc != 4 ) {
1.271 - fprintf( stderr, "Usage: genglsl <vertex-shader-file> <fragment-shader-file> <output-file>\n");
1.272 + if( argc < 2 ) {
1.273 + fprintf( stderr, "Usage: genglsl <glsl-source-file> [output.c [output.h]]\n");
1.274 exit(1);
1.275 }
1.276
1.277 - FILE *vsin = fopen( argv[1], "ro" );
1.278 - if( vsin == NULL ) {
1.279 - perror( "Unable to open vertex shader source" );
1.280 - exit(2);
1.281 + glsldata_t data = readInput(argv[1]);
1.282 +
1.283 + const char *sourcefile, *ifacefile;
1.284 + if( argc > 2 ) {
1.285 + sourcefile = argv[2];
1.286 + } else {
1.287 + sourcefile = makeExtension(argv[1], ".def");
1.288 }
1.289
1.290 - FILE *fsin = fopen( argv[2], "ro" );
1.291 - if( fsin == NULL ) {
1.292 - perror( "Unable to open fragment shader source" );
1.293 - exit(2);
1.294 + if( argc > 3 ) {
1.295 + ifacefile = argv[3];
1.296 + } else {
1.297 + ifacefile = makeExtension(sourcefile, ".h");
1.298 }
1.299
1.300 - FILE *out = fopen( argv[3], "wo" );
1.301 - if( out == NULL ) {
1.302 - perror( "Unable to open output file" );
1.303 - exit(2);
1.304 - }
1.305 -
1.306 - fprintf( out, "/**\n * This file is automatically generated - do not edit\n */\n\n" );
1.307 - fprintf( out, "const char *glsl_vertex_shader_src = \"" );
1.308 -
1.309 - writeShader( out, vsin );
1.310 -
1.311 - fprintf( out, "\";\n\n" );
1.312 - fprintf( out, "const char *glsl_fragment_shader_src = \"" );
1.313 - writeShader( out, fsin );
1.314 - fprintf( out, "\";\n\n" );
1.315 - fclose( fsin );
1.316 - fclose( vsin );
1.317 - fclose( out );
1.318 + writeSource( sourcefile, data );
1.319 + writeInterface( ifacefile, data );
1.320 return 0;
1.321 }
.