--- /dev/null
+#include <stdlib.h>
+#include <string.h>
+#include <opengl.h>
+#include <logger.h>
+#include "ubersdr.h"
+#include "sdr.h"
+
+enum {
+ UBER_LIGHT0,
+ UBER_LIGHT1,
+ UBER_LIGHT2,
+ UBER_LIGHT3,
+ UBER_TEXMAP,
+ UBER_CUBEMAP,
+ UBER_SPHMAP,
+ UBER_SHADOWS,
+
+ MAX_STATE_BITS
+};
+#define MAX_LIGHTS 4
+
+static const char *macros[] = {
+ "#define USE_LIGHT0\n",
+ "#define USE_LIGHT1\n",
+ "#define USE_LIGHT2\n",
+ "#define USE_LIGHT3\n",
+ "#define USE_TEXMAP\n",
+ "#define USE_CUBEMAP\n",
+ "#define USE_SPHMAP\n",
+ "#define USE_SHADOWMAP\n",
+ 0
+};
+
+struct sdrcache {
+ unsigned int vs, ps;
+ unsigned int prog;
+};
+
+static unsigned int mkshader(unsigned int type);
+
+static char *vs_fname, *ps_fname;
+static unsigned int state;
+
+#define CACHE_SIZE (1 << MAX_STATE_BITS)
+static struct sdrcache cache[CACHE_SIZE];
+
+int uber_init(const char *vsname, const char *psname)
+{
+ state = 0;
+ memset(cache, 0, sizeof cache);
+
+ vs_fname = strdup(vsname);
+ ps_fname = strdup(psname);
+ if(!vs_fname || !ps_fname) {
+ free(vs_fname);
+ return -1;
+ }
+ return 0;
+}
+
+void uber_destroy(void)
+{
+ int i;
+
+ for(i=0; i<CACHE_SIZE; i++) {
+ if(cache[i].vs)
+ free_shader(cache[i].vs);
+ if(cache[i].ps)
+ free_shader(cache[i].ps);
+ if(cache[i].prog)
+ free_program(cache[i].prog);
+ }
+ free(vs_fname);
+ free(ps_fname);
+}
+
+void uber_clear(void)
+{
+ state = 0;
+}
+
+void uber_enable_light(int idx)
+{
+ if(idx >= 0 && idx < MAX_LIGHTS) {
+ state |= (1 << (UBER_LIGHT0 + idx));
+ }
+}
+
+void uber_disable_light(int idx)
+{
+ if(idx >= 0 && idx < MAX_LIGHTS) {
+ state &= ~(1 << (UBER_LIGHT0 + idx));
+ }
+}
+
+void uber_enable_texmap(void)
+{
+ state |= (1 << UBER_TEXMAP);
+}
+
+void uber_disable_texmap(void)
+{
+ state &= ~(1 << UBER_TEXMAP);
+}
+
+void uber_enable_cubemap(void)
+{
+ state |= (1 << UBER_CUBEMAP);
+}
+
+void uber_disable_cubemap(void)
+{
+ state &= ~(1 << UBER_CUBEMAP);
+}
+
+void uber_enable_sphmap(void)
+{
+ state |= (1 << UBER_SPHMAP);
+}
+
+void uber_disable_sphmap(void)
+{
+ state &= ~(1 << UBER_SPHMAP);
+}
+
+void uber_enable_shadows(void)
+{
+ state |= (1 << UBER_SHADOWS);
+}
+
+void uber_disable_shadows(void)
+{
+ state &= ~(1 << UBER_SHADOWS);
+}
+
+unsigned int uber_vertex_shader(void)
+{
+ if(!cache[state].vs) {
+ cache[state].vs = mkshader(GL_VERTEX_SHADER);
+ }
+ return cache[state].vs;
+}
+
+unsigned int uber_pixel_shader(void)
+{
+ if(!cache[state].ps) {
+ cache[state].ps = mkshader(GL_FRAGMENT_SHADER);
+ }
+ return cache[state].ps;
+}
+
+static unsigned int mkshader(unsigned int type)
+{
+ int i;
+ unsigned int res;
+ clear_shader_header(type);
+
+ debug_log("mkshader(%s): %x\n", type == GL_VERTEX_SHADER ? "vertex" : "pixel");
+
+ for(i=0; i<MAX_STATE_BITS; i++) {
+ if(state & (1 << i)) {
+ add_shader_header(type, macros[i]);
+ debug_log(" - header: %s\n", macros[i]);
+ }
+ }
+ res = load_shader(type == GL_VERTEX_SHADER ? vs_fname : ps_fname, type);
+ clear_shader_header(type);
+ return res;
+}
+
+unsigned int uber_program(void)
+{
+ if(!cache[state].prog) {
+ unsigned int vs, ps;
+ if(!(vs = uber_vertex_shader()) || !(ps = uber_pixel_shader())) {
+ error_log("uber_program failed to make shaders for state: %x\n", state);
+ return 0;
+ }
+ if(!(cache[state].prog = create_program_link(vs, ps, 0))) {
+ error_log("uber_program failed to link program for state: %x\n", state);
+ return 0;
+ }
+ }
+ return cache[state].prog;
+}