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@1130 | 31 | #include <glib/glist.h>
|
nkeynes@1130 | 32 |
|
nkeynes@1130 | 33 | #define MAX_LINE 4096
|
nkeynes@1130 | 34 | #define DEF_ALLOC_SIZE 4096
|
nkeynes@1130 | 35 | #define MAX_SHADERS 128
|
nkeynes@1130 | 36 |
|
nkeynes@1130 | 37 | typedef enum {
|
nkeynes@1130 | 38 | VERTEX_SHADER = 0,
|
nkeynes@1130 | 39 | FRAGMENT_SHADER = 1
|
nkeynes@1130 | 40 | } shader_type_t;
|
nkeynes@1130 | 41 |
|
nkeynes@1207 | 42 | typedef struct variable {
|
nkeynes@1207 | 43 | gboolean uniform; /* TRUE = uniform, FALSE = attribute */
|
nkeynes@1207 | 44 | const char *name;
|
nkeynes@1207 | 45 | const char *type;
|
nkeynes@1207 | 46 | } *variable_t;
|
nkeynes@1207 | 47 |
|
nkeynes@1130 | 48 | typedef struct shader {
|
nkeynes@1130 | 49 | shader_type_t type;
|
nkeynes@1130 | 50 | const char *name;
|
nkeynes@1130 | 51 | char *body;
|
nkeynes@1207 | 52 | GList *variables;
|
nkeynes@1130 | 53 | } *shader_t;
|
nkeynes@1130 | 54 |
|
nkeynes@1130 | 55 | typedef struct program {
|
nkeynes@1130 | 56 | const char *name;
|
nkeynes@1130 | 57 | gchar **shader_names;
|
nkeynes@1207 | 58 | GList *shaders;
|
nkeynes@1207 | 59 | GList *variables;
|
nkeynes@1130 | 60 | } *program_t;
|
nkeynes@1130 | 61 |
|
nkeynes@1130 | 62 | typedef struct glsldata {
|
nkeynes@1130 | 63 | const char *filename;
|
nkeynes@1130 | 64 | unsigned max_shaders;
|
nkeynes@1130 | 65 | GList *shaders;
|
nkeynes@1130 | 66 | GList *programs;
|
nkeynes@1130 | 67 | } *glsldata_t;
|
nkeynes@1130 | 68 |
|
nkeynes@1207 | 69 | #define isident(c) (isalnum(c)||(c)=='_')
|
nkeynes@1207 | 70 |
|
nkeynes@1207 | 71 | static void parseVarDecl( shader_t shader, gboolean uniform, char *input )
|
nkeynes@1207 | 72 | {
|
nkeynes@1207 | 73 | unsigned i;
|
nkeynes@1207 | 74 | char *p = g_strstrip(input);
|
nkeynes@1207 | 75 | for( i=0; isident(p[i]); i++)
|
nkeynes@1207 | 76 | if( p[i] == 0 ) {
|
nkeynes@1207 | 77 | fprintf( stderr, "Error: unable to parse variable decl '%s'\n", p );
|
nkeynes@1207 | 78 | return; /* incomplete decl? */
|
nkeynes@1207 | 79 | }
|
nkeynes@1207 | 80 | char *type = g_strndup(p, i);
|
nkeynes@1207 | 81 | p = g_strstrip(input+i);
|
nkeynes@1207 | 82 | for( i=0; isident(p[i]); i++)
|
nkeynes@1207 | 83 | if( p[i] == 0 ) {
|
nkeynes@1207 | 84 | fprintf( stderr, "Error: unable to parse variable decl '%s'\n", p );
|
nkeynes@1207 | 85 | return; /* incomplete decl? */
|
nkeynes@1207 | 86 | }
|
nkeynes@1207 | 87 | char *name = g_strndup(p, i);
|
nkeynes@1207 | 88 | variable_t var = g_malloc0(sizeof(struct variable));
|
nkeynes@1207 | 89 | var->uniform = uniform;
|
nkeynes@1207 | 90 | var->type = type;
|
nkeynes@1207 | 91 | var->name = name;
|
nkeynes@1207 | 92 | shader->variables = g_list_append(shader->variables,var);
|
nkeynes@1207 | 93 | }
|
nkeynes@1207 | 94 |
|
nkeynes@1207 | 95 | static shader_t findShader( GList *shaders, const char *name )
|
nkeynes@1207 | 96 | {
|
nkeynes@1207 | 97 | GList *ptr = shaders;
|
nkeynes@1207 | 98 | while( ptr != NULL ) {
|
nkeynes@1207 | 99 | shader_t shader = ptr->data;
|
nkeynes@1207 | 100 | if( strcmp(shader->name, name) == 0 )
|
nkeynes@1207 | 101 | return shader;
|
nkeynes@1207 | 102 | ptr = ptr->next;
|
nkeynes@1207 | 103 | }
|
nkeynes@1207 | 104 | return NULL;
|
nkeynes@1207 | 105 | }
|
nkeynes@1207 | 106 |
|
nkeynes@1207 | 107 | static gboolean addProgramVariable( program_t program, variable_t variable )
|
nkeynes@1207 | 108 | {
|
nkeynes@1207 | 109 | GList *ptr = program->variables;
|
nkeynes@1207 | 110 | while( ptr != NULL ) {
|
nkeynes@1207 | 111 | variable_t varp = ptr->data;
|
nkeynes@1207 | 112 | if( strcmp(varp->name, variable->name) == 0 ) {
|
nkeynes@1207 | 113 | if( varp->uniform == variable->uniform && strcmp(varp->type, variable->type) == 0 )
|
nkeynes@1207 | 114 | return TRUE; /* All ok */
|
nkeynes@1207 | 115 | fprintf( stderr, "Error: Variable type mismatch on '%s'\n", variable->name );
|
nkeynes@1207 | 116 | return FALSE;
|
nkeynes@1207 | 117 | }
|
nkeynes@1207 | 118 | ptr = ptr->next;
|
nkeynes@1207 | 119 | }
|
nkeynes@1207 | 120 | program->variables = g_list_append(program->variables, variable);
|
nkeynes@1207 | 121 | return TRUE;
|
nkeynes@1207 | 122 | }
|
nkeynes@1207 | 123 |
|
nkeynes@1207 | 124 | static void linkPrograms( glsldata_t data )
|
nkeynes@1207 | 125 | {
|
nkeynes@1207 | 126 | GList *program_ptr = data->programs;
|
nkeynes@1207 | 127 | unsigned i;
|
nkeynes@1207 | 128 | while( program_ptr != NULL ) {
|
nkeynes@1207 | 129 | program_t program = program_ptr->data;
|
nkeynes@1207 | 130 | for( i=0; program->shader_names[i] != NULL; i++ ) {
|
nkeynes@1207 | 131 | shader_t shader = findShader(data->shaders, program->shader_names[i]);
|
nkeynes@1207 | 132 | if( shader == NULL ) {
|
nkeynes@1207 | 133 | fprintf( stderr, "Error: unable to resolve shader '%s'\n", program->shader_names[i] );\
|
nkeynes@1207 | 134 | } else {
|
nkeynes@1207 | 135 | GList *varptr = shader->variables;
|
nkeynes@1207 | 136 | while( varptr != NULL ) {
|
nkeynes@1207 | 137 | addProgramVariable(program, varptr->data);
|
nkeynes@1207 | 138 | varptr = varptr->next;
|
nkeynes@1207 | 139 | }
|
nkeynes@1207 | 140 | }
|
nkeynes@1207 | 141 | }
|
nkeynes@1207 | 142 | program_ptr = program_ptr->next;
|
nkeynes@1207 | 143 | }
|
nkeynes@1207 | 144 |
|
nkeynes@1207 | 145 | }
|
nkeynes@1207 | 146 |
|
nkeynes@1207 | 147 |
|
nkeynes@1234 | 148 | static void readInput( const char *filename, glsldata_t result )
|
nkeynes@1130 | 149 | {
|
nkeynes@1130 | 150 | char buf[MAX_LINE];
|
nkeynes@1130 | 151 | size_t current_size = 0, current_posn = 0;
|
nkeynes@1130 | 152 | unsigned i;
|
nkeynes@1130 | 153 |
|
nkeynes@1130 | 154 | FILE *f = fopen( filename, "ro" );
|
nkeynes@1130 | 155 | if( f == NULL ) {
|
nkeynes@1130 | 156 | fprintf( stderr, "Error: unable to open input file '%s': %s\n", filename, strerror(errno) );
|
nkeynes@1234 | 157 | exit(2);
|
nkeynes@1130 | 158 | }
|
nkeynes@1130 | 159 |
|
nkeynes@1130 | 160 | shader_t shader = NULL;
|
nkeynes@1234 | 161 | if( result->filename == NULL ) {
|
nkeynes@1234 | 162 | result->filename = g_strdup(filename);
|
nkeynes@1234 | 163 | } else {
|
nkeynes@1234 | 164 | const gchar *tmp = result->filename;
|
nkeynes@1234 | 165 | result->filename = g_strdup_printf("%s, %s", tmp, filename);
|
nkeynes@1234 | 166 | g_free((gchar *)tmp);
|
nkeynes@1234 | 167 | }
|
nkeynes@1130 | 168 |
|
nkeynes@1130 | 169 | while( fgets(buf, sizeof(buf), f) != NULL ) {
|
nkeynes@1130 | 170 | if( strlen(buf) == 0 )
|
nkeynes@1130 | 171 | continue;
|
nkeynes@1130 | 172 |
|
nkeynes@1130 | 173 | if( strncmp(buf, "#vertex ", 8) == 0 ) {
|
nkeynes@1207 | 174 | shader = g_malloc0(sizeof(struct shader));
|
nkeynes@1130 | 175 | assert( shader != NULL );
|
nkeynes@1130 | 176 | shader->type = VERTEX_SHADER;
|
nkeynes@1130 | 177 | shader->name = strdup(g_strstrip(buf+8));
|
nkeynes@1130 | 178 | shader->body = malloc(DEF_ALLOC_SIZE);
|
nkeynes@1130 | 179 | shader->body[0] = '\0';
|
nkeynes@1130 | 180 | current_size = DEF_ALLOC_SIZE;
|
nkeynes@1130 | 181 | current_posn = 0;
|
nkeynes@1130 | 182 | result->shaders = g_list_append(result->shaders, shader);
|
nkeynes@1130 | 183 | } else if( strncmp( buf, "#fragment ", 10 ) == 0 ) {
|
nkeynes@1207 | 184 | shader = g_malloc0(sizeof(struct shader));
|
nkeynes@1130 | 185 | assert( shader != NULL );
|
nkeynes@1130 | 186 | shader->type = FRAGMENT_SHADER;
|
nkeynes@1130 | 187 | shader->name = strdup(g_strstrip(buf+10));
|
nkeynes@1130 | 188 | shader->body = malloc(DEF_ALLOC_SIZE);
|
nkeynes@1130 | 189 | shader->body[0] = '\0';
|
nkeynes@1130 | 190 | current_size = DEF_ALLOC_SIZE;
|
nkeynes@1130 | 191 | current_posn = 0;
|
nkeynes@1130 | 192 | result->shaders = g_list_append(result->shaders, shader);
|
nkeynes@1130 | 193 | } else if( strncmp( buf, "#program ", 9 ) == 0 ) {
|
nkeynes@1130 | 194 | shader = NULL;
|
nkeynes@1207 | 195 | program_t program = g_malloc0(sizeof(struct program));
|
nkeynes@1130 | 196 | char *rest = buf+9;
|
nkeynes@1130 | 197 | char *equals = strchr(rest, '=');
|
nkeynes@1130 | 198 | if( equals == NULL ) {
|
nkeynes@1130 | 199 | fprintf( stderr, "Error: invalid program line %s\n", buf );
|
nkeynes@1130 | 200 | exit(2);
|
nkeynes@1130 | 201 | }
|
nkeynes@1130 | 202 | *equals = '\0';
|
nkeynes@1130 | 203 | program->name = g_strdup(g_strstrip(rest));
|
nkeynes@1130 | 204 | program->shader_names = g_strsplit_set(g_strstrip(equals+1), " \t\r,", 0);
|
nkeynes@1130 | 205 | result->programs = g_list_append(result->programs, program);
|
nkeynes@1130 | 206 | for(i=0;program->shader_names[i] != NULL; i++ );
|
nkeynes@1130 | 207 | if( i > result->max_shaders )
|
nkeynes@1130 | 208 | result->max_shaders = i;
|
nkeynes@1130 | 209 | } else if( shader != NULL ) {
|
nkeynes@1130 | 210 | size_t len = strlen(buf);
|
nkeynes@1130 | 211 | if( current_posn + len > current_size ) {
|
nkeynes@1130 | 212 | shader->body = realloc(shader->body, current_size*2);
|
nkeynes@1130 | 213 | assert( shader->body != NULL );
|
nkeynes@1130 | 214 | current_size *= 2;
|
nkeynes@1130 | 215 | }
|
nkeynes@1130 | 216 | strcpy( shader->body + current_posn, buf );
|
nkeynes@1130 | 217 | current_posn += len;
|
nkeynes@1207 | 218 | char *line = g_strstrip(buf);
|
nkeynes@1207 | 219 | if( strncmp( line, "uniform ", 8 ) == 0 ) {
|
nkeynes@1207 | 220 | parseVarDecl(shader, TRUE, line+8);
|
nkeynes@1207 | 221 | } else if( strncmp( line, "attribute ", 10 ) == 0 ) {
|
nkeynes@1207 | 222 | parseVarDecl(shader, FALSE, line+10);
|
nkeynes@1207 | 223 | }
|
nkeynes@1130 | 224 | }
|
nkeynes@1130 | 225 | }
|
nkeynes@1130 | 226 |
|
nkeynes@1130 | 227 | fclose(f);
|
nkeynes@1130 | 228 | }
|
nkeynes@405 | 229 |
|
nkeynes@405 | 230 | /**
|
nkeynes@405 | 231 | * Copy input to output, quoting " characters as we go.
|
nkeynes@405 | 232 | */
|
nkeynes@1130 | 233 | static void writeCString( FILE *out, const char *str )
|
nkeynes@405 | 234 | {
|
nkeynes@1130 | 235 | const char *p = str;
|
nkeynes@405 | 236 |
|
nkeynes@1130 | 237 | while( *p != 0 ) {
|
nkeynes@1130 | 238 | if( *p == '\"' ) {
|
nkeynes@736 | 239 | fputc( '\\', out );
|
nkeynes@1130 | 240 | } else if( *p == '\n' ) {
|
nkeynes@736 | 241 | fputs( "\\n\\", out );
|
nkeynes@736 | 242 | }
|
nkeynes@1130 | 243 | fputc( *p, out );
|
nkeynes@1130 | 244 | p++;
|
nkeynes@1130 | 245 | }
|
nkeynes@1130 | 246 | }
|
nkeynes@1130 | 247 |
|
nkeynes@1207 | 248 | static const char *sl_type_map[][3] = {
|
nkeynes@1207 | 249 | {"int", "int", "int *"},
|
nkeynes@1229 | 250 | {"float", "float", "float *"},
|
nkeynes@1207 | 251 | {"short", "short", "short *"},
|
nkeynes@1207 | 252 | {"sampler", "int", "int *"},
|
nkeynes@1207 | 253 | {"vec", "GLfloat *", "GLfloat *"},
|
nkeynes@1207 | 254 | {"mat", "GLfloat *", "GLfloat *"},
|
nkeynes@1207 | 255 | {NULL, NULL}
|
nkeynes@1207 | 256 | };
|
nkeynes@1207 | 257 |
|
nkeynes@1207 | 258 | static const char *getCType( const char *sl_type, gboolean isUniform ) {
|
nkeynes@1207 | 259 | for( unsigned i=0; sl_type_map[i][0] != NULL; i++ ) {
|
nkeynes@1207 | 260 | if( strncmp(sl_type_map[i][0], sl_type, strlen(sl_type_map[i][0])) == 0 ) {
|
nkeynes@1207 | 261 | if( isUniform ) {
|
nkeynes@1207 | 262 | return sl_type_map[i][1];
|
nkeynes@1207 | 263 | } else {
|
nkeynes@1207 | 264 | return sl_type_map[i][2];
|
nkeynes@1207 | 265 | }
|
nkeynes@1207 | 266 | }
|
nkeynes@1207 | 267 | }
|
nkeynes@1207 | 268 | return "void *";
|
nkeynes@1207 | 269 | }
|
nkeynes@1207 | 270 |
|
nkeynes@1130 | 271 | static void writeHeader( FILE *out, glsldata_t data )
|
nkeynes@1130 | 272 | {
|
nkeynes@1130 | 273 | fprintf( out, "/*\n * This file automatically generated by genglsl from %s\n */\n", data->filename );
|
nkeynes@1130 | 274 | }
|
nkeynes@1130 | 275 |
|
nkeynes@1130 | 276 | static void writeInterface( const char *filename, glsldata_t data )
|
nkeynes@1130 | 277 | {
|
nkeynes@1130 | 278 | FILE *f = fopen(filename, "wo");
|
nkeynes@1130 | 279 | if( f == NULL ) {
|
nkeynes@1130 | 280 | fprintf( stderr, "Error: Unable to write interface file '%s': %s\n", filename, strerror(errno) );
|
nkeynes@1130 | 281 | exit(1);
|
nkeynes@1130 | 282 | }
|
nkeynes@1130 | 283 |
|
nkeynes@1130 | 284 | writeHeader( f, data );
|
nkeynes@1130 | 285 | fprintf( f, "#ifndef lxdream_glsl_H\n#define lxdream_glsl_H 1\n\n" );
|
nkeynes@1130 | 286 |
|
nkeynes@1130 | 287 | fprintf( f, "typedef enum {\n" );
|
nkeynes@1130 | 288 | const char *last_name = NULL;
|
nkeynes@1130 | 289 | int count = 0;
|
nkeynes@1130 | 290 | GList *shader_ptr;
|
nkeynes@1130 | 291 | for( shader_ptr = data->shaders; shader_ptr != NULL; shader_ptr = shader_ptr->next ) {
|
nkeynes@1130 | 292 | count++;
|
nkeynes@1130 | 293 | shader_t shader = (shader_t)shader_ptr->data;
|
nkeynes@1130 | 294 | fprintf( f, " %s,\n", shader->name );
|
nkeynes@1130 | 295 | last_name = shader->name;
|
nkeynes@1130 | 296 | }
|
nkeynes@1130 | 297 | fprintf( f, "} shader_id;\n\n" );
|
nkeynes@1130 | 298 |
|
nkeynes@1130 | 299 | if( last_name == NULL )
|
nkeynes@1130 | 300 | last_name = "NULL";
|
nkeynes@1130 | 301 | fprintf( f, "#define GLSL_LAST_SHADER %s\n", last_name );
|
nkeynes@1130 | 302 | fprintf( f, "#define GLSL_NUM_SHADERS %d\n", count );
|
nkeynes@1130 | 303 | fprintf( f, "#define GLSL_NO_SHADER -1\n\n" );
|
nkeynes@1130 | 304 | fprintf( f, "#define GLSL_VERTEX_SHADER 1\n" );
|
nkeynes@1130 | 305 | fprintf( f, "#define GLSL_FRAGMENT_SHADER 2\n" );
|
nkeynes@1130 | 306 |
|
nkeynes@1130 | 307 | count = 0;
|
nkeynes@1130 | 308 | GList *program_ptr;
|
nkeynes@1130 | 309 | for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
|
nkeynes@1130 | 310 | count++;
|
nkeynes@1130 | 311 | }
|
nkeynes@1207 | 312 | fprintf( f, "#define GLSL_NUM_PROGRAMS %d\n", count );
|
nkeynes@1130 | 313 |
|
nkeynes@1207 | 314 | for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
|
nkeynes@1207 | 315 | program_t program = program_ptr->data;
|
nkeynes@1207 | 316 | GList *var_ptr;
|
nkeynes@1207 | 317 | fprintf( f, "void glsl_use_%s();\n", program->name );
|
nkeynes@1207 | 318 | for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
|
nkeynes@1207 | 319 | variable_t var = var_ptr->data;
|
nkeynes@1207 | 320 | if( var->uniform ) {
|
nkeynes@1207 | 321 | 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 | 322 | } else {
|
nkeynes@1208 | 323 | 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 | 324 | if( strcmp(var->type,"vec4") == 0 ) { /* Special case */
|
nkeynes@1209 | 325 | 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 | 326 | }
|
nkeynes@1207 | 327 | }
|
nkeynes@1207 | 328 | }
|
nkeynes@1207 | 329 | }
|
nkeynes@1130 | 330 |
|
nkeynes@1130 | 331 | fprintf( f, "#endif /* !lxdream_glsl_H */\n" );
|
nkeynes@1130 | 332 |
|
nkeynes@1130 | 333 | fclose(f);
|
nkeynes@1130 | 334 | }
|
nkeynes@1130 | 335 |
|
nkeynes@1130 | 336 | static void writeSource( 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, "struct shader_def {\n int type;\n const char *source;\n};\n" );
|
nkeynes@1130 | 346 |
|
nkeynes@1130 | 347 | fprintf( f, "const struct shader_def shader_source[] = {\n" );
|
nkeynes@1130 | 348 | GList *shader_ptr;
|
nkeynes@1130 | 349 | for( shader_ptr = data->shaders; shader_ptr != NULL; shader_ptr = shader_ptr->next ) {
|
nkeynes@1130 | 350 | shader_t shader = (shader_t)shader_ptr->data;
|
nkeynes@1130 | 351 | fprintf( f, " {%s,\"", (shader->type == VERTEX_SHADER ? "GLSL_VERTEX_SHADER" : "GLSL_FRAGMENT_SHADER") );
|
nkeynes@1130 | 352 | writeCString( f, shader->body );
|
nkeynes@1130 | 353 | fprintf( f, "\"},\n" );
|
nkeynes@1130 | 354 | }
|
nkeynes@1130 | 355 | fprintf( f, " {GLSL_NO_SHADER,NULL}};\n\n" );
|
nkeynes@1130 | 356 |
|
nkeynes@1130 | 357 | fprintf( f, "const int program_list[][%d] = {\n", data->max_shaders+1 );
|
nkeynes@1130 | 358 | GList *program_ptr;
|
nkeynes@1207 | 359 | GList *var_ptr;
|
nkeynes@1130 | 360 | unsigned i;
|
nkeynes@1130 | 361 | for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
|
nkeynes@1130 | 362 | program_t program = (program_t)program_ptr->data;
|
nkeynes@1130 | 363 | fprintf( f, " {" );
|
nkeynes@1130 | 364 | for( i=0; program->shader_names[i] != NULL; i++ ) {
|
nkeynes@1130 | 365 | fprintf(f, "%s,", program->shader_names[i] );
|
nkeynes@1130 | 366 | }
|
nkeynes@1130 | 367 | fprintf( f, "GLSL_NO_SHADER},\n" );
|
nkeynes@1130 | 368 | }
|
nkeynes@1130 | 369 | fprintf( f, " {GLSL_NO_SHADER}};\n" );
|
nkeynes@1130 | 370 |
|
nkeynes@1207 | 371 | /* per-program functions */
|
nkeynes@1207 | 372 | for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
|
nkeynes@1207 | 373 | program_t program = program_ptr->data;
|
nkeynes@1207 | 374 | fprintf( f, "\nstatic gl_program_t prog_%s_id;\n",program->name );
|
nkeynes@1207 | 375 | for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
|
nkeynes@1207 | 376 | variable_t var = var_ptr->data;
|
nkeynes@1207 | 377 | fprintf( f, "static GLint var_%s_%s_loc;\n", program->name, var->name);
|
nkeynes@1207 | 378 | }
|
nkeynes@1207 | 379 |
|
nkeynes@1207 | 380 | }
|
nkeynes@1207 | 381 | for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
|
nkeynes@1207 | 382 | program_t program = program_ptr->data;
|
nkeynes@1208 | 383 | fprintf( f, "\nstatic void glsl_cleanup_%s() {\n", program->name );
|
nkeynes@1208 | 384 | for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
|
nkeynes@1208 | 385 | variable_t var = var_ptr->data;
|
nkeynes@1208 | 386 | if( !var->uniform ) {
|
nkeynes@1208 | 387 | fprintf( f, " glsl_disable_attrib(var_%s_%s_loc);\n", program->name, var->name );
|
nkeynes@1208 | 388 | }
|
nkeynes@1208 | 389 | }
|
nkeynes@1208 | 390 | fprintf( f, "}\n");
|
nkeynes@1208 | 391 |
|
nkeynes@1208 | 392 | fprintf( f, "\nvoid glsl_use_%s() {\n", program->name );
|
nkeynes@1208 | 393 | fprintf( f, " glsl_use_program(prog_%s_id);\n", program->name );
|
nkeynes@1229 | 394 | fprintf( f, " glsl_set_cleanup_fn(glsl_cleanup_%s);\n", program->name );
|
nkeynes@1208 | 395 | for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
|
nkeynes@1208 | 396 | variable_t var = var_ptr->data;
|
nkeynes@1208 | 397 | if( !var->uniform ) {
|
nkeynes@1208 | 398 | fprintf( f, " glsl_enable_attrib(var_%s_%s_loc);\n", program->name, var->name );
|
nkeynes@1208 | 399 | }
|
nkeynes@1208 | 400 | }
|
nkeynes@1208 | 401 | fprintf( f, "}\n");
|
nkeynes@1208 | 402 |
|
nkeynes@1207 | 403 |
|
nkeynes@1207 | 404 | for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
|
nkeynes@1207 | 405 | variable_t var = var_ptr->data;
|
nkeynes@1207 | 406 | if( var->uniform ) {
|
nkeynes@1207 | 407 | 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 | 408 | fprintf( f, " glsl_set_uniform_%s(var_%s_%s_loc,value);\n}\n", var->type, program->name, var->name );
|
nkeynes@1207 | 409 | } else {
|
nkeynes@1207 | 410 | 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 | 411 | fprintf( f, " glsl_set_attrib_%s(var_%s_%s_loc,stride, ptr);\n}\n", var->type, program->name, var->name );
|
nkeynes@1209 | 412 | if( strcmp(var->type,"vec4") == 0 ) { /* Special case to load vec3 arrays into a vec4 */
|
nkeynes@1209 | 413 | 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 | 414 | fprintf( f, " glsl_set_attrib_vec3(var_%s_%s_loc,stride, ptr);\n}\n", program->name, var->name );
|
nkeynes@1209 | 415 | }
|
nkeynes@1207 | 416 | }
|
nkeynes@1207 | 417 | }
|
nkeynes@1207 | 418 | }
|
nkeynes@1207 | 419 |
|
nkeynes@1207 | 420 | fprintf( f, "\nstatic void glsl_init_programs( gl_program_t *ids ) {\n" );
|
nkeynes@1207 | 421 | for( program_ptr = data->programs, i=0; program_ptr != NULL; program_ptr = program_ptr->next, i++ ) {
|
nkeynes@1207 | 422 | program_t program = program_ptr->data;
|
nkeynes@1207 | 423 |
|
nkeynes@1207 | 424 | fprintf( f, " prog_%s_id = ids[%d];\n\n", program->name, i );
|
nkeynes@1207 | 425 | for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
|
nkeynes@1207 | 426 | variable_t var = var_ptr->data;
|
nkeynes@1207 | 427 | if( var->uniform ) {
|
nkeynes@1207 | 428 | 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 | 429 | } else {
|
nkeynes@1207 | 430 | 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 | 431 | }
|
nkeynes@1207 | 432 | }
|
nkeynes@1207 | 433 | }
|
nkeynes@1207 | 434 | fprintf( f, "}\n" );
|
nkeynes@1207 | 435 |
|
nkeynes@1130 | 436 | fclose(f);
|
nkeynes@1130 | 437 | }
|
nkeynes@1130 | 438 |
|
nkeynes@1234 | 439 | static const char *makeExtension(const char *basename, const char *ext)
|
nkeynes@1130 | 440 | {
|
nkeynes@1130 | 441 | const char *oldext = strrchr(basename, '.');
|
nkeynes@1130 | 442 | if( oldext == NULL ) {
|
nkeynes@1130 | 443 | return g_strdup_printf("%s%s", basename, ext);
|
nkeynes@1130 | 444 | } else {
|
nkeynes@1169 | 445 | return g_strdup_printf("%.*s%s", (int)(oldext-basename), basename, ext);
|
nkeynes@405 | 446 | }
|
nkeynes@405 | 447 | }
|
nkeynes@405 | 448 |
|
nkeynes@1234 | 449 | static char *option_list = "hi:o:";
|
nkeynes@1234 | 450 | static struct option long_option_list[] = {
|
nkeynes@1234 | 451 | { "help", no_argument, NULL, 'h' },
|
nkeynes@1234 | 452 | { "interface", required_argument, 'i' },
|
nkeynes@1234 | 453 | { "output", required_argument, NULL, 'o' },
|
nkeynes@1234 | 454 | { NULL, 0, 0, 0 } };
|
nkeynes@1234 | 455 |
|
nkeynes@1234 | 456 | static void usage() {
|
nkeynes@1234 | 457 | fprintf( stderr, "Usage: genglsl <glsl-source-list> [-o output.def] [-i output.h]\n");
|
nkeynes@1234 | 458 | }
|
nkeynes@405 | 459 | int main( int argc, char *argv[] )
|
nkeynes@405 | 460 | {
|
nkeynes@1234 | 461 | const char *output_file = NULL;
|
nkeynes@1234 | 462 | const char *iface_file = NULL;
|
nkeynes@1234 | 463 | int opt;
|
nkeynes@1234 | 464 |
|
nkeynes@1234 | 465 | while( (opt = getopt_long( argc, argv, option_list, long_option_list, NULL )) != -1 ) {
|
nkeynes@1234 | 466 | switch( opt ) {
|
nkeynes@1234 | 467 | case 'h':
|
nkeynes@1234 | 468 | usage();
|
nkeynes@1234 | 469 | exit(0);
|
nkeynes@1234 | 470 | break;
|
nkeynes@1234 | 471 | case 'i':
|
nkeynes@1234 | 472 | if( iface_file != NULL ) {
|
nkeynes@1234 | 473 | fprintf( stderr, "Error: at most one interface file can be supplied\n" );
|
nkeynes@1234 | 474 | usage();
|
nkeynes@1234 | 475 | exit(1);
|
nkeynes@1234 | 476 | }
|
nkeynes@1234 | 477 | iface_file = optarg;
|
nkeynes@1234 | 478 | break;
|
nkeynes@1234 | 479 | case 'o':
|
nkeynes@1234 | 480 | if( output_file != NULL ) {
|
nkeynes@1234 | 481 | fprintf( stderr, "Error: at most one output file can be supplied\n" );
|
nkeynes@1234 | 482 | usage();
|
nkeynes@1234 | 483 | exit(1);
|
nkeynes@1234 | 484 | }
|
nkeynes@1234 | 485 | output_file = optarg;
|
nkeynes@1234 | 486 | }
|
nkeynes@1234 | 487 | }
|
nkeynes@1234 | 488 |
|
nkeynes@1234 | 489 | if( optind == argc ) {
|
nkeynes@1234 | 490 | usage();
|
nkeynes@736 | 491 | exit(1);
|
nkeynes@405 | 492 | }
|
nkeynes@405 | 493 |
|
nkeynes@1234 | 494 | if( output_file == NULL ) {
|
nkeynes@1234 | 495 | output_file = makeExtension(argv[optind], ".def");
|
nkeynes@1234 | 496 | }
|
nkeynes@1234 | 497 | if( iface_file == NULL ) {
|
nkeynes@1234 | 498 | iface_file = makeExtension(output_file, ".h");
|
nkeynes@405 | 499 | }
|
nkeynes@405 | 500 |
|
nkeynes@1234 | 501 | glsldata_t data = g_malloc0(sizeof(struct glsldata));
|
nkeynes@1234 | 502 | while( optind < argc ) {
|
nkeynes@1234 | 503 | readInput(argv[optind++], data);
|
nkeynes@405 | 504 | }
|
nkeynes@1234 | 505 | linkPrograms(data);
|
nkeynes@405 | 506 |
|
nkeynes@1234 | 507 | writeSource( output_file, data );
|
nkeynes@1234 | 508 | writeInterface( iface_file, data );
|
nkeynes@405 | 509 | return 0;
|
nkeynes@405 | 510 | }
|