rev |
line source |
nuclear@10
|
1 #include <stdio.h>
|
nuclear@10
|
2 #include <stdlib.h>
|
nuclear@10
|
3 #include <string.h>
|
nuclear@10
|
4 #include <errno.h>
|
nuclear@10
|
5 #include <stdarg.h>
|
nuclear@10
|
6 #include <assert.h>
|
nuclear@10
|
7 #include "opengl.h"
|
nuclear@21
|
8 #include "assman.h"
|
nuclear@10
|
9
|
nuclear@10
|
10 #if defined(unix) || defined(__unix__)
|
nuclear@10
|
11 #include <unistd.h>
|
nuclear@10
|
12 #include <sys/stat.h>
|
nuclear@10
|
13 #endif /* unix */
|
nuclear@10
|
14
|
nuclear@10
|
15 #include "sdr.h"
|
nuclear@10
|
16
|
nuclear@10
|
17 static const char *sdrtypestr(unsigned int sdrtype);
|
nuclear@10
|
18
|
nuclear@10
|
19 unsigned int create_vertex_shader(const char *src)
|
nuclear@10
|
20 {
|
nuclear@10
|
21 return create_shader(src, GL_VERTEX_SHADER);
|
nuclear@10
|
22 }
|
nuclear@10
|
23
|
nuclear@10
|
24 unsigned int create_pixel_shader(const char *src)
|
nuclear@10
|
25 {
|
nuclear@10
|
26 return create_shader(src, GL_FRAGMENT_SHADER);
|
nuclear@10
|
27 }
|
nuclear@10
|
28
|
nuclear@10
|
29 unsigned int create_tessctl_shader(const char *src)
|
nuclear@10
|
30 {
|
nuclear@10
|
31 #ifdef GL_TESS_CONTROL_SHADER
|
nuclear@10
|
32 return create_shader(src, GL_TESS_CONTROL_SHADER);
|
nuclear@10
|
33 #else
|
nuclear@10
|
34 return 0;
|
nuclear@10
|
35 #endif
|
nuclear@10
|
36 }
|
nuclear@10
|
37
|
nuclear@10
|
38 unsigned int create_tesseval_shader(const char *src)
|
nuclear@10
|
39 {
|
nuclear@10
|
40 #ifdef GL_TESS_EVALUATION_SHADER
|
nuclear@10
|
41 return create_shader(src, GL_TESS_EVALUATION_SHADER);
|
nuclear@10
|
42 #else
|
nuclear@10
|
43 return 0;
|
nuclear@10
|
44 #endif
|
nuclear@10
|
45 }
|
nuclear@10
|
46
|
nuclear@10
|
47 unsigned int create_geometry_shader(const char *src)
|
nuclear@10
|
48 {
|
nuclear@10
|
49 #ifdef GL_GEOMETRY_SHADER
|
nuclear@10
|
50 return create_shader(src, GL_GEOMETRY_SHADER);
|
nuclear@10
|
51 #else
|
nuclear@10
|
52 return 0;
|
nuclear@10
|
53 #endif
|
nuclear@10
|
54 }
|
nuclear@10
|
55
|
nuclear@10
|
56 unsigned int create_shader(const char *src, unsigned int sdr_type)
|
nuclear@10
|
57 {
|
nuclear@10
|
58 unsigned int sdr;
|
nuclear@10
|
59 int success, info_len;
|
nuclear@10
|
60 char *info_str = 0;
|
nuclear@10
|
61 GLenum err;
|
nuclear@10
|
62
|
nuclear@10
|
63 sdr = glCreateShader(sdr_type);
|
nuclear@10
|
64 assert(glGetError() == GL_NO_ERROR);
|
nuclear@10
|
65 glShaderSource(sdr, 1, &src, 0);
|
nuclear@10
|
66 err = glGetError();
|
nuclear@10
|
67 assert(err == GL_NO_ERROR);
|
nuclear@10
|
68 glCompileShader(sdr);
|
nuclear@10
|
69 assert(glGetError() == GL_NO_ERROR);
|
nuclear@10
|
70
|
nuclear@10
|
71 glGetShaderiv(sdr, GL_COMPILE_STATUS, &success);
|
nuclear@10
|
72 assert(glGetError() == GL_NO_ERROR);
|
nuclear@10
|
73 glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len);
|
nuclear@10
|
74 assert(glGetError() == GL_NO_ERROR);
|
nuclear@10
|
75
|
nuclear@10
|
76 if(info_len) {
|
nuclear@10
|
77 if((info_str = malloc(info_len + 1))) {
|
nuclear@10
|
78 glGetShaderInfoLog(sdr, info_len, 0, info_str);
|
nuclear@10
|
79 assert(glGetError() == GL_NO_ERROR);
|
nuclear@10
|
80 info_str[info_len] = 0;
|
nuclear@10
|
81 }
|
nuclear@10
|
82 }
|
nuclear@10
|
83
|
nuclear@10
|
84 if(success) {
|
nuclear@10
|
85 fprintf(stderr, info_str ? "done: %s\n" : "done\n", info_str);
|
nuclear@10
|
86 } else {
|
nuclear@10
|
87 fprintf(stderr, info_str ? "failed: %s\n" : "failed\n", info_str);
|
nuclear@10
|
88 glDeleteShader(sdr);
|
nuclear@10
|
89 sdr = 0;
|
nuclear@10
|
90 }
|
nuclear@10
|
91
|
nuclear@10
|
92 free(info_str);
|
nuclear@10
|
93 return sdr;
|
nuclear@10
|
94 }
|
nuclear@10
|
95
|
nuclear@10
|
96 void free_shader(unsigned int sdr)
|
nuclear@10
|
97 {
|
nuclear@10
|
98 glDeleteShader(sdr);
|
nuclear@10
|
99 }
|
nuclear@10
|
100
|
nuclear@10
|
101 unsigned int load_vertex_shader(const char *fname)
|
nuclear@10
|
102 {
|
nuclear@10
|
103 return load_shader(fname, GL_VERTEX_SHADER);
|
nuclear@10
|
104 }
|
nuclear@10
|
105
|
nuclear@10
|
106 unsigned int load_pixel_shader(const char *fname)
|
nuclear@10
|
107 {
|
nuclear@10
|
108 return load_shader(fname, GL_FRAGMENT_SHADER);
|
nuclear@10
|
109 }
|
nuclear@10
|
110
|
nuclear@10
|
111 unsigned int load_tessctl_shader(const char *fname)
|
nuclear@10
|
112 {
|
nuclear@10
|
113 #ifdef GL_TESS_CONTROL_SHADER
|
nuclear@10
|
114 return load_shader(fname, GL_TESS_CONTROL_SHADER);
|
nuclear@10
|
115 #else
|
nuclear@10
|
116 return 0;
|
nuclear@10
|
117 #endif
|
nuclear@10
|
118 }
|
nuclear@10
|
119
|
nuclear@10
|
120 unsigned int load_tesseval_shader(const char *fname)
|
nuclear@10
|
121 {
|
nuclear@10
|
122 #ifdef GL_TESS_EVALUATION_SHADER
|
nuclear@10
|
123 return load_shader(fname, GL_TESS_EVALUATION_SHADER);
|
nuclear@10
|
124 #else
|
nuclear@10
|
125 return 0;
|
nuclear@10
|
126 #endif
|
nuclear@10
|
127 }
|
nuclear@10
|
128
|
nuclear@10
|
129 unsigned int load_geometry_shader(const char *fname)
|
nuclear@10
|
130 {
|
nuclear@10
|
131 #ifdef GL_GEOMETRY_SHADER
|
nuclear@10
|
132 return load_shader(fname, GL_GEOMETRY_SHADER);
|
nuclear@10
|
133 #else
|
nuclear@10
|
134 return 0;
|
nuclear@10
|
135 #endif
|
nuclear@10
|
136 }
|
nuclear@10
|
137
|
nuclear@10
|
138 unsigned int load_shader(const char *fname, unsigned int sdr_type)
|
nuclear@10
|
139 {
|
nuclear@10
|
140 unsigned int sdr;
|
nuclear@10
|
141 size_t filesize;
|
nuclear@21
|
142 ass_file *fp;
|
nuclear@10
|
143 char *src;
|
nuclear@10
|
144
|
nuclear@21
|
145 if(!(fp = ass_fopen(fname, "rb"))) {
|
nuclear@10
|
146 fprintf(stderr, "failed to open shader %s: %s\n", fname, strerror(errno));
|
nuclear@10
|
147 return 0;
|
nuclear@10
|
148 }
|
nuclear@10
|
149
|
nuclear@21
|
150 filesize = ass_fseek(fp, 0, SEEK_END);
|
nuclear@21
|
151 /*filesize = ass_ftell(fp);*/
|
nuclear@21
|
152 printf(" filesize: %ld\n", filesize);
|
nuclear@21
|
153 ass_fseek(fp, 0, SEEK_SET);
|
nuclear@10
|
154
|
nuclear@10
|
155 if(!(src = malloc(filesize + 1))) {
|
nuclear@21
|
156 ass_fclose(fp);
|
nuclear@10
|
157 return 0;
|
nuclear@10
|
158 }
|
nuclear@21
|
159 ass_fread(src, 1, filesize, fp);
|
nuclear@10
|
160 src[filesize] = 0;
|
nuclear@21
|
161 ass_fclose(fp);
|
nuclear@10
|
162
|
nuclear@10
|
163 fprintf(stderr, "compiling %s shader: %s... ", sdrtypestr(sdr_type), fname);
|
nuclear@10
|
164 sdr = create_shader(src, sdr_type);
|
nuclear@10
|
165
|
nuclear@10
|
166 free(src);
|
nuclear@10
|
167 return sdr;
|
nuclear@10
|
168 }
|
nuclear@10
|
169
|
nuclear@10
|
170
|
nuclear@10
|
171 /* ---- gpu programs ---- */
|
nuclear@10
|
172
|
nuclear@10
|
173 unsigned int create_program(void)
|
nuclear@10
|
174 {
|
nuclear@10
|
175 unsigned int prog = glCreateProgram();
|
nuclear@10
|
176 assert(glGetError() == GL_NO_ERROR);
|
nuclear@10
|
177 return prog;
|
nuclear@10
|
178 }
|
nuclear@10
|
179
|
nuclear@10
|
180 unsigned int create_program_link(unsigned int sdr0, ...)
|
nuclear@10
|
181 {
|
nuclear@10
|
182 unsigned int prog, sdr;
|
nuclear@10
|
183 va_list ap;
|
nuclear@10
|
184
|
nuclear@10
|
185 if(!(prog = create_program())) {
|
nuclear@10
|
186 return 0;
|
nuclear@10
|
187 }
|
nuclear@10
|
188
|
nuclear@10
|
189 attach_shader(prog, sdr0);
|
nuclear@10
|
190 if(glGetError()) {
|
nuclear@10
|
191 return 0;
|
nuclear@10
|
192 }
|
nuclear@10
|
193
|
nuclear@10
|
194 va_start(ap, sdr0);
|
nuclear@10
|
195 while((sdr = va_arg(ap, unsigned int))) {
|
nuclear@10
|
196 attach_shader(prog, sdr);
|
nuclear@10
|
197 if(glGetError()) {
|
nuclear@10
|
198 return 0;
|
nuclear@10
|
199 }
|
nuclear@10
|
200 }
|
nuclear@10
|
201 va_end(ap);
|
nuclear@10
|
202
|
nuclear@10
|
203 if(link_program(prog) == -1) {
|
nuclear@10
|
204 free_program(prog);
|
nuclear@10
|
205 return 0;
|
nuclear@10
|
206 }
|
nuclear@10
|
207 return prog;
|
nuclear@10
|
208 }
|
nuclear@10
|
209
|
nuclear@10
|
210 unsigned int create_program_load(const char *vfile, const char *pfile)
|
nuclear@10
|
211 {
|
nuclear@10
|
212 unsigned int vs = 0, ps = 0;
|
nuclear@10
|
213
|
nuclear@10
|
214 if(vfile && *vfile && !(vs = load_vertex_shader(vfile))) {
|
nuclear@10
|
215 return 0;
|
nuclear@10
|
216 }
|
nuclear@10
|
217 if(pfile && *pfile && !(ps = load_pixel_shader(pfile))) {
|
nuclear@10
|
218 return 0;
|
nuclear@10
|
219 }
|
nuclear@10
|
220 return create_program_link(vs, ps, 0);
|
nuclear@10
|
221 }
|
nuclear@10
|
222
|
nuclear@10
|
223 void free_program(unsigned int sdr)
|
nuclear@10
|
224 {
|
nuclear@10
|
225 glDeleteProgram(sdr);
|
nuclear@10
|
226 }
|
nuclear@10
|
227
|
nuclear@10
|
228 void attach_shader(unsigned int prog, unsigned int sdr)
|
nuclear@10
|
229 {
|
nuclear@17
|
230 int err;
|
nuclear@17
|
231
|
nuclear@10
|
232 if(prog && sdr) {
|
nuclear@17
|
233 assert(glGetError() == GL_NO_ERROR);
|
nuclear@10
|
234 glAttachShader(prog, sdr);
|
nuclear@17
|
235 if((err = glGetError()) != GL_NO_ERROR) {
|
nuclear@17
|
236 fprintf(stderr, "failed to attach shader %u to program %u (err: 0x%x)\n", sdr, prog, err);
|
nuclear@10
|
237 abort();
|
nuclear@10
|
238 }
|
nuclear@10
|
239 }
|
nuclear@10
|
240 }
|
nuclear@10
|
241
|
nuclear@10
|
242 int link_program(unsigned int prog)
|
nuclear@10
|
243 {
|
nuclear@10
|
244 int linked, info_len, retval = 0;
|
nuclear@10
|
245 char *info_str = 0;
|
nuclear@10
|
246
|
nuclear@10
|
247 glLinkProgram(prog);
|
nuclear@10
|
248 assert(glGetError() == GL_NO_ERROR);
|
nuclear@10
|
249 glGetProgramiv(prog, GL_LINK_STATUS, &linked);
|
nuclear@10
|
250 assert(glGetError() == GL_NO_ERROR);
|
nuclear@10
|
251 glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &info_len);
|
nuclear@10
|
252 assert(glGetError() == GL_NO_ERROR);
|
nuclear@10
|
253
|
nuclear@10
|
254 if(info_len) {
|
nuclear@10
|
255 if((info_str = malloc(info_len + 1))) {
|
nuclear@10
|
256 glGetProgramInfoLog(prog, info_len, 0, info_str);
|
nuclear@10
|
257 assert(glGetError() == GL_NO_ERROR);
|
nuclear@10
|
258 info_str[info_len] = 0;
|
nuclear@10
|
259 }
|
nuclear@10
|
260 }
|
nuclear@10
|
261
|
nuclear@10
|
262 if(linked) {
|
nuclear@10
|
263 fprintf(stderr, info_str ? "linking done: %s\n" : "linking done\n", info_str);
|
nuclear@10
|
264 } else {
|
nuclear@10
|
265 fprintf(stderr, info_str ? "linking failed: %s\n" : "linking failed\n", info_str);
|
nuclear@10
|
266 retval = -1;
|
nuclear@10
|
267 }
|
nuclear@10
|
268
|
nuclear@10
|
269 free(info_str);
|
nuclear@10
|
270 return retval;
|
nuclear@10
|
271 }
|
nuclear@10
|
272
|
nuclear@10
|
273 int bind_program(unsigned int prog)
|
nuclear@10
|
274 {
|
nuclear@10
|
275 GLenum err;
|
nuclear@10
|
276
|
nuclear@10
|
277 glUseProgram(prog);
|
nuclear@10
|
278 if(prog && (err = glGetError()) != GL_NO_ERROR) {
|
nuclear@10
|
279 /* maybe the program is not linked, try linking first */
|
nuclear@10
|
280 if(err == GL_INVALID_OPERATION) {
|
nuclear@10
|
281 if(link_program(prog) == -1) {
|
nuclear@10
|
282 return -1;
|
nuclear@10
|
283 }
|
nuclear@10
|
284 glUseProgram(prog);
|
nuclear@10
|
285 return glGetError() == GL_NO_ERROR ? 0 : -1;
|
nuclear@10
|
286 }
|
nuclear@10
|
287 return -1;
|
nuclear@10
|
288 }
|
nuclear@10
|
289 return 0;
|
nuclear@10
|
290 }
|
nuclear@10
|
291
|
nuclear@10
|
292 /* ugly but I'm not going to write the same bloody code over and over */
|
nuclear@10
|
293 #define BEGIN_UNIFORM_CODE \
|
nuclear@10
|
294 int loc, curr_prog; \
|
nuclear@10
|
295 glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog); \
|
nuclear@10
|
296 if((unsigned int)curr_prog != prog && bind_program(prog) == -1) { \
|
nuclear@10
|
297 return -1; \
|
nuclear@10
|
298 } \
|
nuclear@10
|
299 if((loc = glGetUniformLocation(prog, name)) != -1)
|
nuclear@10
|
300
|
nuclear@10
|
301 #define END_UNIFORM_CODE \
|
nuclear@10
|
302 if((unsigned int)curr_prog != prog) { \
|
nuclear@10
|
303 bind_program(curr_prog); \
|
nuclear@10
|
304 } \
|
nuclear@10
|
305 return loc == -1 ? -1 : 0
|
nuclear@10
|
306
|
nuclear@10
|
307 int set_uniform_int(unsigned int prog, const char *name, int val)
|
nuclear@10
|
308 {
|
nuclear@10
|
309 BEGIN_UNIFORM_CODE {
|
nuclear@10
|
310 glUniform1i(loc, val);
|
nuclear@10
|
311 }
|
nuclear@10
|
312 END_UNIFORM_CODE;
|
nuclear@10
|
313 }
|
nuclear@10
|
314
|
nuclear@10
|
315 int set_uniform_float(unsigned int prog, const char *name, float val)
|
nuclear@10
|
316 {
|
nuclear@10
|
317 BEGIN_UNIFORM_CODE {
|
nuclear@10
|
318 glUniform1f(loc, val);
|
nuclear@10
|
319 }
|
nuclear@10
|
320 END_UNIFORM_CODE;
|
nuclear@10
|
321 }
|
nuclear@10
|
322
|
nuclear@10
|
323 int set_uniform_float2(unsigned int prog, const char *name, float x, float y)
|
nuclear@10
|
324 {
|
nuclear@10
|
325 BEGIN_UNIFORM_CODE {
|
nuclear@10
|
326 glUniform2f(loc, x, y);
|
nuclear@10
|
327 }
|
nuclear@10
|
328 END_UNIFORM_CODE;
|
nuclear@10
|
329 }
|
nuclear@10
|
330
|
nuclear@10
|
331 int set_uniform_float3(unsigned int prog, const char *name, float x, float y, float z)
|
nuclear@10
|
332 {
|
nuclear@10
|
333 BEGIN_UNIFORM_CODE {
|
nuclear@10
|
334 glUniform3f(loc, x, y, z);
|
nuclear@10
|
335 }
|
nuclear@10
|
336 END_UNIFORM_CODE;
|
nuclear@10
|
337 }
|
nuclear@10
|
338
|
nuclear@10
|
339 int set_uniform_float4(unsigned int prog, const char *name, float x, float y, float z, float w)
|
nuclear@10
|
340 {
|
nuclear@10
|
341 BEGIN_UNIFORM_CODE {
|
nuclear@10
|
342 glUniform4f(loc, x, y, z, w);
|
nuclear@10
|
343 }
|
nuclear@10
|
344 END_UNIFORM_CODE;
|
nuclear@10
|
345 }
|
nuclear@10
|
346
|
nuclear@10
|
347 int set_uniform_matrix4(unsigned int prog, const char *name, float *mat)
|
nuclear@10
|
348 {
|
nuclear@10
|
349 BEGIN_UNIFORM_CODE {
|
nuclear@10
|
350 glUniformMatrix4fv(loc, 1, GL_FALSE, mat);
|
nuclear@10
|
351 }
|
nuclear@10
|
352 END_UNIFORM_CODE;
|
nuclear@10
|
353 }
|
nuclear@10
|
354
|
nuclear@10
|
355 int set_uniform_matrix4_transposed(unsigned int prog, const char *name, float *mat)
|
nuclear@10
|
356 {
|
nuclear@10
|
357 BEGIN_UNIFORM_CODE {
|
nuclear@10
|
358 glUniformMatrix4fv(loc, 1, GL_TRUE, mat);
|
nuclear@10
|
359 }
|
nuclear@10
|
360 END_UNIFORM_CODE;
|
nuclear@10
|
361 }
|
nuclear@10
|
362
|
nuclear@10
|
363 int get_attrib_loc(unsigned int prog, const char *name)
|
nuclear@10
|
364 {
|
nuclear@10
|
365 int loc, curr_prog;
|
nuclear@10
|
366
|
nuclear@10
|
367 glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog);
|
nuclear@10
|
368 if((unsigned int)curr_prog != prog && bind_program(prog) == -1) {
|
nuclear@10
|
369 return -1;
|
nuclear@10
|
370 }
|
nuclear@10
|
371
|
nuclear@10
|
372 loc = glGetAttribLocation(prog, (char*)name);
|
nuclear@10
|
373
|
nuclear@10
|
374 if((unsigned int)curr_prog != prog) {
|
nuclear@10
|
375 bind_program(curr_prog);
|
nuclear@10
|
376 }
|
nuclear@10
|
377 return loc;
|
nuclear@10
|
378 }
|
nuclear@10
|
379
|
nuclear@10
|
380 void set_attrib_float3(int attr_loc, float x, float y, float z)
|
nuclear@10
|
381 {
|
nuclear@10
|
382 glVertexAttrib3f(attr_loc, x, y, z);
|
nuclear@10
|
383 }
|
nuclear@10
|
384
|
nuclear@10
|
385 static const char *sdrtypestr(unsigned int sdrtype)
|
nuclear@10
|
386 {
|
nuclear@10
|
387 switch(sdrtype) {
|
nuclear@10
|
388 case GL_VERTEX_SHADER:
|
nuclear@10
|
389 return "vertex";
|
nuclear@10
|
390 case GL_FRAGMENT_SHADER:
|
nuclear@10
|
391 return "pixel";
|
nuclear@10
|
392 #ifdef GL_TESS_CONTROL_SHADER
|
nuclear@10
|
393 case GL_TESS_CONTROL_SHADER:
|
nuclear@10
|
394 return "tessellation control";
|
nuclear@10
|
395 #endif
|
nuclear@10
|
396 #ifdef GL_TESS_EVALUATION_SHADER
|
nuclear@10
|
397 case GL_TESS_EVALUATION_SHADER:
|
nuclear@10
|
398 return "tessellation evaluation";
|
nuclear@10
|
399 #endif
|
nuclear@10
|
400 #ifdef GL_GEOMETRY_SHADER
|
nuclear@10
|
401 case GL_GEOMETRY_SHADER:
|
nuclear@10
|
402 return "geometry";
|
nuclear@10
|
403 #endif
|
nuclear@10
|
404
|
nuclear@10
|
405 default:
|
nuclear@10
|
406 break;
|
nuclear@10
|
407 }
|
nuclear@10
|
408 return "<unknown>";
|
nuclear@10
|
409 }
|