filename | src/tools/genglsl.c |
changeset | 1130:5f56fc931112 |
prev | 968:6fb1481859a4 |
next | 1151: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 +00001.2 +++ b/src/tools/genglsl.c Fri Sep 17 20:08:50 2010 +10001.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 in1.8 - * a C file with appropriate escaping.1.9 + * Tool to take an input .glsl file and write out a corresponding .c and .h1.10 + * file based on the content. The .glsl file contains a number of shaders1.11 + * marked with either #fragment <name> or #vertex <name>1.12 + * a C file with appropriate escaping, as well as program definitions1.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 modify1.19 * it under the terms of the GNU General Public License as published by1.20 @@ -17,62 +20,267 @@1.21 * GNU General Public License for more details.1.22 */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 40961.33 +#define DEF_ALLOC_SIZE 40961.34 +#define MAX_SHADERS 1281.35 +1.36 +typedef enum {1.37 + VERTEX_SHADER = 0,1.38 + FRAGMENT_SHADER = 11.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.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.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.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.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.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.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 }
.