final changes before dropping
[ld37_one_room] / src / ubersdr.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include <opengl.h>
4 #include <logger.h>
5 #include "ubersdr.h"
6 #include "sdr.h"
7
8 enum {
9         UBER_LIGHT0,
10         UBER_LIGHT1,
11         UBER_LIGHT2,
12         UBER_LIGHT3,
13         UBER_TEXMAP,
14         UBER_CUBEMAP,
15         UBER_SPHMAP,
16         UBER_SHADOWS,
17
18         MAX_STATE_BITS
19 };
20 #define MAX_LIGHTS      4
21
22 static const char *macros[] = {
23         "#define USE_LIGHT0\n",
24         "#define USE_LIGHT1\n",
25         "#define USE_LIGHT2\n",
26         "#define USE_LIGHT3\n",
27         "#define USE_TEXMAP\n",
28         "#define USE_CUBEMAP\n",
29         "#define USE_SPHMAP\n",
30         "#define USE_SHADOWMAP\n",
31         0
32 };
33
34 struct sdrcache {
35         unsigned int vs, ps;
36         unsigned int prog;
37 };
38
39 static unsigned int mkshader(unsigned int type);
40
41 static char *vs_fname, *ps_fname;
42 static unsigned int state;
43
44 #define CACHE_SIZE      (1 << MAX_STATE_BITS)
45 static struct sdrcache cache[CACHE_SIZE];
46
47 int uber_init(const char *vsname, const char *psname)
48 {
49         state = 0;
50         memset(cache, 0, sizeof cache);
51
52         vs_fname = strdup(vsname);
53         ps_fname = strdup(psname);
54         if(!vs_fname || !ps_fname) {
55                 free(vs_fname);
56                 return -1;
57         }
58         return 0;
59 }
60
61 void uber_destroy(void)
62 {
63         int i;
64
65         for(i=0; i<CACHE_SIZE; i++) {
66                 if(cache[i].vs)
67                         free_shader(cache[i].vs);
68                 if(cache[i].ps)
69                         free_shader(cache[i].ps);
70                 if(cache[i].prog)
71                         free_program(cache[i].prog);
72         }
73         free(vs_fname);
74         free(ps_fname);
75 }
76
77 void uber_clear(void)
78 {
79         state = 0;
80 }
81
82 void uber_enable_light(int idx)
83 {
84         if(idx >= 0 && idx < MAX_LIGHTS) {
85                 state |= (1 << (UBER_LIGHT0 + idx));
86         }
87 }
88
89 void uber_disable_light(int idx)
90 {
91         if(idx >= 0 && idx < MAX_LIGHTS) {
92                 state &= ~(1 << (UBER_LIGHT0 + idx));
93         }
94 }
95
96 void uber_enable_texmap(void)
97 {
98         state |= (1 << UBER_TEXMAP);
99 }
100
101 void uber_disable_texmap(void)
102 {
103         state &= ~(1 << UBER_TEXMAP);
104 }
105
106 void uber_enable_cubemap(void)
107 {
108         state |= (1 << UBER_CUBEMAP);
109 }
110
111 void uber_disable_cubemap(void)
112 {
113         state &= ~(1 << UBER_CUBEMAP);
114 }
115
116 void uber_enable_sphmap(void)
117 {
118         state |= (1 << UBER_SPHMAP);
119 }
120
121 void uber_disable_sphmap(void)
122 {
123         state &= ~(1 << UBER_SPHMAP);
124 }
125
126 void uber_enable_shadows(void)
127 {
128         state |= (1 << UBER_SHADOWS);
129 }
130
131 void uber_disable_shadows(void)
132 {
133         state &= ~(1 << UBER_SHADOWS);
134 }
135
136 unsigned int uber_vertex_shader(void)
137 {
138         if(!cache[state].vs) {
139                 cache[state].vs = mkshader(GL_VERTEX_SHADER);
140         }
141         return cache[state].vs;
142 }
143
144 unsigned int uber_pixel_shader(void)
145 {
146         if(!cache[state].ps) {
147                 cache[state].ps = mkshader(GL_FRAGMENT_SHADER);
148         }
149         return cache[state].ps;
150 }
151
152 static unsigned int mkshader(unsigned int type)
153 {
154         int i;
155         unsigned int res;
156         clear_shader_header(type);
157
158         debug_log("mkshader(%s): %x\n", type == GL_VERTEX_SHADER ? "vertex" : "pixel");
159
160         for(i=0; i<MAX_STATE_BITS; i++) {
161                 if(state & (1 << i)) {
162                         add_shader_header(type, macros[i]);
163                         debug_log("  - header: %s\n", macros[i]);
164                 }
165         }
166         res = load_shader(type == GL_VERTEX_SHADER ? vs_fname : ps_fname, type);
167         clear_shader_header(type);
168         return res;
169 }
170
171 unsigned int uber_program(void)
172 {
173         if(!cache[state].prog) {
174                 unsigned int vs, ps;
175                 if(!(vs = uber_vertex_shader()) || !(ps = uber_pixel_shader())) {
176                         error_log("uber_program failed to make shaders for state: %x\n", state);
177                         return 0;
178                 }
179                 if(!(cache[state].prog = create_program_link(vs, ps, 0))) {
180                         error_log("uber_program failed to link program for state: %x\n", state);
181                         return 0;
182                 }
183         }
184         return cache[state].prog;
185 }