rev |
line source |
nuclear@20
|
1 #include <assert.h>
|
nuclear@20
|
2 #include <string>
|
nuclear@20
|
3 #include <map>
|
nuclear@20
|
4 #include "shader.h"
|
nuclear@20
|
5 #include "sdr.h"
|
nuclear@20
|
6 #include "opengl.h"
|
nuclear@20
|
7
|
nuclear@20
|
8 std::map<std::string, unsigned int> sdrdb;
|
nuclear@20
|
9
|
nuclear@21
|
10 const SdrProg *SdrProg::active;
|
nuclear@21
|
11
|
nuclear@20
|
12 SdrProg::SdrProg()
|
nuclear@20
|
13 {
|
nuclear@20
|
14 prog = 0;
|
nuclear@20
|
15 valid = false;
|
nuclear@20
|
16 }
|
nuclear@20
|
17
|
nuclear@20
|
18 SdrProg::~SdrProg()
|
nuclear@20
|
19 {
|
nuclear@20
|
20 destroy();
|
nuclear@20
|
21 }
|
nuclear@20
|
22
|
nuclear@20
|
23 void SdrProg::create()
|
nuclear@20
|
24 {
|
nuclear@20
|
25 destroy();
|
nuclear@20
|
26 prog = glCreateProgram();
|
nuclear@20
|
27 }
|
nuclear@20
|
28
|
nuclear@20
|
29 void SdrProg::destroy()
|
nuclear@20
|
30 {
|
nuclear@20
|
31 if(prog) {
|
nuclear@20
|
32 glDeleteProgram(prog);
|
nuclear@20
|
33 }
|
nuclear@20
|
34 valid = false;
|
nuclear@20
|
35
|
nuclear@20
|
36 for(size_t i=0; i<priv_sdr.size(); i++) {
|
nuclear@20
|
37 glDeleteShader(priv_sdr[i]);
|
nuclear@20
|
38 }
|
nuclear@20
|
39 priv_sdr.clear();
|
nuclear@20
|
40 }
|
nuclear@20
|
41
|
nuclear@20
|
42 bool SdrProg::attach_shader(unsigned int sdr)
|
nuclear@20
|
43 {
|
nuclear@20
|
44 assert(glGetError() == GL_NO_ERROR);
|
nuclear@20
|
45
|
nuclear@20
|
46 glAttachShader(prog, sdr);
|
nuclear@20
|
47 if(glGetError() != GL_NO_ERROR) {
|
nuclear@20
|
48 fprintf(stderr, "failed to attach shader %u to program %u\n", sdr, prog);
|
nuclear@20
|
49 return false;
|
nuclear@20
|
50 }
|
nuclear@20
|
51
|
nuclear@20
|
52 valid = false;
|
nuclear@20
|
53 return true;
|
nuclear@20
|
54 }
|
nuclear@20
|
55
|
nuclear@20
|
56 bool SdrProg::create(unsigned int vsdr, unsigned int psdr)
|
nuclear@20
|
57 {
|
nuclear@20
|
58 create();
|
nuclear@20
|
59
|
nuclear@20
|
60 if(!attach_shader(vsdr) || !attach_shader(psdr)) {
|
nuclear@20
|
61 return false;
|
nuclear@20
|
62 }
|
nuclear@20
|
63
|
nuclear@21
|
64 bind_default_attribs();
|
nuclear@21
|
65 return link();
|
nuclear@20
|
66 }
|
nuclear@20
|
67
|
nuclear@20
|
68 bool SdrProg::create(const char *vsrc, const char *psrc)
|
nuclear@20
|
69 {
|
nuclear@20
|
70 unsigned int vs = create_shader(vsrc, GL_VERTEX_SHADER);
|
nuclear@20
|
71 if(!vs) {
|
nuclear@20
|
72 return false;
|
nuclear@20
|
73 }
|
nuclear@20
|
74
|
nuclear@20
|
75 unsigned int ps = create_shader(psrc, GL_FRAGMENT_SHADER);
|
nuclear@20
|
76 if(!ps) {
|
nuclear@20
|
77 glDeleteShader(vs);
|
nuclear@20
|
78 return false;
|
nuclear@20
|
79 }
|
nuclear@20
|
80
|
nuclear@20
|
81 if(!create(vs, ps)) {
|
nuclear@20
|
82 glDeleteShader(vs);
|
nuclear@20
|
83 glDeleteShader(ps);
|
nuclear@20
|
84 return false;
|
nuclear@20
|
85 }
|
nuclear@20
|
86
|
nuclear@20
|
87 priv_sdr.push_back(vs);
|
nuclear@20
|
88 priv_sdr.push_back(ps);
|
nuclear@20
|
89 return true;
|
nuclear@20
|
90 }
|
nuclear@20
|
91
|
nuclear@20
|
92 bool SdrProg::load(const char *vfname, const char *pfname)
|
nuclear@20
|
93 {
|
nuclear@21
|
94 unsigned int vs = get_shader(vfname, GL_VERTEX_SHADER);
|
nuclear@20
|
95 if(!vs) {
|
nuclear@20
|
96 return false;
|
nuclear@20
|
97 }
|
nuclear@20
|
98
|
nuclear@21
|
99 unsigned int ps = get_shader(pfname, GL_FRAGMENT_SHADER);
|
nuclear@20
|
100 if(!ps) {
|
nuclear@20
|
101 return false;
|
nuclear@20
|
102 }
|
nuclear@20
|
103
|
nuclear@20
|
104 printf("creating shader program (%s, %s)\n", vfname, pfname);
|
nuclear@20
|
105 if(!(prog = create_program_link(vs, ps, 0))) {
|
nuclear@20
|
106 return false;
|
nuclear@20
|
107 }
|
nuclear@21
|
108
|
nuclear@21
|
109 bind_default_attribs();
|
nuclear@21
|
110 return link();
|
nuclear@20
|
111 }
|
nuclear@20
|
112
|
nuclear@20
|
113 bool SdrProg::link() const
|
nuclear@20
|
114 {
|
nuclear@21
|
115 if(link_program(prog) == -1) {
|
nuclear@21
|
116 return false;
|
nuclear@21
|
117 }
|
nuclear@21
|
118 valid = true;
|
nuclear@21
|
119 return true;
|
nuclear@20
|
120 }
|
nuclear@20
|
121
|
nuclear@20
|
122 int SdrProg::get_uniform(const char *name) const
|
nuclear@20
|
123 {
|
nuclear@20
|
124 if(!bind()) {
|
nuclear@20
|
125 return -1;
|
nuclear@20
|
126 }
|
nuclear@20
|
127 return glGetUniformLocation(prog, name);
|
nuclear@20
|
128 }
|
nuclear@20
|
129
|
nuclear@20
|
130 int SdrProg::get_attrib(const char *name) const
|
nuclear@20
|
131 {
|
nuclear@20
|
132 if(!bind()) {
|
nuclear@20
|
133 return -1;
|
nuclear@20
|
134 }
|
nuclear@20
|
135 return glGetAttribLocation(prog, name);
|
nuclear@20
|
136 }
|
nuclear@20
|
137
|
nuclear@20
|
138 bool SdrProg::bind_attrib(const char *name, int loc) const
|
nuclear@20
|
139 {
|
nuclear@20
|
140 if(!prog) {
|
nuclear@20
|
141 return false;
|
nuclear@20
|
142 }
|
nuclear@20
|
143
|
nuclear@20
|
144 assert(glGetError() == GL_NO_ERROR);
|
nuclear@20
|
145 glBindAttribLocation(prog, loc, name);
|
nuclear@20
|
146 if(glGetError() != GL_NO_ERROR) {
|
nuclear@20
|
147 fprintf(stderr, "failed to bind attribute %s of program %u to location %d\n",
|
nuclear@20
|
148 name, prog, loc);
|
nuclear@20
|
149 return false;
|
nuclear@20
|
150 }
|
nuclear@20
|
151 valid = false; /* must relink after the glBindAttribLocation call */
|
nuclear@20
|
152 return true;
|
nuclear@20
|
153 }
|
nuclear@20
|
154
|
nuclear@21
|
155 void SdrProg::bind_default_attribs() const
|
nuclear@21
|
156 {
|
nuclear@21
|
157 // XXX must be in sync with SdrDefaultAttrib enums in shader.h
|
nuclear@21
|
158 static const char *def_names[] = {
|
nuclear@21
|
159 "attr_vertex",
|
nuclear@21
|
160 "attr_normal",
|
nuclear@21
|
161 "attr_texcoord",
|
nuclear@21
|
162 "attr_color",
|
nuclear@21
|
163 "attr_tangent",
|
nuclear@21
|
164 0
|
nuclear@21
|
165 };
|
nuclear@21
|
166
|
nuclear@21
|
167 for(int i=0; def_names[i]; i++) {
|
nuclear@21
|
168 bind_attrib(def_names[i], i);
|
nuclear@21
|
169 }
|
nuclear@21
|
170 }
|
nuclear@21
|
171
|
nuclear@21
|
172
|
nuclear@20
|
173 bool SdrProg::bind() const
|
nuclear@20
|
174 {
|
nuclear@20
|
175 if(!prog || (!valid && !link())) {
|
nuclear@20
|
176 return false;
|
nuclear@20
|
177 }
|
nuclear@20
|
178
|
nuclear@20
|
179 assert(glGetError() == GL_NO_ERROR);
|
nuclear@20
|
180 glUseProgram(prog);
|
nuclear@20
|
181 if(glGetError() != GL_NO_ERROR) {
|
nuclear@20
|
182 fprintf(stderr, "failed to bind program %d\n", prog);
|
nuclear@20
|
183 return false;
|
nuclear@20
|
184 }
|
nuclear@21
|
185
|
nuclear@21
|
186 active = this;
|
nuclear@20
|
187 return true;
|
nuclear@20
|
188 }
|
nuclear@20
|
189
|
nuclear@22
|
190 void SdrProg::set_uniform(const char *name, int count, const int *val) const
|
nuclear@22
|
191 {
|
nuclear@22
|
192 if(!bind()) return;
|
nuclear@22
|
193
|
nuclear@22
|
194 int loc = glGetUniformLocation(prog, name);
|
nuclear@22
|
195 if(loc == -1) return;
|
nuclear@22
|
196
|
nuclear@22
|
197 switch(count) {
|
nuclear@22
|
198 case 1:
|
nuclear@22
|
199 glUniform1iv(loc, 1, val);
|
nuclear@22
|
200 break;
|
nuclear@22
|
201 case 2:
|
nuclear@22
|
202 glUniform2iv(loc, 1, val);
|
nuclear@22
|
203 break;
|
nuclear@22
|
204 case 3:
|
nuclear@22
|
205 glUniform3iv(loc, 1, val);
|
nuclear@22
|
206 case 4:
|
nuclear@22
|
207 glUniform4iv(loc, 1, val);
|
nuclear@22
|
208 default:
|
nuclear@22
|
209 break;
|
nuclear@22
|
210 }
|
nuclear@22
|
211 }
|
nuclear@22
|
212
|
nuclear@22
|
213 void SdrProg::set_uniform(const char *name, int count, const float *val) const
|
nuclear@22
|
214 {
|
nuclear@22
|
215 if(!bind()) return;
|
nuclear@22
|
216
|
nuclear@22
|
217 int loc = glGetUniformLocation(prog, name);
|
nuclear@22
|
218 if(loc == -1) return;
|
nuclear@22
|
219
|
nuclear@22
|
220 switch(count) {
|
nuclear@22
|
221 case 1:
|
nuclear@22
|
222 glUniform1fv(loc, 1, val);
|
nuclear@22
|
223 break;
|
nuclear@22
|
224 case 2:
|
nuclear@22
|
225 glUniform2fv(loc, 1, val);
|
nuclear@22
|
226 break;
|
nuclear@22
|
227 case 3:
|
nuclear@22
|
228 glUniform3fv(loc, 1, val);
|
nuclear@22
|
229 case 4:
|
nuclear@22
|
230 glUniform4fv(loc, 1, val);
|
nuclear@22
|
231 default:
|
nuclear@22
|
232 break;
|
nuclear@22
|
233 }
|
nuclear@22
|
234 }
|
nuclear@22
|
235
|
nuclear@22
|
236 void SdrProg::set_uniform(const char *name, const Vector4 &v) const
|
nuclear@22
|
237 {
|
nuclear@22
|
238 set_uniform(name, 4, &v.x);
|
nuclear@22
|
239 }
|
nuclear@22
|
240
|
nuclear@22
|
241
|
nuclear@22
|
242 void SdrProg::set_uniform1i(const char *name, int x) const
|
nuclear@22
|
243 {
|
nuclear@22
|
244 set_uniform(name, 1, &x);
|
nuclear@22
|
245 }
|
nuclear@22
|
246
|
nuclear@22
|
247 void SdrProg::set_uniform2i(const char *name, int x, int y) const
|
nuclear@22
|
248 {
|
nuclear@22
|
249 int v[] = {x, y};
|
nuclear@22
|
250 set_uniform(name, 2, v);
|
nuclear@22
|
251 }
|
nuclear@22
|
252
|
nuclear@22
|
253 void SdrProg::set_uniform3i(const char *name, int x, int y, int z) const
|
nuclear@22
|
254 {
|
nuclear@22
|
255 int v[] = {x, y, z};
|
nuclear@22
|
256 set_uniform(name, 3, v);
|
nuclear@22
|
257 }
|
nuclear@22
|
258
|
nuclear@22
|
259 void SdrProg::set_uniform4i(const char *name, int x, int y, int z, int w) const
|
nuclear@22
|
260 {
|
nuclear@22
|
261 int v[] = {x, y, z, w};
|
nuclear@22
|
262 set_uniform(name, 4, v);
|
nuclear@22
|
263 }
|
nuclear@22
|
264
|
nuclear@22
|
265 void SdrProg::set_uniform1f(const char *name, float x) const
|
nuclear@22
|
266 {
|
nuclear@22
|
267 set_uniform(name, 1, &x);
|
nuclear@22
|
268 }
|
nuclear@22
|
269
|
nuclear@22
|
270 void SdrProg::set_uniform2f(const char *name, float x, float y) const
|
nuclear@22
|
271 {
|
nuclear@22
|
272 float v[] = {x, y};
|
nuclear@22
|
273 set_uniform(name, 2, v);
|
nuclear@22
|
274 }
|
nuclear@22
|
275
|
nuclear@22
|
276 void SdrProg::set_uniform3f(const char *name, float x, float y, float z) const
|
nuclear@22
|
277 {
|
nuclear@22
|
278 float v[] = {x, y, z};
|
nuclear@22
|
279 set_uniform(name, 3, v);
|
nuclear@22
|
280 }
|
nuclear@22
|
281
|
nuclear@22
|
282 void SdrProg::set_uniform4f(const char *name, float x, float y, float z, float w) const
|
nuclear@22
|
283 {
|
nuclear@22
|
284 float v[] = {x, y, z, w};
|
nuclear@22
|
285 set_uniform(name, 4, v);
|
nuclear@22
|
286 }
|
nuclear@22
|
287
|
nuclear@22
|
288 void SdrProg::set_uniform_matrix(const char *name, const float *m) const
|
nuclear@22
|
289 {
|
nuclear@22
|
290 if(!bind()) return;
|
nuclear@22
|
291
|
nuclear@22
|
292 int loc = glGetUniformLocation(prog, name);
|
nuclear@22
|
293 if(loc == -1) return;
|
nuclear@22
|
294
|
nuclear@22
|
295 glUniformMatrix4fv(loc, 1, 0, m);
|
nuclear@22
|
296 }
|
nuclear@22
|
297
|
nuclear@22
|
298 void SdrProg::set_uniform_matrix(const char *name, const Matrix4x4 &m) const
|
nuclear@22
|
299 {
|
nuclear@22
|
300 Matrix4x4 tmp = m.transposed();
|
nuclear@22
|
301 set_uniform_matrix(name, tmp[0]);
|
nuclear@22
|
302 }
|
nuclear@22
|
303
|
nuclear@22
|
304
|
nuclear@22
|
305
|
nuclear@20
|
306 unsigned int get_shader(const char *name, unsigned int type)
|
nuclear@20
|
307 {
|
nuclear@20
|
308 std::map<std::string, unsigned int>::const_iterator it = sdrdb.find(name);
|
nuclear@20
|
309 if(it != sdrdb.end()) {
|
nuclear@20
|
310 return it->second;
|
nuclear@20
|
311 }
|
nuclear@20
|
312
|
nuclear@20
|
313 unsigned int sdr = load_shader(name, type);
|
nuclear@20
|
314 if(!sdr) {
|
nuclear@20
|
315 return 0;
|
nuclear@20
|
316 }
|
nuclear@20
|
317
|
nuclear@20
|
318 sdrdb[name] = sdr;
|
nuclear@20
|
319 return sdr;
|
nuclear@20
|
320 }
|
nuclear@21
|
321
|
nuclear@21
|
322 SdrProg *get_sdrprog(const char *vfile, const char *pfile)
|
nuclear@21
|
323 {
|
nuclear@21
|
324 SdrProg *sp = new SdrProg;
|
nuclear@21
|
325 if(!sp->load(vfile, pfile)) {
|
nuclear@21
|
326 delete sp;
|
nuclear@21
|
327 return 0;
|
nuclear@21
|
328 }
|
nuclear@21
|
329 return sp;
|
nuclear@21
|
330 }
|