filename | src/tools/genglsl.c |
changeset | 1258:f8a9c0fd2abb |
prev | 1240:190df8a791ca |
next | 1288:fdb8f59143c7 |
author | nkeynes |
date | Sun Jul 01 13:20:34 2012 +1000 (11 years ago) |
permissions | -rw-r--r-- |
last change | Add support for Nokia N900 - Generic support for EGL with GTK - Workaround for nokia bug with egl config Based on patch from guinux, thanks! |
file | annotate | diff | log | raw |
nkeynes@405 | 1 | /** |
nkeynes@561 | 2 | * $Id$ |
nkeynes@405 | 3 | * |
nkeynes@1130 | 4 | * Tool to take an input .glsl file and write out a corresponding .c and .h |
nkeynes@1130 | 5 | * file based on the content. The .glsl file contains a number of shaders |
nkeynes@1130 | 6 | * marked with either #fragment <name> or #vertex <name> |
nkeynes@1130 | 7 | * a C file with appropriate escaping, as well as program definitions |
nkeynes@1130 | 8 | * written as #program <name> = <shader1> <shader2> ... <shaderN> |
nkeynes@405 | 9 | * |
nkeynes@1234 | 10 | * Copyright (c) 2007-2012 Nathan Keynes. |
nkeynes@405 | 11 | * |
nkeynes@405 | 12 | * This program is free software; you can redistribute it and/or modify |
nkeynes@405 | 13 | * it under the terms of the GNU General Public License as published by |
nkeynes@405 | 14 | * the Free Software Foundation; either version 2 of the License, or |
nkeynes@405 | 15 | * (at your option) any later version. |
nkeynes@405 | 16 | * |
nkeynes@405 | 17 | * This program is distributed in the hope that it will be useful, |
nkeynes@405 | 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
nkeynes@405 | 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
nkeynes@405 | 20 | * GNU General Public License for more details. |
nkeynes@405 | 21 | */ |
nkeynes@405 | 22 | |
nkeynes@1130 | 23 | #include <assert.h> |
nkeynes@1207 | 24 | #include <ctype.h> |
nkeynes@1130 | 25 | #include <errno.h> |
nkeynes@405 | 26 | #include <stdio.h> |
nkeynes@405 | 27 | #include <stdlib.h> |
nkeynes@1130 | 28 | #include <string.h> |
nkeynes@1234 | 29 | #include <getopt.h> |
nkeynes@1130 | 30 | #include <glib/gstrfuncs.h> |
nkeynes@1235 | 31 | #include <glib/gshell.h> |
nkeynes@1130 | 32 | #include <glib/glist.h> |
nkeynes@1235 | 33 | #include "../../config.h" |
nkeynes@1130 | 34 | |
nkeynes@1130 | 35 | #define MAX_LINE 4096 |
nkeynes@1130 | 36 | #define DEF_ALLOC_SIZE 4096 |
nkeynes@1130 | 37 | #define MAX_SHADERS 128 |
nkeynes@1130 | 38 | |
nkeynes@1130 | 39 | typedef enum { |
nkeynes@1130 | 40 | VERTEX_SHADER = 0, |
nkeynes@1130 | 41 | FRAGMENT_SHADER = 1 |
nkeynes@1130 | 42 | } shader_type_t; |
nkeynes@1130 | 43 | |
nkeynes@1207 | 44 | typedef struct variable { |
nkeynes@1207 | 45 | gboolean uniform; /* TRUE = uniform, FALSE = attribute */ |
nkeynes@1207 | 46 | const char *name; |
nkeynes@1207 | 47 | const char *type; |
nkeynes@1207 | 48 | } *variable_t; |
nkeynes@1207 | 49 | |
nkeynes@1130 | 50 | typedef struct shader { |
nkeynes@1130 | 51 | shader_type_t type; |
nkeynes@1130 | 52 | const char *name; |
nkeynes@1130 | 53 | char *body; |
nkeynes@1207 | 54 | GList *variables; |
nkeynes@1130 | 55 | } *shader_t; |
nkeynes@1130 | 56 | |
nkeynes@1130 | 57 | typedef struct program { |
nkeynes@1130 | 58 | const char *name; |
nkeynes@1130 | 59 | gchar **shader_names; |
nkeynes@1207 | 60 | GList *shaders; |
nkeynes@1207 | 61 | GList *variables; |
nkeynes@1130 | 62 | } *program_t; |
nkeynes@1130 | 63 | |
nkeynes@1130 | 64 | typedef struct glsldata { |
nkeynes@1130 | 65 | const char *filename; |
nkeynes@1130 | 66 | unsigned max_shaders; |
nkeynes@1130 | 67 | GList *shaders; |
nkeynes@1130 | 68 | GList *programs; |
nkeynes@1130 | 69 | } *glsldata_t; |
nkeynes@1130 | 70 | |
nkeynes@1207 | 71 | #define isident(c) (isalnum(c)||(c)=='_') |
nkeynes@1207 | 72 | |
nkeynes@1207 | 73 | static void parseVarDecl( shader_t shader, gboolean uniform, char *input ) |
nkeynes@1207 | 74 | { |
nkeynes@1207 | 75 | unsigned i; |
nkeynes@1207 | 76 | char *p = g_strstrip(input); |
nkeynes@1207 | 77 | for( i=0; isident(p[i]); i++) |
nkeynes@1207 | 78 | if( p[i] == 0 ) { |
nkeynes@1207 | 79 | fprintf( stderr, "Error: unable to parse variable decl '%s'\n", p ); |
nkeynes@1207 | 80 | return; /* incomplete decl? */ |
nkeynes@1207 | 81 | } |
nkeynes@1207 | 82 | char *type = g_strndup(p, i); |
nkeynes@1207 | 83 | p = g_strstrip(input+i); |
nkeynes@1207 | 84 | for( i=0; isident(p[i]); i++) |
nkeynes@1207 | 85 | if( p[i] == 0 ) { |
nkeynes@1207 | 86 | fprintf( stderr, "Error: unable to parse variable decl '%s'\n", p ); |
nkeynes@1207 | 87 | return; /* incomplete decl? */ |
nkeynes@1207 | 88 | } |
nkeynes@1207 | 89 | char *name = g_strndup(p, i); |
nkeynes@1207 | 90 | variable_t var = g_malloc0(sizeof(struct variable)); |
nkeynes@1207 | 91 | var->uniform = uniform; |
nkeynes@1207 | 92 | var->type = type; |
nkeynes@1207 | 93 | var->name = name; |
nkeynes@1207 | 94 | shader->variables = g_list_append(shader->variables,var); |
nkeynes@1207 | 95 | } |
nkeynes@1207 | 96 | |
nkeynes@1207 | 97 | static shader_t findShader( GList *shaders, const char *name ) |
nkeynes@1207 | 98 | { |
nkeynes@1207 | 99 | GList *ptr = shaders; |
nkeynes@1207 | 100 | while( ptr != NULL ) { |
nkeynes@1207 | 101 | shader_t shader = ptr->data; |
nkeynes@1207 | 102 | if( strcmp(shader->name, name) == 0 ) |
nkeynes@1207 | 103 | return shader; |
nkeynes@1207 | 104 | ptr = ptr->next; |
nkeynes@1207 | 105 | } |
nkeynes@1207 | 106 | return NULL; |
nkeynes@1207 | 107 | } |
nkeynes@1207 | 108 | |
nkeynes@1207 | 109 | static gboolean addProgramVariable( program_t program, variable_t variable ) |
nkeynes@1207 | 110 | { |
nkeynes@1207 | 111 | GList *ptr = program->variables; |
nkeynes@1207 | 112 | while( ptr != NULL ) { |
nkeynes@1207 | 113 | variable_t varp = ptr->data; |
nkeynes@1207 | 114 | if( strcmp(varp->name, variable->name) == 0 ) { |
nkeynes@1207 | 115 | if( varp->uniform == variable->uniform && strcmp(varp->type, variable->type) == 0 ) |
nkeynes@1207 | 116 | return TRUE; /* All ok */ |
nkeynes@1207 | 117 | fprintf( stderr, "Error: Variable type mismatch on '%s'\n", variable->name ); |
nkeynes@1207 | 118 | return FALSE; |
nkeynes@1207 | 119 | } |
nkeynes@1207 | 120 | ptr = ptr->next; |
nkeynes@1207 | 121 | } |
nkeynes@1207 | 122 | program->variables = g_list_append(program->variables, variable); |
nkeynes@1207 | 123 | return TRUE; |
nkeynes@1207 | 124 | } |
nkeynes@1207 | 125 | |
nkeynes@1207 | 126 | static void linkPrograms( glsldata_t data ) |
nkeynes@1207 | 127 | { |
nkeynes@1207 | 128 | GList *program_ptr = data->programs; |
nkeynes@1207 | 129 | unsigned i; |
nkeynes@1207 | 130 | while( program_ptr != NULL ) { |
nkeynes@1207 | 131 | program_t program = program_ptr->data; |
nkeynes@1207 | 132 | for( i=0; program->shader_names[i] != NULL; i++ ) { |
nkeynes@1207 | 133 | shader_t shader = findShader(data->shaders, program->shader_names[i]); |
nkeynes@1207 | 134 | if( shader == NULL ) { |
nkeynes@1207 | 135 | fprintf( stderr, "Error: unable to resolve shader '%s'\n", program->shader_names[i] );\ |
nkeynes@1207 | 136 | } else { |
nkeynes@1207 | 137 | GList *varptr = shader->variables; |
nkeynes@1207 | 138 | while( varptr != NULL ) { |
nkeynes@1207 | 139 | addProgramVariable(program, varptr->data); |
nkeynes@1207 | 140 | varptr = varptr->next; |
nkeynes@1207 | 141 | } |
nkeynes@1207 | 142 | } |
nkeynes@1207 | 143 | } |
nkeynes@1207 | 144 | program_ptr = program_ptr->next; |
nkeynes@1207 | 145 | } |
nkeynes@1207 | 146 | |
nkeynes@1207 | 147 | } |
nkeynes@1207 | 148 | |
nkeynes@1235 | 149 | static GList *temp_filenames = NULL; |
nkeynes@1207 | 150 | |
nkeynes@1235 | 151 | static void cleanup_tempfiles(void) |
nkeynes@1235 | 152 | { |
nkeynes@1235 | 153 | while( temp_filenames != NULL ) { |
nkeynes@1235 | 154 | unlink( (char *)temp_filenames->data ); |
nkeynes@1235 | 155 | g_free(temp_filenames->data); |
nkeynes@1235 | 156 | temp_filenames = temp_filenames->next; |
nkeynes@1235 | 157 | } |
nkeynes@1235 | 158 | } |
nkeynes@1235 | 159 | |
nkeynes@1235 | 160 | /** |
nkeynes@1235 | 161 | * Preprocess the input file and return a temporary filename containing the result |
nkeynes@1235 | 162 | */ |
nkeynes@1235 | 163 | static FILE *preprocessInput( const char *filename, GList *cpp_opts ) |
nkeynes@1235 | 164 | { |
nkeynes@1235 | 165 | char tmpname[] = "/tmp/genglsl.XXXXXXXX"; |
nkeynes@1235 | 166 | int fd = mkstemp(tmpname); |
nkeynes@1235 | 167 | if( fd == -1 ) { |
nkeynes@1235 | 168 | fprintf( stderr, "Error: unable to get a temporary filename (%s)\n", strerror(errno) ); |
nkeynes@1235 | 169 | exit(2); |
nkeynes@1235 | 170 | } |
nkeynes@1235 | 171 | char *quoted_filename = g_shell_quote(filename); |
nkeynes@1235 | 172 | |
nkeynes@1235 | 173 | int nOpts = g_list_length(cpp_opts); |
nkeynes@1235 | 174 | gchar *quoted_opts_arr[nOpts]; |
nkeynes@1235 | 175 | int length = 0, count=0; |
nkeynes@1235 | 176 | for( GList *ptr = cpp_opts; ptr != NULL; ptr = ptr->next ) { |
nkeynes@1235 | 177 | quoted_opts_arr[count] = g_shell_quote((gchar *)ptr->data); |
nkeynes@1235 | 178 | length += strlen(quoted_opts_arr[count++]) + 1; |
nkeynes@1235 | 179 | } |
nkeynes@1235 | 180 | gchar quoted_cpp_opts[length]; |
nkeynes@1235 | 181 | quoted_cpp_opts[0] = '\0'; |
nkeynes@1235 | 182 | for( count=0; count<nOpts; count++ ) { |
nkeynes@1235 | 183 | if( count != 0 ) |
nkeynes@1235 | 184 | strcat(quoted_cpp_opts, " "); |
nkeynes@1235 | 185 | strcat(quoted_cpp_opts, quoted_opts_arr[count]); |
nkeynes@1235 | 186 | g_free(quoted_opts_arr[count++]); |
nkeynes@1235 | 187 | } |
nkeynes@1235 | 188 | |
nkeynes@1235 | 189 | const char *command = g_strdup_printf("%s -E 's/^#(program|vertex|fragment)/#pragma \\1/' %s | %s %s - > %s", |
nkeynes@1235 | 190 | BUILD_SED_PROG, quoted_filename, BUILD_CPP_PROG, quoted_cpp_opts, tmpname ); |
nkeynes@1235 | 191 | if( system(command) != 0 ) { |
nkeynes@1235 | 192 | fprintf( stderr, "Error: unable to run preprocessor command '%s' (%s)\n", command, strerror(errno) ); |
nkeynes@1235 | 193 | exit(2); |
nkeynes@1235 | 194 | } |
nkeynes@1235 | 195 | |
nkeynes@1235 | 196 | temp_filenames = g_list_append(temp_filenames, g_strdup(tmpname)); |
nkeynes@1235 | 197 | return fdopen(fd, "r"); |
nkeynes@1235 | 198 | } |
nkeynes@1235 | 199 | |
nkeynes@1235 | 200 | static void readInput( const char *filename, GList *cpp_opts, glsldata_t result ) |
nkeynes@1130 | 201 | { |
nkeynes@1130 | 202 | char buf[MAX_LINE]; |
nkeynes@1130 | 203 | size_t current_size = 0, current_posn = 0; |
nkeynes@1130 | 204 | unsigned i; |
nkeynes@1130 | 205 | |
nkeynes@1235 | 206 | |
nkeynes@1235 | 207 | FILE *f = preprocessInput(filename, cpp_opts ); |
nkeynes@1130 | 208 | if( f == NULL ) { |
nkeynes@1130 | 209 | fprintf( stderr, "Error: unable to open input file '%s': %s\n", filename, strerror(errno) ); |
nkeynes@1234 | 210 | exit(2); |
nkeynes@1130 | 211 | } |
nkeynes@1130 | 212 | |
nkeynes@1130 | 213 | shader_t shader = NULL; |
nkeynes@1234 | 214 | if( result->filename == NULL ) { |
nkeynes@1234 | 215 | result->filename = g_strdup(filename); |
nkeynes@1234 | 216 | } else { |
nkeynes@1234 | 217 | const gchar *tmp = result->filename; |
nkeynes@1234 | 218 | result->filename = g_strdup_printf("%s, %s", tmp, filename); |
nkeynes@1234 | 219 | g_free((gchar *)tmp); |
nkeynes@1234 | 220 | } |
nkeynes@1130 | 221 | |
nkeynes@1130 | 222 | while( fgets(buf, sizeof(buf), f) != NULL ) { |
nkeynes@1130 | 223 | if( strlen(buf) == 0 ) |
nkeynes@1130 | 224 | continue; |
nkeynes@1130 | 225 | |
nkeynes@1235 | 226 | if( buf[0] == '#' ) { |
nkeynes@1235 | 227 | char *p = buf+1; |
nkeynes@1235 | 228 | if( strncmp(p, "pragma ", 7) == 0 ) { |
nkeynes@1235 | 229 | p += 7; |
nkeynes@1130 | 230 | } |
nkeynes@1235 | 231 | if( strncmp(p, "vertex ", 7) == 0 ) { |
nkeynes@1235 | 232 | shader = g_malloc0(sizeof(struct shader)); |
nkeynes@1235 | 233 | assert( shader != NULL ); |
nkeynes@1235 | 234 | shader->type = VERTEX_SHADER; |
nkeynes@1235 | 235 | shader->name = strdup(g_strstrip(p+7)); |
nkeynes@1235 | 236 | shader->body = malloc(DEF_ALLOC_SIZE); |
nkeynes@1235 | 237 | shader->body[0] = '\0'; |
nkeynes@1235 | 238 | current_size = DEF_ALLOC_SIZE; |
nkeynes@1235 | 239 | current_posn = 0; |
nkeynes@1235 | 240 | result->shaders = g_list_append(result->shaders, shader); |
nkeynes@1235 | 241 | } else if( strncmp( p, "fragment ", 9 ) == 0 ) { |
nkeynes@1235 | 242 | shader = g_malloc0(sizeof(struct shader)); |
nkeynes@1235 | 243 | assert( shader != NULL ); |
nkeynes@1235 | 244 | shader->type = FRAGMENT_SHADER; |
nkeynes@1235 | 245 | shader->name = strdup(g_strstrip(p+9)); |
nkeynes@1235 | 246 | shader->body = malloc(DEF_ALLOC_SIZE); |
nkeynes@1235 | 247 | shader->body[0] = '\0'; |
nkeynes@1235 | 248 | current_size = DEF_ALLOC_SIZE; |
nkeynes@1235 | 249 | current_posn = 0; |
nkeynes@1235 | 250 | result->shaders = g_list_append(result->shaders, shader); |
nkeynes@1235 | 251 | } else if( strncmp( p, "program ", 8 ) == 0 ) { |
nkeynes@1235 | 252 | shader = NULL; |
nkeynes@1235 | 253 | program_t program = g_malloc0(sizeof(struct program)); |
nkeynes@1235 | 254 | char *rest = p+8; |
nkeynes@1235 | 255 | char *equals = strchr(rest, '='); |
nkeynes@1235 | 256 | if( equals == NULL ) { |
nkeynes@1235 | 257 | fprintf( stderr, "Error: invalid program line %s\n", buf ); |
nkeynes@1235 | 258 | exit(2); |
nkeynes@1235 | 259 | } |
nkeynes@1235 | 260 | *equals = '\0'; |
nkeynes@1235 | 261 | program->name = g_strdup(g_strstrip(rest)); |
nkeynes@1235 | 262 | program->shader_names = g_strsplit_set(g_strstrip(equals+1), " \t\r,", 0); |
nkeynes@1235 | 263 | result->programs = g_list_append(result->programs, program); |
nkeynes@1235 | 264 | for(i=0;program->shader_names[i] != NULL; i++ ); |
nkeynes@1235 | 265 | if( i > result->max_shaders ) |
nkeynes@1235 | 266 | result->max_shaders = i; |
nkeynes@1235 | 267 | } |
nkeynes@1235 | 268 | /* Else discard any other # lines */ |
nkeynes@1130 | 269 | } else if( shader != NULL ) { |
nkeynes@1130 | 270 | size_t len = strlen(buf); |
nkeynes@1130 | 271 | if( current_posn + len > current_size ) { |
nkeynes@1130 | 272 | shader->body = realloc(shader->body, current_size*2); |
nkeynes@1130 | 273 | assert( shader->body != NULL ); |
nkeynes@1130 | 274 | current_size *= 2; |
nkeynes@1130 | 275 | } |
nkeynes@1130 | 276 | strcpy( shader->body + current_posn, buf ); |
nkeynes@1130 | 277 | current_posn += len; |
nkeynes@1207 | 278 | char *line = g_strstrip(buf); |
nkeynes@1207 | 279 | if( strncmp( line, "uniform ", 8 ) == 0 ) { |
nkeynes@1207 | 280 | parseVarDecl(shader, TRUE, line+8); |
nkeynes@1207 | 281 | } else if( strncmp( line, "attribute ", 10 ) == 0 ) { |
nkeynes@1207 | 282 | parseVarDecl(shader, FALSE, line+10); |
nkeynes@1207 | 283 | } |
nkeynes@1130 | 284 | } |
nkeynes@1130 | 285 | } |
nkeynes@1130 | 286 | |
nkeynes@1130 | 287 | fclose(f); |
nkeynes@1130 | 288 | } |
nkeynes@405 | 289 | |
nkeynes@405 | 290 | /** |
nkeynes@405 | 291 | * Copy input to output, quoting " characters as we go. |
nkeynes@405 | 292 | */ |
nkeynes@1130 | 293 | static void writeCString( FILE *out, const char *str ) |
nkeynes@405 | 294 | { |
nkeynes@1130 | 295 | const char *p = str; |
nkeynes@405 | 296 | |
nkeynes@1130 | 297 | while( *p != 0 ) { |
nkeynes@1130 | 298 | if( *p == '\"' ) { |
nkeynes@736 | 299 | fputc( '\\', out ); |
nkeynes@1130 | 300 | } else if( *p == '\n' ) { |
nkeynes@736 | 301 | fputs( "\\n\\", out ); |
nkeynes@736 | 302 | } |
nkeynes@1130 | 303 | fputc( *p, out ); |
nkeynes@1130 | 304 | p++; |
nkeynes@1130 | 305 | } |
nkeynes@1130 | 306 | } |
nkeynes@1130 | 307 | |
nkeynes@1207 | 308 | static const char *sl_type_map[][3] = { |
nkeynes@1207 | 309 | {"int", "int", "int *"}, |
nkeynes@1229 | 310 | {"float", "float", "float *"}, |
nkeynes@1207 | 311 | {"short", "short", "short *"}, |
nkeynes@1207 | 312 | {"sampler", "int", "int *"}, |
nkeynes@1207 | 313 | {"vec", "GLfloat *", "GLfloat *"}, |
nkeynes@1207 | 314 | {"mat", "GLfloat *", "GLfloat *"}, |
nkeynes@1207 | 315 | {NULL, NULL} |
nkeynes@1207 | 316 | }; |
nkeynes@1207 | 317 | |
nkeynes@1207 | 318 | static const char *getCType( const char *sl_type, gboolean isUniform ) { |
nkeynes@1207 | 319 | for( unsigned i=0; sl_type_map[i][0] != NULL; i++ ) { |
nkeynes@1207 | 320 | if( strncmp(sl_type_map[i][0], sl_type, strlen(sl_type_map[i][0])) == 0 ) { |
nkeynes@1207 | 321 | if( isUniform ) { |
nkeynes@1207 | 322 | return sl_type_map[i][1]; |
nkeynes@1207 | 323 | } else { |
nkeynes@1207 | 324 | return sl_type_map[i][2]; |
nkeynes@1207 | 325 | } |
nkeynes@1207 | 326 | } |
nkeynes@1207 | 327 | } |
nkeynes@1207 | 328 | return "void *"; |
nkeynes@1207 | 329 | } |
nkeynes@1207 | 330 | |
nkeynes@1130 | 331 | static void writeHeader( FILE *out, glsldata_t data ) |
nkeynes@1130 | 332 | { |
nkeynes@1130 | 333 | fprintf( out, "/*\n * This file automatically generated by genglsl from %s\n */\n", data->filename ); |
nkeynes@1130 | 334 | } |
nkeynes@1130 | 335 | |
nkeynes@1130 | 336 | static void writeInterface( const char *filename, glsldata_t data ) |
nkeynes@1130 | 337 | { |
nkeynes@1130 | 338 | FILE *f = fopen(filename, "wo"); |
nkeynes@1130 | 339 | if( f == NULL ) { |
nkeynes@1130 | 340 | fprintf( stderr, "Error: Unable to write interface file '%s': %s\n", filename, strerror(errno) ); |
nkeynes@1130 | 341 | exit(1); |
nkeynes@1130 | 342 | } |
nkeynes@1130 | 343 | |
nkeynes@1130 | 344 | writeHeader( f, data ); |
nkeynes@1130 | 345 | fprintf( f, "#ifndef lxdream_glsl_H\n#define lxdream_glsl_H 1\n\n" ); |
nkeynes@1130 | 346 | |
nkeynes@1130 | 347 | fprintf( f, "typedef enum {\n" ); |
nkeynes@1130 | 348 | const char *last_name = NULL; |
nkeynes@1130 | 349 | int count = 0; |
nkeynes@1130 | 350 | GList *shader_ptr; |
nkeynes@1130 | 351 | for( shader_ptr = data->shaders; shader_ptr != NULL; shader_ptr = shader_ptr->next ) { |
nkeynes@1130 | 352 | count++; |
nkeynes@1130 | 353 | shader_t shader = (shader_t)shader_ptr->data; |
nkeynes@1130 | 354 | fprintf( f, " %s,\n", shader->name ); |
nkeynes@1130 | 355 | last_name = shader->name; |
nkeynes@1130 | 356 | } |
nkeynes@1130 | 357 | fprintf( f, "} shader_id;\n\n" ); |
nkeynes@1130 | 358 | |
nkeynes@1130 | 359 | if( last_name == NULL ) |
nkeynes@1130 | 360 | last_name = "NULL"; |
nkeynes@1130 | 361 | fprintf( f, "#define GLSL_LAST_SHADER %s\n", last_name ); |
nkeynes@1130 | 362 | fprintf( f, "#define GLSL_NUM_SHADERS %d\n", count ); |
nkeynes@1130 | 363 | fprintf( f, "#define GLSL_NO_SHADER -1\n\n" ); |
nkeynes@1130 | 364 | fprintf( f, "#define GLSL_VERTEX_SHADER 1\n" ); |
nkeynes@1130 | 365 | fprintf( f, "#define GLSL_FRAGMENT_SHADER 2\n" ); |
nkeynes@1130 | 366 | |
nkeynes@1130 | 367 | count = 0; |
nkeynes@1130 | 368 | GList *program_ptr; |
nkeynes@1130 | 369 | for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) { |
nkeynes@1130 | 370 | count++; |
nkeynes@1130 | 371 | } |
nkeynes@1207 | 372 | fprintf( f, "#define GLSL_NUM_PROGRAMS %d\n", count ); |
nkeynes@1130 | 373 | |
nkeynes@1207 | 374 | for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) { |
nkeynes@1207 | 375 | program_t program = program_ptr->data; |
nkeynes@1207 | 376 | GList *var_ptr; |
nkeynes@1207 | 377 | fprintf( f, "void glsl_use_%s();\n", program->name ); |
nkeynes@1207 | 378 | for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) { |
nkeynes@1207 | 379 | variable_t var = var_ptr->data; |
nkeynes@1207 | 380 | if( var->uniform ) { |
nkeynes@1207 | 381 | fprintf( f, "void glsl_set_%s_%s(%s value); /* uniform %s %s */ \n", program->name, var->name, getCType(var->type,var->uniform), var->type, var->name ); |
nkeynes@1207 | 382 | } else { |
nkeynes@1208 | 383 | fprintf( f, "void glsl_set_%s_%s_pointer(%s ptr, GLint stride); /* attribute %s %s */ \n", program->name, var->name, getCType(var->type,var->uniform), var->type, var->name); |
nkeynes@1209 | 384 | if( strcmp(var->type,"vec4") == 0 ) { /* Special case */ |
nkeynes@1240 | 385 | fprintf( f, "void glsl_set_%s_%s_vec2_pointer(%s ptr, GLint stride); /* attribute %s %s */ \n", program->name, var->name, getCType(var->type,var->uniform), var->type, var->name); |
nkeynes@1209 | 386 | fprintf( f, "void glsl_set_%s_%s_vec3_pointer(%s ptr, GLint stride); /* attribute %s %s */ \n", program->name, var->name, getCType(var->type,var->uniform), var->type, var->name); |
nkeynes@1209 | 387 | } |
nkeynes@1207 | 388 | } |
nkeynes@1207 | 389 | } |
nkeynes@1207 | 390 | } |
nkeynes@1130 | 391 | |
nkeynes@1258 | 392 | fprintf( f, "void glsl_clear_shader();\n" ); |
nkeynes@1258 | 393 | |
nkeynes@1130 | 394 | fprintf( f, "#endif /* !lxdream_glsl_H */\n" ); |
nkeynes@1130 | 395 | |
nkeynes@1130 | 396 | fclose(f); |
nkeynes@1130 | 397 | } |
nkeynes@1130 | 398 | |
nkeynes@1130 | 399 | static void writeSource( const char *filename, glsldata_t data ) |
nkeynes@1130 | 400 | { |
nkeynes@1130 | 401 | FILE *f = fopen(filename, "wo"); |
nkeynes@1130 | 402 | if( f == NULL ) { |
nkeynes@1130 | 403 | fprintf( stderr, "Error: Unable to write interface file '%s': %s\n", filename, strerror(errno) ); |
nkeynes@1130 | 404 | exit(1); |
nkeynes@1130 | 405 | } |
nkeynes@1130 | 406 | |
nkeynes@1130 | 407 | writeHeader( f, data ); |
nkeynes@1130 | 408 | fprintf( f, "struct shader_def {\n int type;\n const char *source;\n};\n" ); |
nkeynes@1130 | 409 | |
nkeynes@1130 | 410 | fprintf( f, "const struct shader_def shader_source[] = {\n" ); |
nkeynes@1130 | 411 | GList *shader_ptr; |
nkeynes@1130 | 412 | for( shader_ptr = data->shaders; shader_ptr != NULL; shader_ptr = shader_ptr->next ) { |
nkeynes@1130 | 413 | shader_t shader = (shader_t)shader_ptr->data; |
nkeynes@1130 | 414 | fprintf( f, " {%s,\"", (shader->type == VERTEX_SHADER ? "GLSL_VERTEX_SHADER" : "GLSL_FRAGMENT_SHADER") ); |
nkeynes@1130 | 415 | writeCString( f, shader->body ); |
nkeynes@1130 | 416 | fprintf( f, "\"},\n" ); |
nkeynes@1130 | 417 | } |
nkeynes@1130 | 418 | fprintf( f, " {GLSL_NO_SHADER,NULL}};\n\n" ); |
nkeynes@1130 | 419 | |
nkeynes@1130 | 420 | fprintf( f, "const int program_list[][%d] = {\n", data->max_shaders+1 ); |
nkeynes@1130 | 421 | GList *program_ptr; |
nkeynes@1207 | 422 | GList *var_ptr; |
nkeynes@1130 | 423 | unsigned i; |
nkeynes@1130 | 424 | for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) { |
nkeynes@1130 | 425 | program_t program = (program_t)program_ptr->data; |
nkeynes@1130 | 426 | fprintf( f, " {" ); |
nkeynes@1130 | 427 | for( i=0; program->shader_names[i] != NULL; i++ ) { |
nkeynes@1130 | 428 | fprintf(f, "%s,", program->shader_names[i] ); |
nkeynes@1130 | 429 | } |
nkeynes@1130 | 430 | fprintf( f, "GLSL_NO_SHADER},\n" ); |
nkeynes@1130 | 431 | } |
nkeynes@1130 | 432 | fprintf( f, " {GLSL_NO_SHADER}};\n" ); |
nkeynes@1130 | 433 | |
nkeynes@1207 | 434 | /* per-program functions */ |
nkeynes@1207 | 435 | for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) { |
nkeynes@1207 | 436 | program_t program = program_ptr->data; |
nkeynes@1207 | 437 | fprintf( f, "\nstatic gl_program_t prog_%s_id;\n",program->name ); |
nkeynes@1207 | 438 | for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) { |
nkeynes@1207 | 439 | variable_t var = var_ptr->data; |
nkeynes@1207 | 440 | fprintf( f, "static GLint var_%s_%s_loc;\n", program->name, var->name); |
nkeynes@1207 | 441 | } |
nkeynes@1207 | 442 | |
nkeynes@1207 | 443 | } |
nkeynes@1207 | 444 | for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) { |
nkeynes@1207 | 445 | program_t program = program_ptr->data; |
nkeynes@1208 | 446 | fprintf( f, "\nstatic void glsl_cleanup_%s() {\n", program->name ); |
nkeynes@1208 | 447 | for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) { |
nkeynes@1208 | 448 | variable_t var = var_ptr->data; |
nkeynes@1208 | 449 | if( !var->uniform ) { |
nkeynes@1208 | 450 | fprintf( f, " glsl_disable_attrib(var_%s_%s_loc);\n", program->name, var->name ); |
nkeynes@1208 | 451 | } |
nkeynes@1208 | 452 | } |
nkeynes@1208 | 453 | fprintf( f, "}\n"); |
nkeynes@1208 | 454 | |
nkeynes@1208 | 455 | fprintf( f, "\nvoid glsl_use_%s() {\n", program->name ); |
nkeynes@1208 | 456 | fprintf( f, " glsl_use_program(prog_%s_id);\n", program->name ); |
nkeynes@1229 | 457 | fprintf( f, " glsl_set_cleanup_fn(glsl_cleanup_%s);\n", program->name ); |
nkeynes@1208 | 458 | for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) { |
nkeynes@1208 | 459 | variable_t var = var_ptr->data; |
nkeynes@1208 | 460 | if( !var->uniform ) { |
nkeynes@1208 | 461 | fprintf( f, " glsl_enable_attrib(var_%s_%s_loc);\n", program->name, var->name ); |
nkeynes@1208 | 462 | } |
nkeynes@1208 | 463 | } |
nkeynes@1208 | 464 | fprintf( f, "}\n"); |
nkeynes@1208 | 465 | |
nkeynes@1207 | 466 | |
nkeynes@1207 | 467 | for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) { |
nkeynes@1207 | 468 | variable_t var = var_ptr->data; |
nkeynes@1207 | 469 | if( var->uniform ) { |
nkeynes@1207 | 470 | fprintf( f, "void glsl_set_%s_%s(%s value){ /* uniform %s %s */ \n", program->name, var->name, getCType(var->type,var->uniform), var->type, var->name ); |
nkeynes@1207 | 471 | fprintf( f, " glsl_set_uniform_%s(var_%s_%s_loc,value);\n}\n", var->type, program->name, var->name ); |
nkeynes@1207 | 472 | } else { |
nkeynes@1207 | 473 | fprintf( f, "void glsl_set_%s_%s_pointer(%s ptr, GLsizei stride){ /* attribute %s %s */ \n", program->name, var->name, getCType(var->type,var->uniform), var->type, var->name); |
nkeynes@1207 | 474 | fprintf( f, " glsl_set_attrib_%s(var_%s_%s_loc,stride, ptr);\n}\n", var->type, program->name, var->name ); |
nkeynes@1209 | 475 | if( strcmp(var->type,"vec4") == 0 ) { /* Special case to load vec3 arrays into a vec4 */ |
nkeynes@1209 | 476 | fprintf( f, "void glsl_set_%s_%s_vec3_pointer(%s ptr, GLsizei stride){ /* attribute %s %s */ \n", program->name, var->name, getCType(var->type,var->uniform), var->type, var->name); |
nkeynes@1209 | 477 | fprintf( f, " glsl_set_attrib_vec3(var_%s_%s_loc,stride, ptr);\n}\n", program->name, var->name ); |
nkeynes@1240 | 478 | fprintf( f, "void glsl_set_%s_%s_vec2_pointer(%s ptr, GLsizei stride){ /* attribute %s %s */ \n", program->name, var->name, getCType(var->type,var->uniform), var->type, var->name); |
nkeynes@1240 | 479 | fprintf( f, " glsl_set_attrib_vec2(var_%s_%s_loc,stride, ptr);\n}\n", program->name, var->name ); |
nkeynes@1209 | 480 | } |
nkeynes@1207 | 481 | } |
nkeynes@1207 | 482 | } |
nkeynes@1207 | 483 | } |
nkeynes@1207 | 484 | |
nkeynes@1258 | 485 | fprintf( f, "\nvoid glsl_clear_shader() {\n" ); |
nkeynes@1258 | 486 | fprintf( f, " glsl_run_cleanup_fn();\n glsl_use_program(0);\n}\n" ); |
nkeynes@1258 | 487 | |
nkeynes@1207 | 488 | fprintf( f, "\nstatic void glsl_init_programs( gl_program_t *ids ) {\n" ); |
nkeynes@1207 | 489 | for( program_ptr = data->programs, i=0; program_ptr != NULL; program_ptr = program_ptr->next, i++ ) { |
nkeynes@1207 | 490 | program_t program = program_ptr->data; |
nkeynes@1207 | 491 | |
nkeynes@1207 | 492 | fprintf( f, " prog_%s_id = ids[%d];\n\n", program->name, i ); |
nkeynes@1207 | 493 | for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) { |
nkeynes@1207 | 494 | variable_t var = var_ptr->data; |
nkeynes@1207 | 495 | if( var->uniform ) { |
nkeynes@1207 | 496 | fprintf( f, " var_%s_%s_loc = glsl_get_uniform_location(prog_%s_id, \"%s\");\n", program->name, var->name, program->name, var->name ); |
nkeynes@1207 | 497 | } else { |
nkeynes@1207 | 498 | fprintf( f, " var_%s_%s_loc = glsl_get_attrib_location(prog_%s_id, \"%s\");\n", program->name, var->name, program->name, var->name ); |
nkeynes@1207 | 499 | } |
nkeynes@1207 | 500 | } |
nkeynes@1207 | 501 | } |
nkeynes@1258 | 502 | |
nkeynes@1207 | 503 | fprintf( f, "}\n" ); |
nkeynes@1207 | 504 | |
nkeynes@1130 | 505 | fclose(f); |
nkeynes@1130 | 506 | } |
nkeynes@1130 | 507 | |
nkeynes@1234 | 508 | static const char *makeExtension(const char *basename, const char *ext) |
nkeynes@1130 | 509 | { |
nkeynes@1130 | 510 | const char *oldext = strrchr(basename, '.'); |
nkeynes@1130 | 511 | if( oldext == NULL ) { |
nkeynes@1130 | 512 | return g_strdup_printf("%s%s", basename, ext); |
nkeynes@1130 | 513 | } else { |
nkeynes@1169 | 514 | return g_strdup_printf("%.*s%s", (int)(oldext-basename), basename, ext); |
nkeynes@405 | 515 | } |
nkeynes@405 | 516 | } |
nkeynes@405 | 517 | |
nkeynes@1235 | 518 | static char *option_list = "hi:I:D:U:o:"; |
nkeynes@1234 | 519 | static struct option long_option_list[] = { |
nkeynes@1234 | 520 | { "help", no_argument, NULL, 'h' }, |
nkeynes@1235 | 521 | { "interface", required_argument, NULL, 'i' }, |
nkeynes@1234 | 522 | { "output", required_argument, NULL, 'o' }, |
nkeynes@1234 | 523 | { NULL, 0, 0, 0 } }; |
nkeynes@1234 | 524 | |
nkeynes@1234 | 525 | static void usage() { |
nkeynes@1234 | 526 | fprintf( stderr, "Usage: genglsl <glsl-source-list> [-o output.def] [-i output.h]\n"); |
nkeynes@1234 | 527 | } |
nkeynes@405 | 528 | int main( int argc, char *argv[] ) |
nkeynes@405 | 529 | { |
nkeynes@1234 | 530 | const char *output_file = NULL; |
nkeynes@1234 | 531 | const char *iface_file = NULL; |
nkeynes@1235 | 532 | GList *cpp_opts = NULL; |
nkeynes@1234 | 533 | int opt; |
nkeynes@1234 | 534 | |
nkeynes@1234 | 535 | while( (opt = getopt_long( argc, argv, option_list, long_option_list, NULL )) != -1 ) { |
nkeynes@1234 | 536 | switch( opt ) { |
nkeynes@1234 | 537 | case 'h': |
nkeynes@1234 | 538 | usage(); |
nkeynes@1234 | 539 | exit(0); |
nkeynes@1234 | 540 | break; |
nkeynes@1235 | 541 | case 'D': case 'I': case 'U': |
nkeynes@1235 | 542 | cpp_opts = g_list_append(cpp_opts, g_strdup_printf( "-%c%s", opt, optarg )); |
nkeynes@1235 | 543 | break; |
nkeynes@1234 | 544 | case 'i': |
nkeynes@1234 | 545 | if( iface_file != NULL ) { |
nkeynes@1234 | 546 | fprintf( stderr, "Error: at most one interface file can be supplied\n" ); |
nkeynes@1234 | 547 | usage(); |
nkeynes@1234 | 548 | exit(1); |
nkeynes@1234 | 549 | } |
nkeynes@1234 | 550 | iface_file = optarg; |
nkeynes@1234 | 551 | break; |
nkeynes@1234 | 552 | case 'o': |
nkeynes@1234 | 553 | if( output_file != NULL ) { |
nkeynes@1234 | 554 | fprintf( stderr, "Error: at most one output file can be supplied\n" ); |
nkeynes@1234 | 555 | usage(); |
nkeynes@1234 | 556 | exit(1); |
nkeynes@1234 | 557 | } |
nkeynes@1234 | 558 | output_file = optarg; |
nkeynes@1234 | 559 | } |
nkeynes@1234 | 560 | } |
nkeynes@1234 | 561 | |
nkeynes@1234 | 562 | if( optind == argc ) { |
nkeynes@1234 | 563 | usage(); |
nkeynes@736 | 564 | exit(1); |
nkeynes@405 | 565 | } |
nkeynes@405 | 566 | |
nkeynes@1234 | 567 | if( output_file == NULL ) { |
nkeynes@1234 | 568 | output_file = makeExtension(argv[optind], ".def"); |
nkeynes@1234 | 569 | } |
nkeynes@1234 | 570 | if( iface_file == NULL ) { |
nkeynes@1234 | 571 | iface_file = makeExtension(output_file, ".h"); |
nkeynes@405 | 572 | } |
nkeynes@405 | 573 | |
nkeynes@1235 | 574 | atexit(cleanup_tempfiles); |
nkeynes@1234 | 575 | glsldata_t data = g_malloc0(sizeof(struct glsldata)); |
nkeynes@1234 | 576 | while( optind < argc ) { |
nkeynes@1235 | 577 | readInput(argv[optind++], cpp_opts, data); |
nkeynes@405 | 578 | } |
nkeynes@1234 | 579 | linkPrograms(data); |
nkeynes@405 | 580 | |
nkeynes@1234 | 581 | writeSource( output_file, data ); |
nkeynes@1234 | 582 | writeInterface( iface_file, data ); |
nkeynes@405 | 583 | return 0; |
nkeynes@405 | 584 | } |
.