<html>
<body>
  <div id="body" style="background-color:#ffffff;" >
<table cellspacing="0" cellpadding="0" border="0" rules="cols">
<tr class="head" style="border-bottom-width:1px;border-bottom-style:solid;" ><td class="headtd" style="padding:0;padding-top:.2em;" colspan="4">Commit in <b><tt>lxdream/src</tt></b></td></tr>
<tr><td><tt>pvr2/<a href="#file1">gl_sl.c</a></tt></td><td id="added" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ddffdd;" align="right">+31</td><td id="removed" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ffdddd;" align="right">-73</td><td class="headtd2" style="padding-left:.3em;padding-right:.3em;" nowrap="nowrap">a9b41bcb8410 -> f7ca985659c6</td></tr>
<tr class="alt" style=";" ><td><tt>    /<a href="#file2">glrender.c</a></tt></td><td id="addedalt" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ccf7cc;" align="right">+5</td><td id="removed" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ffdddd;" align="right">-4</td><td class="headtd2" style="padding-left:.3em;padding-right:.3em;" nowrap="nowrap">a9b41bcb8410 -> f7ca985659c6</td></tr>
<tr><td><tt>    /<a href="#file3">glutil.h</a></tt></td><td id="added" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ddffdd;" align="right">+5</td><td id="removed" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ffdddd;" align="right">-6</td><td class="headtd2" style="padding-left:.3em;padding-right:.3em;" nowrap="nowrap">a9b41bcb8410 -> f7ca985659c6</td></tr>
<tr class="alt" style=";" ><td><tt>    /<a href="#file4">shaders.glsl</a></tt></td><td id="addedalt" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ccf7cc;" align="right">+1</td><td id="removed" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ffdddd;" align="right">-1</td><td class="headtd2" style="padding-left:.3em;padding-right:.3em;" nowrap="nowrap">a9b41bcb8410 -> f7ca985659c6</td></tr>
<tr><td><tt>tools/<a href="#file5">genglsl.c</a></tt></td><td id="added" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ddffdd;" align="right">+179</td><td id="removed" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ffdddd;" align="right">-21</td><td class="headtd2" style="padding-left:.3em;padding-right:.3em;" nowrap="nowrap">a9b41bcb8410 -> f7ca985659c6</td></tr>
<tr><td></td><td id="added" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ddffdd;" align="right">+221</td><td id="removed" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ffdddd;" align="right">-105</td><td></td></tr>
</table>
<small id="info" style="color: #888888;" >5 modified files</small><br />
<pre class="comment" style="white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;white-space:pre-wrap;word-wrap:break-word;padding:4px;border:1px dashed #000000;background-color:#ffffdd;" >
Gen helper functions for uniform + attribute variables, along with the main
program use, to provide a more usable interface to the shaders
</pre>
<hr /><a name="file1" /><div class="file" style="border:1px solid #eeeeee;margin-top:1em;margin-bottom:1em;" >
<span class="pathname" style="font-family:monospace; float:right;" >lxdream/src/pvr2</span><br />
<div class="fileheader" style="margin-bottom:.5em;" ><big><b>gl_sl.c</b></big> <small id="info" style="color: #888888;" >a9b41bcb8410 -> f7ca985659c6</small></div>
<pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >--- lxdream/src/pvr2/gl_sl.c
+++ lxdream/src/pvr2/gl_sl.c
@@ -21,6 +21,7 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > #include "lxdream.h"
 #include "display.h"
 #include "pvr2/glutil.h"
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+#include "pvr2/shaders.h"
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > 
 #define MAX_ERROR_BUF 4096
 #define INVALID_SHADER 0
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -151,25 +152,22 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     glDeleteObjectARB(program);
 }
 
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-static inline GLint glsl_get_uniform_location<span id="removedchars" style="background-color:#ff9999;font-weight:bolder;" >_prim</span>(gl_program_t program, const char *name)
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+static inline GLint glsl_get_uniform_location(gl_program_t program, const char *name)
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > {
     return glGetUniformLocationARB(program, name);
 }
 
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-static inline GLint glsl_get_attrib_location<span id="removedchars" style="background-color:#ff9999;font-weight:bolder;" >_prim</span>(gl_program_t program, const char *name)
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+static inline GLint glsl_get_attrib_location(gl_program_t program, const char *name)
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > {
     return glGetAttribLocationARB(program, name);
 }
 
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-static inline void glsl_set_uniform_int_prim(GLint location, GLint value)
-{
-    glUniform1iARB(location,value);
-}
-
-static inline void glsl_set_uniform_mat4_prim(GLint location, GLfloat *value)
-{
-    glUniformMatrix4fvARB(location, 1, GL_FALSE, value);
-}
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+#define glsl_set_uniform_sampler1D(id,v) glUniform1iARB(id,v)
+#define glsl_set_uniform_sampler2D(id,v) glUniform1iARB(id,v)
+#define glsl_set_uniform_vec4(id,v) glUniform4fvARB(id,1,v)
+#define glsl_set_uniform_mat4(id,v) glUniformMatrix4fvARB(id,1,GL_FALSE,v)
+#define glsl_set_attrib_vec3(id,stride,v) glVertexAttribPointerARB(id, 3, GL_FLOAT, GL_FALSE, stride, v)
+#define glsl_set_attrib_vec4(id,stride,v) glVertexAttribPointerARB(id, 4, GL_FLOAT, GL_FALSE, stride, v)
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > 
 #elif HAVE_OPENGL_SHADER
 
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -279,24 +277,23 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     glDeleteProgram(program);
 }
 
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-static inline GLint glsl_get_uniform_location<span id="removedchars" style="background-color:#ff9999;font-weight:bolder;" >_prim</span>(gl_program_t program, const char *name)
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+static inline GLint glsl_get_uniform_location(gl_program_t program, const char *name)
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > {
     return glGetUniformLocation(program, name);
 }
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-static inline void glsl_set_uniform_int_prim(GLint location, GLint value)
-{
-    glUniform1i(location, value);
-}
-
-static inline void glsl_set_uniform_mat4_prim(GLint location, GLfloat *value)
-{
-    glUniformMatrix4fv(location, 1, GL_TRUE, value);
-}
-
-static inline GLint glsl_get_attrib_location_prim(gl_program_t program, const char *name)
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+static inline GLint glsl_get_attrib_location(gl_program_t program, const char *name)
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > {
     return glGetAttribLocation(program, name);
 }
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+
+#define glsl_set_uniform_sampler1D(id,v) glUniform1i(id,v)
+#define glsl_set_uniform_sampler2D(id,v) glUniform1i(id,v)
+#define glsl_set_uniform_vec4(id,v) glUniform4fv(id,1,v)
+#define glsl_set_uniform_mat4(id,v) glUniformMatrix4fv(id,1,GL_FALSE,v)
+#define glsl_set_attrib_vec3(id,stride,v) glVertexAttribPointer(id, 3, GL_FLOAT, GL_FALSE, stride, v)
+#define glsl_set_attrib_vec4(id,stride,v) glVertexAttribPointer(id, 4, GL_FLOAT, GL_FALSE, stride, v)
+
+
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > #else
 gboolean glsl_is_supported()
 {
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -335,23 +332,23 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > {
 }
 
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-static inline GLint glsl_get_uniform_location<span id="removedchars" style="background-color:#ff9999;font-weight:bolder;" >_prim</span>(gl_program_t program, const char *name)
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+static inline GLint glsl_get_uniform_location(gl_program_t program, const char *name)
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > {
     return 0;
 }
 
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-static inline void glsl_set_uniform_int_prim(GLint location, GLint value)
-{
-}
-
-static inline void glsl_set_uniform_mat4_prim(GLint location, GLfloat *value)
-{
-}
-
-static inline GLint glsl_get_attrib_location_prim(gl_program_t program, const char *name)
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+static inline GLint glsl_get_attrib_location(gl_program_t program, const char *name)
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > {
     return 0;
 }
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+
+#define glsl_set_uniform_sampler2D(id,v)
+#define glsl_set_uniform_vec4(id,v)
+#define glsl_set_uniform_mat4(id,v)
+#define glsl_set_attrib_vec3(id,stride,v)
+#define glsl_set_attrib_vec4(id,stride,v)
+
+
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > #endif
 
 /****************************************************************************/
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -429,6 +426,7 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >         return FALSE;
     }
     
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+    glsl_init_programs(program_array);
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     glsl_use_program(0);
     return TRUE;
 }
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -444,46 +442,6 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     }
 }
 
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-gboolean glsl_set_shader(unsigned i)
-{
-    assert( i >= 0 && i <= GLSL_LAST_PROGRAM );
-
-    if( program_array[i] != INVALID_PROGRAM ) {
-        glsl_use_program(program_array[i]);
-        return TRUE;
-    } else {
-        return FALSE;
-    }
-}
-
-GLint glsl_get_uniform_location( unsigned program, const char *name )
-{
-    assert( program >= 0 && program <= GLSL_LAST_PROGRAM );
-
-    return glsl_get_uniform_location_prim(program_array[program], name);
-}
-
-GLint glsl_get_attrib_location( unsigned program, const char *name )
-{
-    assert( program >= 0 && program <= GLSL_LAST_PROGRAM );
-
-    return glsl_get_attrib_location_prim(program_array[program], name);
-}
-
-void glsl_set_uniform_int( unsigned program, const char *name, GLint value )
-{
-    assert( program >= 0 && program <= GLSL_LAST_PROGRAM );
-    GLint location = glsl_get_uniform_location_prim(program_array[program], name);
-    glsl_set_uniform_int_prim(location, value);
-}
-
-void glsl_set_uniform_mat4( unsigned program, const char *name, GLfloat *value )
-{
-    assert( program >= 0 && program <= GLSL_LAST_PROGRAM );
-    GLint location = glsl_get_uniform_location_prim(program_array[program], name);
-    glsl_set_uniform_mat4_prim(location, value);
-}
-
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > void glsl_clear_shader()
 {
     glsl_use_program(0);
</pre></div>
<hr /><a name="file2" /><div class="file" style="border:1px solid #eeeeee;margin-top:1em;margin-bottom:1em;" >
<span class="pathname" style="font-family:monospace; float:right;" >lxdream/src/pvr2</span><br />
<div class="fileheader" style="margin-bottom:.5em;" ><big><b>glrender.c</b></big> <small id="info" style="color: #888888;" >a9b41bcb8410 -> f7ca985659c6</small></div>
<pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >--- lxdream/src/pvr2/glrender.c
+++ lxdream/src/pvr2/glrender.c
@@ -24,6 +24,7 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > #include "pvr2/glutil.h"
 #include "pvr2/scene.h"
 #include "pvr2/tileiter.h"
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+#include "pvr2/shaders.h"
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > 
 #ifdef APPLE_BUILD
 #include "OpenGL/CGLCurrent.h"
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -160,9 +161,9 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     glFogf(GL_FOG_END, 1.0);
 
     if( have_shaders ) {
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-        glsl_set_shader(DEFAULT_PROGRAM);
-        glsl_set_uniform_int(DEFAULT_PROGRAM, "primary_texture", 0);
-        glsl_set_uniform_int(DEFAULT_PROGRAM, "palette_texture", 1);
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+        glsl_use_pvr2_shader();
+        glsl_set_pvr2_shader_primary_texture(0);
+        glsl_set_pvr2_shader_palette_texture(1);
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >         glsl_clear_shader();
     }
 }
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -460,7 +461,7 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     glSecondaryColorPointerEXT(3, GL_FLOAT, sizeof(struct vertex_struct), pvr2_scene.vertex_array[0].offset_rgba );
     glFogCoordPointerEXT(GL_FLOAT, sizeof(struct vertex_struct), &pvr2_scene.vertex_array[0].offset_rgba[3] );
     /* Turn on the shaders (if available) */
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-    glsl_set_shader(DEFAULT_PROGRAM);
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+    glsl_use_pvr2_shader();
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > 
     /* Render the background */
     gl_render_bkgnd( pvr2_scene.bkgnd_poly );
