Merge branch 'master' of goat:git/laserbrain_demo
[laserbrain_demo] / src / unistate.cc
1 #include <map>
2 #include <vector>
3 #include "unistate.h"
4 #include "shader.h"
5 #include "logger.h"
6
7 struct StateItem {
8         StType type;
9
10         union {
11                 int ival[4];
12                 float fval[16];
13         };
14         int transpose;  // for matrices
15 };
16
17 static const char *typestr(StType type);
18 static int type_nelem(StType type);
19 static StType float_type(int elem);
20 static StType int_type(int elem);
21
22 std::vector<StateItem> state;
23 std::map<std::string, int> stateidx;
24
25
26 int add_unistate(const char *name, StType type)
27 {
28         static const float ident3[] = {1, 0, 0, 0, 1, 0, 0, 0, 1};
29         static const float ident4[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
30
31         if(stateidx.find(name) != stateidx.end()) {
32                 return stateidx[name];
33         }
34
35         StateItem sitem;
36         memset(&sitem, 0, sizeof sitem);
37         sitem.type = type;
38
39         // initialize to a reasonable default value
40         switch(type) {
41         case ST_MATRIX3:
42                 memcpy(sitem.fval, ident3, sizeof ident3);
43                 break;
44
45         case ST_MATRIX4:
46                 memcpy(sitem.fval, ident4, sizeof ident4);
47                 break;
48
49         default:
50                 break;  // in all other cases leave it zero (see memset above)
51         }
52
53         int sidx = state.size();
54         state.push_back(sitem);
55         stateidx[name] = sidx;
56
57         debug_log("adding uniform state [%d]: %s %s\n", sidx, typestr(sitem.type), name);
58
59         return sidx;
60 }
61
62 int get_unistate_index(const char *name)
63 {
64         std::map<std::string, int>::const_iterator it = stateidx.find(name);
65         if(it != stateidx.end()) {
66                 return it->second;
67         }
68         return -1;
69 }
70
71 #define CHECK_INDEX(i)  \
72         if(i < 0 || i >= (int)state.size()) return
73
74 #define CHECK_COUNT(count, type) \
75         do { \
76                 int max_elem = type_nelem(type); \
77                 if(!(count) || (count) > max_elem) { \
78                         count = max_elem; \
79                 } \
80         } while(0)
81
82 void set_unistate(int sidx, const int *val, int count)
83 {
84         CHECK_INDEX(sidx);
85         CHECK_COUNT(count, state[sidx].type);
86
87         memcpy(state[sidx].ival, val, count * sizeof *state[sidx].ival);
88 }
89
90 void set_unistate(int sidx, const float *val, int count)
91 {
92         CHECK_INDEX(sidx);
93         CHECK_COUNT(count, state[sidx].type);
94
95         memcpy(state[sidx].fval, val, count * sizeof *state[sidx].fval);
96         state[sidx].transpose = 0;
97 }
98
99 void get_unistate(int sidx, int *val, int count)
100 {
101         CHECK_INDEX(sidx);
102         CHECK_COUNT(count, state[sidx].type);
103
104         memcpy(val, state[sidx].ival, count * sizeof *val);
105 }
106
107 void get_unistate(int sidx, float *val, int count)
108 {
109         CHECK_INDEX(sidx);
110         CHECK_COUNT(count, state[sidx].type);
111
112         memcpy(val, state[sidx].fval, count * sizeof *val);
113 }
114
115 void set_unistate(int sidx, int val)
116 {
117         set_unistate(sidx, &val, 1);
118 }
119
120 void set_unistate(int sidx, float val)
121 {
122         set_unistate(sidx, &val, 1);
123 }
124
125 void set_unistate(int sidx, const Vec2 &vec)
126 {
127         set_unistate(sidx, &vec.x, 2);
128 }
129
130 void set_unistate(int sidx, const Vec3 &vec)
131 {
132         set_unistate(sidx, &vec.x, 3);
133 }
134
135 void set_unistate(int sidx, const Vec4 &vec)
136 {
137         set_unistate(sidx, &vec.x, 4);
138 }
139
140 void set_unistate(int sidx, const Mat3 &mat)
141 {
142         set_unistate(sidx, mat[0], 9);
143         state[sidx].transpose = 0;
144 }
145
146 void set_unistate(int sidx, const Mat4 &mat)
147 {
148         set_unistate(sidx, mat[0], 16);
149         state[sidx].transpose = 0;
150 }
151
152
153 int set_unistate(const char *name, int *val, int count)
154 {
155         int sidx = get_unistate_index(name);
156         if(sidx < 0) {
157                 StType type = int_type(count);
158                 if(type == ST_UNKNOWN) {
159                         error_log("invalid element count (%d) while setting previously unknown unistate item \"%s\"\n",
160                                         count, name);
161                         return -1;
162                 }
163
164                 sidx = add_unistate(name, type);
165         }
166         set_unistate(sidx, val);
167         return sidx;
168 }
169
170 int set_unistate(const char *name, float *val, int count)
171 {
172         int sidx = get_unistate_index(name);
173         if(sidx < 0) {
174                 StType type = float_type(count);
175                 if(type == ST_UNKNOWN) {
176                         error_log("invalid element count (%d) while setting previously unknown unistate item \"%s\"\n",
177                                         count, name);
178                         return -1;
179                 }
180
181                 sidx = add_unistate(name, type);
182         }
183         set_unistate(sidx, val);
184         return sidx;
185 }
186
187 int set_unistate(const char *name, int val)
188 {
189         int sidx = get_unistate_index(name);
190         if(sidx < 0) {
191                 sidx = add_unistate(name, ST_INT);
192         }
193         set_unistate(sidx, val);
194         return sidx;
195 }
196
197 int set_unistate(const char *name, float val)
198 {
199         int sidx = get_unistate_index(name);
200         if(sidx < 0) {
201                 sidx = add_unistate(name, ST_FLOAT);
202         }
203         set_unistate(sidx, val);
204         return sidx;
205 }
206
207 int set_unistate(const char *name, const Vec2 &vec)
208 {
209         int sidx = get_unistate_index(name);
210         if(sidx < 0) {
211                 sidx = add_unistate(name, ST_FLOAT2);
212         }
213         set_unistate(sidx, vec);
214         return sidx;
215 }
216
217 int set_unistate(const char *name, const Vec3 &vec)
218 {
219         int sidx = get_unistate_index(name);
220         if(sidx < 0) {
221                 sidx = add_unistate(name, ST_FLOAT3);
222         }
223         set_unistate(sidx, vec);
224         return sidx;
225 }
226
227 int set_unistate(const char *name, const Vec4 &vec)
228 {
229         int sidx = get_unistate_index(name);
230         if(sidx < 0) {
231                 sidx = add_unistate(name, ST_FLOAT4);
232         }
233         set_unistate(sidx, vec);
234         return sidx;
235 }
236
237 int set_unistate(const char *name, const Mat3 &mat)
238 {
239         int sidx = get_unistate_index(name);
240         if(sidx < 0) {
241                 sidx = add_unistate(name, ST_MATRIX3);
242         }
243         set_unistate(sidx, mat);
244         return sidx;
245 }
246
247 int set_unistate(const char *name, const Mat4 &mat)
248 {
249         int sidx = get_unistate_index(name);
250         if(sidx < 0) {
251                 sidx = add_unistate(name, ST_MATRIX4);
252         }
253         set_unistate(sidx, mat);
254         return sidx;
255 }
256
257
258 int get_unistate_int(int sidx)
259 {
260         int val = 0;
261         get_unistate(sidx, &val, 1);
262         return val;
263 }
264
265 float get_unistate_float(int sidx)
266 {
267         float val = 0.0f;
268         get_unistate(sidx, &val, 1);
269         return val;
270 }
271
272 Vec2 get_unistate_vec2(int sidx)
273 {
274         float val[2] = {0.0f, 0.0f};
275         get_unistate(sidx, val, 2);
276         return Vec2(val[0], val[1]);
277 }
278
279 Vec3 get_unistate_vec3(int sidx)
280 {
281         float val[3] = {0.0f, 0.0f, 0.0f};
282         get_unistate(sidx, val, 3);
283         return Vec3(val[0], val[1], val[2]);
284 }
285
286 Vec4 get_unistate_vec4(int sidx)
287 {
288         float val[4] = {0.0f, 0.0f, 0.0f};
289         get_unistate(sidx, val, 4);
290         return Vec4(val[0], val[1], val[2], val[3]);
291 }
292
293 Mat3 get_unistate_mat3(int sidx)
294 {
295         Mat3 res;
296         get_unistate(sidx, res.m[0], 9);
297         return res;
298 }
299
300 Mat4 get_unistate_mat4(int sidx)
301 {
302         Mat4 res;
303         get_unistate(sidx, res.m[0], 16);
304         return res;
305 }
306
307
308 int get_unistate_int(const char *name)
309 {
310         int sidx = get_unistate_index(name);
311         if(sidx == -1) {
312                 return 0;
313         }
314         return get_unistate_int(sidx);
315 }
316
317 float get_unistate_float(const char *name)
318 {
319         int sidx = get_unistate_index(name);
320         if(sidx == -1) {
321                 return 0.0f;
322         }
323         return get_unistate_float(sidx);
324 }
325
326 Vec2 get_unistate_vec2(const char *name)
327 {
328         int sidx = get_unistate_index(name);
329         if(sidx == -1) {
330                 return Vec2();
331         }
332         return get_unistate_vec2(sidx);
333 }
334
335 Vec3 get_unistate_vec3(const char *name)
336 {
337         int sidx = get_unistate_index(name);
338         if(sidx == -1) {
339                 return Vec3();
340         }
341         return get_unistate_vec3(sidx);
342 }
343
344 Vec4 get_unistate_vec4(const char *name)
345 {
346         int sidx = get_unistate_index(name);
347         if(sidx == -1) {
348                 return Vec4();
349         }
350         return get_unistate_vec4(sidx);
351 }
352
353 Mat3 get_unistate_mat3(const char *name)
354 {
355         int sidx = get_unistate_index(name);
356         if(sidx == -1) {
357                 return Mat3();
358         }
359         return get_unistate_mat3(sidx);
360 }
361
362 Mat4 get_unistate_mat4(const char *name)
363 {
364         int sidx = get_unistate_index(name);
365         if(sidx == -1) {
366                 return Mat4();
367         }
368         return get_unistate_mat4(sidx);
369 }
370
371
372 void setup_unistate(const ShaderProg *sdr)
373 {
374         if(!sdr) {
375                 if(!(sdr = ShaderProg::current)) {
376                         return;
377                 }
378         }
379
380         sdr->setup_state_uniforms();
381 }
382
383 bool setup_unistate(int sidx, const ShaderProg *sdr, int loc)
384 {
385         if(loc < 0 || sidx < 0 || sidx >= (int)state.size()) {
386                 return false;
387         }
388
389         glUseProgram(sdr->get_id());
390
391         switch(state[sidx].type) {
392         case ST_INT:
393                 glUniform1iv(loc, 1, state[sidx].ival);
394                 break;
395         case ST_INT2:
396                 glUniform2iv(loc, 1, state[sidx].ival);
397                 break;
398         case ST_INT3:
399                 glUniform3iv(loc, 1, state[sidx].ival);
400                 break;
401         case ST_INT4:
402                 glUniform4iv(loc, 1, state[sidx].ival);
403                 break;
404
405         case ST_FLOAT:
406                 glUniform1fv(loc, 1, state[sidx].fval);
407                 break;
408         case ST_FLOAT2:
409                 glUniform2fv(loc, 1, state[sidx].fval);
410                 break;
411         case ST_FLOAT3:
412                 glUniform3fv(loc, 1, state[sidx].fval);
413                 break;
414         case ST_FLOAT4:
415                 glUniform4fv(loc, 1, state[sidx].fval);
416                 break;
417
418         case ST_MATRIX3:
419 #ifdef GL_ES_VERSION_2_0
420                 {
421                         float tmat[9], *ptr = tmat;
422                         for(int i=0; i<3; i++) {
423                                 for(int j=0; j<3; j++) {
424                                         *ptr++ = state[sidx].fval[j * 3 + i];
425                                 }
426                         }
427                         glUniformMatrix3fv(loc, 1, GL_FALSE, tmat);
428                 }
429 #else
430                 glUniformMatrix3fv(loc, 1, state[sidx].transpose, state[sidx].fval);
431 #endif
432                 break;
433
434         case ST_MATRIX4:
435 #ifdef GL_ES_VERSION_2_0
436                 {
437                         float tmat[16], *ptr = tmat;
438                         for(int i=0; i<4; i++) {
439                                 for(int j=0; j<4; j++) {
440                                         *ptr++ = state[sidx].fval[j * 4 + i];
441                                 }
442                         }
443                         glUniformMatrix4fv(loc, 1, GL_FALSE, tmat);
444                 }
445 #else
446                 glUniformMatrix4fv(loc, 1, state[sidx].transpose, state[sidx].fval);
447 #endif
448                 break;
449
450         default:
451                 return false;
452         }
453
454         return true;
455 }
456
457 bool setup_unistate(const char *name, const ShaderProg *sdr)
458 {
459         int loc = sdr->get_uniform_location(name);
460         if(loc == -1) {
461                 return false;
462         }
463         return setup_unistate(get_unistate_index(name), sdr, loc);
464 }
465
466 void set_world_matrix(const Mat4 &mat)
467 {
468         static int sidx = -1, sidx_transp, sidx_mat3;
469
470         if(sidx == -1) {
471                 sidx = add_unistate("st_world_matrix", ST_MATRIX4);
472                 sidx_mat3 = add_unistate("st_world_matrix3", ST_MATRIX3);
473                 sidx_transp = add_unistate("st_world_matrix_transpose", ST_MATRIX4);
474         }
475
476         set_unistate(sidx, mat);
477         set_unistate(sidx_mat3, mat.submatrix(3, 3));
478         set_unistate(sidx_transp, mat[0]);
479         state[sidx_transp].transpose = 1;
480 }
481
482 void set_view_matrix(const Mat4 &mat)
483 {
484         static int sidx = -1, sidx_transp, sidx_mat3;
485
486         if(sidx == -1) {
487                 sidx = add_unistate("st_view_matrix", ST_MATRIX4);
488                 sidx_mat3 = add_unistate("st_view_matrix3", ST_MATRIX3);
489                 sidx_transp = add_unistate("st_view_matrix_transpose", ST_MATRIX4);
490         }
491
492         set_unistate(sidx, mat);
493         set_unistate(sidx_mat3, mat.submatrix(3, 3));
494         set_unistate(sidx_transp, mat[0]);
495         state[sidx_transp].transpose = 1;
496 }
497
498 void set_projection_matrix(const Mat4 &mat)
499 {
500         static int sidx = -1;
501
502         if(sidx == -1) {
503                 sidx = add_unistate("st_proj_matrix", ST_MATRIX4);
504         }
505
506         set_unistate(sidx, mat);
507 }
508
509 void set_texture_matrix(const Mat4 &mat)
510 {
511         static int sidx = -1;
512
513         if(sidx == -1) {
514                 sidx = add_unistate("st_tex_matrix", ST_MATRIX4);
515         }
516
517         set_unistate(sidx, mat);
518 }
519
520 Mat4 get_world_matrix()
521 {
522         static int sidx = -1;
523
524         if(sidx == -1) {
525                 if((sidx = get_unistate_index("st_world_matrix")) == -1) {
526                         return Mat4();
527                 }
528         }
529         return get_unistate_mat4(sidx);
530 }
531
532 Mat4 get_view_matrix()
533 {
534         static int sidx = -1;
535
536         if(sidx == -1) {
537                 if((sidx = get_unistate_index("st_view_matrix")) == -1) {
538                         return Mat4();
539                 }
540         }
541         return get_unistate_mat4(sidx);
542 }
543
544 Mat4 get_projection_matrix()
545 {
546         static int sidx = -1;
547
548         if(sidx == -1) {
549                 if((sidx = get_unistate_index("st_proj_matrix")) == -1) {
550                         return Mat4();
551                 }
552         }
553         return get_unistate_mat4(sidx);
554 }
555
556 Mat4 get_texture_matrix()
557 {
558         static int sidx = -1;
559
560         if(sidx == -1) {
561                 if((sidx = get_unistate_index("st_tex_matrix")) == -1) {
562                         return Mat4();
563                 }
564         }
565         return get_unistate_mat4(sidx);
566 }
567
568 void setup_gl_matrices()
569 {
570 #ifdef USE_OLDGL
571         Mat4 modelview = get_view_matrix() * get_world_matrix();
572         Mat4 proj = get_projection_matrix();
573         Mat4 tex = get_texture_matrix();
574
575         glMatrixMode(GL_TEXTURE);
576         glLoadTransposeMatrixf(tex[0]);
577         glMatrixMode(GL_PROJECTION);
578         glLoadTransposeMatrixf(proj[0]);
579         glMatrixMode(GL_MODELVIEW);
580         glLoadTransposeMatrixf(modelview[0]);
581 #endif
582 }
583
584 static const char *typestr(StType type)
585 {
586         switch(type) {
587         case ST_INT:
588                 return "int";
589         case ST_INT2:
590                 return "ivec2";
591         case ST_INT3:
592                 return "ivec3";
593         case ST_INT4:
594                 return "ivec4";
595         case ST_FLOAT:
596                 return "float";
597         case ST_FLOAT2:
598                 return "vec2";
599         case ST_FLOAT3:
600                 return "vec3";
601         case ST_FLOAT4:
602                 return "vec4";
603         case ST_MATRIX3:
604                 return "mat3";
605         case ST_MATRIX4:
606                 return "mat4";
607
608         default:
609                 break;
610         }
611         return "<unknown>";
612 }
613
614 static int type_nelem(StType type)
615 {
616         switch(type) {
617         case ST_INT:
618         case ST_FLOAT:
619                 return 1;
620         case ST_INT2:
621         case ST_FLOAT2:
622                 return 2;
623         case ST_INT3:
624         case ST_FLOAT3:
625                 return 3;
626         case ST_INT4:
627         case ST_FLOAT4:
628                 return 4;
629         case ST_MATRIX3:
630                 return 9;
631         case ST_MATRIX4:
632                 return 16;
633
634         default:
635                 break;
636         }
637
638         return 0;
639 }
640
641 static StType float_type(int elem)
642 {
643         switch(elem) {
644         case 1:
645                 return ST_FLOAT;
646         case 2:
647                 return ST_FLOAT2;
648         case 3:
649                 return ST_FLOAT3;
650         case 4:
651                 return ST_FLOAT4;
652         case 9:
653                 return ST_MATRIX3;
654         case 16:
655                 return ST_MATRIX4;
656         default:
657                 break;
658         }
659         return ST_UNKNOWN;
660 }
661
662 static StType int_type(int elem)
663 {
664         switch(elem) {
665         case 1:
666                 return ST_INT;
667         case 2:
668                 return ST_INT2;
669         case 3:
670                 return ST_INT3;
671         case 4:
672                 return ST_INT4;
673         default:
674                 break;
675         }
676         return ST_UNKNOWN;
677 }