</pre></div>
<hr /><a name="file3" /><div class="file" style="border:1px solid #eeeeee;margin-top:1em;margin-bottom:1em;" >
<span class="pathname" style="font-family:monospace; float:right;" >lxdream/src/pvr2</span><br />
<div class="fileheader" style="margin-bottom:.5em;" ><big><b>glutil.h</b></big> <small id="info" style="color: #888888;" >a9b41bcb8410 -> f7ca985659c6</small></div>
<pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >--- lxdream/src/pvr2/glutil.h
+++ lxdream/src/pvr2/glutil.h
@@ -21,7 +21,6 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > 
 #include <stdio.h>
 #include "display.h"
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-#include "pvr2/shaders.h"
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > 
 #ifdef __cplusplus
 extern "C" {
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -56,17 +55,17 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > gboolean isGLMultitextureSupported();
 gboolean isGLMirroredTextureSupported();
 
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+/****** Extension variant wrangling *****/
+
+
+
+
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > /****** Shader handling (gl_sl.c) *****/
 gboolean glsl_is_supported(void);
 const char *glsl_get_version(void);
 gboolean glsl_load_shaders( );
 void glsl_unload_shaders(void);
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-gboolean glsl_set_shader( unsigned program_id );
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > void glsl_clear_shader();
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-GLint glsl_get_uniform_location( unsigned program, const char *name );
-void glsl_set_uniform_int( unsigned program, const char *name, GLint value );
-void glsl_set_uniform_mat4( unsigned program, const char *name, GLfloat *value );
-GLint glsl_get_attrib_location(unsigned program, const char *name);
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > 
 /* Convenience formatting function for driver use */
 void fprint_extensions( FILE *out, const char *extensions );
</pre></div>
<hr /><a name="file4" /><div class="file" style="border:1px solid #eeeeee;margin-top:1em;margin-bottom:1em;" >
<span class="pathname" style="font-family:monospace; float:right;" >lxdream/src/pvr2</span><br />
<div class="fileheader" style="margin-bottom:.5em;" ><big><b>shaders.glsl</b></big> <small id="info" style="color: #888888;" >a9b41bcb8410 -> f7ca985659c6</small></div>
<pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >--- lxdream/src/pvr2/shaders.glsl
+++ lxdream/src/pvr2/shaders.glsl
@@ -105,5 +105,5 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >      gl_FragDepth = gl_FragCoord.z;
 }
 
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-#program <span id="removedchars" style="background-color:#ff9999;font-weight:bolder;" >DEFAULT_PROGRAM</span> = DEFAULT_VERTEX_SHADER DEFAULT_FRAGMENT_SHADER
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+#program <span id="addedchars" style="background-color:#99ff99;font-weight:bolder;" >pvr2_shader</span> = DEFAULT_VERTEX_SHADER DEFAULT_FRAGMENT_SHADER
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > 
</pre></div>
<hr /><a name="file5" /><div class="file" style="border:1px solid #eeeeee;margin-top:1em;margin-bottom:1em;" >
<span class="pathname" style="font-family:monospace; float:right;" >lxdream/src/tools</span><br />
<div class="fileheader" style="margin-bottom:.5em;" ><big><b>genglsl.c</b></big> <small id="info" style="color: #888888;" >a9b41bcb8410 -> f7ca985659c6</small></div>
<pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >--- lxdream/src/tools/genglsl.c
+++ lxdream/src/tools/genglsl.c
@@ -21,6 +21,7 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >  */
 
 #include <assert.h>
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+#include <ctype.h>
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -37,15 +38,24 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     FRAGMENT_SHADER = 1
 } shader_type_t;
 
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+typedef struct variable {
+    gboolean uniform; /* TRUE = uniform, FALSE = attribute */
+    const char *name;
+    const char *type;
+} *variable_t;
+
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > typedef struct shader {
     shader_type_t type;
     const char *name;
     char *body;
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+    GList *variables;
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > } *shader_t;
 
 typedef struct program {
     const char *name;
     gchar **shader_names;
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+    GList *shaders;
+    GList *variables;
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > } *program_t;
 
 typedef struct glsldata {
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -55,6 +65,85 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     GList *programs;
 } *glsldata_t;
 
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+#define isident(c) (isalnum(c)||(c)=='_')
+
+static void parseVarDecl( shader_t shader, gboolean uniform, char *input )
+{
+    unsigned i;
+    char *p = g_strstrip(input);
+    for( i=0; isident(p[i]); i++)
+    if( p[i] == 0 ) {
+        fprintf( stderr, "Error: unable to parse variable decl '%s'\n", p );
+        return; /* incomplete decl? */
+    }
+    char *type = g_strndup(p, i);
+    p = g_strstrip(input+i);
+    for( i=0; isident(p[i]); i++)
+    if( p[i] == 0 ) {
+        fprintf( stderr, "Error: unable to parse variable decl '%s'\n", p );
+        return; /* incomplete decl? */
+    }
+    char *name = g_strndup(p, i);
+    variable_t var = g_malloc0(sizeof(struct variable));
+    var->uniform = uniform;
+    var->type = type;
+    var->name = name;
+    shader->variables = g_list_append(shader->variables,var);
+}
+
+static shader_t findShader( GList *shaders, const char *name )
+{
+    GList *ptr = shaders;
+    while( ptr != NULL ) {
+        shader_t shader = ptr->data;
+        if( strcmp(shader->name, name) == 0 )
+            return shader;
+        ptr = ptr->next;
+    }
+    return NULL;
+}
+
+static gboolean addProgramVariable( program_t program, variable_t variable )
+{
+    GList *ptr = program->variables;
+    while( ptr != NULL ) {
+        variable_t varp = ptr->data;
+        if( strcmp(varp->name, variable->name) == 0 ) {
+            if( varp->uniform == variable->uniform && strcmp(varp->type, variable->type) == 0 )
+                return TRUE; /* All ok */
+            fprintf( stderr, "Error: Variable type mismatch on '%s'\n", variable->name );
+            return FALSE;
+        }
+        ptr = ptr->next;
+    }
+    program->variables = g_list_append(program->variables, variable);
+    return TRUE;
+}
+
+static void linkPrograms( glsldata_t data )
+{
+    GList *program_ptr = data->programs;
+    unsigned i;
+    while( program_ptr != NULL ) {
+        program_t program = program_ptr->data;
+        for( i=0; program->shader_names[i] != NULL; i++ ) {
+            shader_t shader = findShader(data->shaders, program->shader_names[i]);
+            if( shader == NULL ) {
+                fprintf( stderr, "Error: unable to resolve shader '%s'\n", program->shader_names[i] );\
+            } else {
+                GList *varptr = shader->variables;
+                while( varptr != NULL ) {
+                    addProgramVariable(program, varptr->data);
+                    varptr = varptr->next;
+                }
+            }
+        }
+        program_ptr = program_ptr->next;
+    }
+
+}
+
+
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > static struct glsldata *readInput( const char *filename )
 {
     char buf[MAX_LINE];
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -68,19 +157,16 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     }
 
     shader_t shader = NULL;
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-    glsldata_t result = <span id="removedchars" style="background-color:#ff9999;font-weight:bolder;" >malloc</span>(sizeof(struct glsldata));
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+    glsldata_t result = <span id="addedchars" style="background-color:#99ff99;font-weight:bolder;" >g_malloc0</span>(sizeof(struct glsldata));
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     assert( result != NULL );
     result->filename = strdup(filename);
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-    result->shaders = NULL;
-    result->programs = NULL;
-    result->max_shaders = 0;
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > 
     while( fgets(buf, sizeof(buf), f) != NULL ) {
         if( strlen(buf) == 0 )
             continue;
 
         if( strncmp(buf, "#vertex ", 8) == 0 ) {
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-            shader = <span id="removedchars" style="background-color:#ff9999;font-weight:bolder;" >malloc</span>(sizeof(struct shader));
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+            shader = <span id="addedchars" style="background-color:#99ff99;font-weight:bolder;" >g_malloc0</span>(sizeof(struct shader));
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >             assert( shader != NULL );
             shader->type = VERTEX_SHADER;
             shader->name = strdup(g_strstrip(buf+8));
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -90,7 +176,7 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >             current_posn = 0;
             result->shaders = g_list_append(result->shaders, shader);
         } else if( strncmp( buf, "#fragment ", 10 ) == 0 ) {
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-            shader = <span id="removedchars" style="background-color:#ff9999;font-weight:bolder;" >malloc</span>(sizeof(struct shader));
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+            shader = <span id="addedchars" style="background-color:#99ff99;font-weight:bolder;" >g_malloc0</span>(sizeof(struct shader));
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >             assert( shader != NULL );
             shader->type = FRAGMENT_SHADER;
             shader->name = strdup(g_strstrip(buf+10));
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -101,7 +187,7 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >             result->shaders = g_list_append(result->shaders, shader);
         } else if( strncmp( buf, "#program ", 9 ) == 0 ) {
             shader = NULL;
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-            program_t program = <span id="removedchars" style="background-color:#ff9999;font-weight:bolder;" >malloc</span>(sizeof(struct program));
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+            program_t program = <span id="addedchars" style="background-color:#99ff99;font-weight:bolder;" >g_malloc0</span>(sizeof(struct program));
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >             char *rest = buf+9;
             char *equals = strchr(rest, '=');
             if( equals == NULL ) {
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -124,10 +210,17 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >             }
             strcpy( shader->body + current_posn, buf );
             current_posn += len;
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+            char *line = g_strstrip(buf);
+            if( strncmp( line, "uniform ", 8 ) == 0 ) {
+                parseVarDecl(shader, TRUE, line+8);
+            } else if( strncmp( line, "attribute ", 10 ) == 0 ) {
+                parseVarDecl(shader, FALSE, line+10);
+            }
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >         }
     }
 
     fclose(f);
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+    linkPrograms(result);
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     return result;
 }
 
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -149,6 +242,28 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     }
 }
 
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+static const char *sl_type_map[][3] = {
+        {"int", "int", "int *"},
+        {"short", "short", "short *"},
+        {"sampler", "int", "int *"},
+        {"vec", "GLfloat *", "GLfloat *"},
+        {"mat", "GLfloat *", "GLfloat *"},
+        {NULL, NULL}
+};
+
+static const char *getCType( const char *sl_type, gboolean isUniform ) {
+    for( unsigned i=0; sl_type_map[i][0] != NULL; i++ ) {
+        if( strncmp(sl_type_map[i][0], sl_type, strlen(sl_type_map[i][0])) == 0 ) {
+            if( isUniform ) {
+                return sl_type_map[i][1];
+            } else {
+                return sl_type_map[i][2];
+            }
+        }
+    }
+    return "void *";
+}
+
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > static void writeHeader( FILE *out, glsldata_t data )
 {
     fprintf( out, "/*\n * This file automatically generated by genglsl from %s\n */\n", data->filename );
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -185,26 +300,26 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     fprintf( f, "#define GLSL_VERTEX_SHADER 1\n" );
     fprintf( f, "#define GLSL_FRAGMENT_SHADER 2\n" );
 
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-    fprintf( f, "typedef enum {\n" );
-    last_name = NULL;
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     count = 0;
     GList *program_ptr;
     for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
         count++;
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-        program_t program = (program_t)program_ptr->data;
-        fprintf( f, "    %s,\n", program->name );
-        last_name = program->name;
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     }
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-    fprintf( f, "} program_id;\n\n" );
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+    fprintf( f, "#define GLSL_NUM_PROGRAMS %d\n", count );
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > 
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-    if( last_name == NULL )
-        last_name = "NULL";
-    fprintf( f, "#define GLSL_LAST_PROGRAM %s\n", last_name );
-    fprintf( f, "#define GLSL_NUM_PROGRAMS %d\n", count );
-    fprintf( f, "#define GLSL_NO_PROGRAM -1\n\n" );
-
-    fprintf( f, "int glsl_load_programs();\n" );
-    fprintf( f, "void glsl_use_program_id( program_id );\n" );
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+    for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
+        program_t program = program_ptr->data;
+        GList *var_ptr;
+        fprintf( f, "void glsl_use_%s();\n", program->name );
+        for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
+            variable_t var = var_ptr->data;
+            if( var->uniform ) {
+                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 );
+            } else {
+                fprintf( f, "void glsl_set_%s_%s_pointer(%s ptr); /* attribute %s %s */ \n", program->name, var->name, getCType(var->type,var->uniform), var->type, var->name);
+            }
+        }
+    }
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > 
     fprintf( f, "#endif /* !lxdream_glsl_H */\n" );
 
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -234,6 +349,7 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > 
     fprintf( f, "const int program_list[][%d] = {\n", data->max_shaders+1 );
     GList *program_ptr;
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+    GList *var_ptr;
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     unsigned i;
     for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
         program_t program = (program_t)program_ptr->data;
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -245,6 +361,48 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     }
     fprintf( f, "    {GLSL_NO_SHADER}};\n" );
 
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+    /* per-program functions */
+    for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
+        program_t program = program_ptr->data;
+        fprintf( f, "\nstatic gl_program_t prog_%s_id;\n",program->name );
+        for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
+            variable_t var = var_ptr->data;
+            fprintf( f, "static GLint var_%s_%s_loc;\n", program->name, var->name);
+        }
+
+    }
+    for( program_ptr = data->programs; program_ptr != NULL; program_ptr = program_ptr->next ) {
+        program_t program = program_ptr->data;
+        fprintf( f, "\nvoid glsl_use_%s() {\n    glsl_use_program(prog_%s_id);\n}\n", program->name, program->name );
+
+        for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
+            variable_t var = var_ptr->data;
+            if( var->uniform ) {
+                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 );
+                fprintf( f, "    glsl_set_uniform_%s(var_%s_%s_loc,value);\n}\n", var->type, program->name, var->name );
+            } else {
+                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);
+                fprintf( f, "    glsl_set_attrib_%s(var_%s_%s_loc,stride, ptr);\n}\n", var->type, program->name, var->name );
+            }
+        }
+    }
+
+    fprintf( f, "\nstatic void glsl_init_programs( gl_program_t *ids ) {\n" );
+    for( program_ptr = data->programs, i=0; program_ptr != NULL; program_ptr = program_ptr->next, i++ ) {
+        program_t program = program_ptr->data;
+
+        fprintf( f, "    prog_%s_id = ids[%d];\n\n", program->name, i );
+        for( var_ptr = program->variables; var_ptr != NULL; var_ptr = var_ptr->next ) {
+            variable_t var = var_ptr->data;
+            if( var->uniform ) {
+                fprintf( f, "    var_%s_%s_loc = glsl_get_uniform_location(prog_%s_id, \"%s\");\n", program->name, var->name, program->name, var->name );
+            } else {
+                fprintf( f, "    var_%s_%s_loc = glsl_get_attrib_location(prog_%s_id, \"%s\");\n", program->name, var->name, program->name, var->name );
+            }
+        }
+    }
+    fprintf( f, "}\n" );
+
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     fclose(f);
 }
 
</pre></div>
<center><small>Chaos Theory</small></center>
</div></body></html>