libgoatvr

view src/vr.c @ 33:1102327fe85f

added red-cyan anaglyph fallback drawing
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 30 Oct 2015 06:34:00 +0200
parents 7eea82cea9d2
children
line source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "opengl.h"
5 #include "vr.h"
6 #include "vr_impl.h"
7 #include "mathutil.h"
9 #define DEF_IPD 0.064f
11 static void fallback_present(void);
14 static struct vr_module *vrm;
15 static float idmat[] = {
16 1, 0, 0, 0,
17 0, 1, 0, 0,
18 0, 0, 1, 0,
19 0, 0, 0, 1
20 };
21 static float fbtex_rect[] = {
22 0, 0, 1, 1
23 };
25 static void *defopt; /* default options db */
27 static struct {
28 float umin, umax, vmin, vmax;
29 int tex;
30 } rtarg[2];
33 int vr_init(void)
34 {
35 int i, nmodules;
36 char *env;
38 /* create the default options database */
39 if(!defopt && (defopt = create_options())) {
40 set_option_float(defopt, VR_RENDER_RES_SCALE, 1.0f);
41 set_option_float(defopt, VR_EYE_HEIGHT, 1.675f);
42 set_option_float(defopt, VR_IPD, DEF_IPD);
43 set_option_vec3f(defopt, VR_LEYE_OFFSET, -DEF_IPD * 0.5f, 0.0f, 0.0f);
44 set_option_vec3f(defopt, VR_REYE_OFFSET, DEF_IPD * 0.5f, 0.0f, 0.0f);
46 set_option_int(defopt, VR_NULL_STEREO_SBS,
47 (env = getenv("VR_NULL_STEREO_SBS")) && atoi(env) ? 1 : 0);
48 set_option_int(defopt, VR_NULL_STEREO_GL,
49 (env = getenv("VR_NULL_STEREO_GL")) && atoi(env) ? 1 : 0);
50 set_option_int(defopt, VR_NULL_STEREO_REDCYAN,
51 (env = getenv("VR_NULL_STEREO_REDCYAN")) && atoi(env) ? 1 : 0);
52 }
54 if(vrm) {
55 vr_shutdown();
56 }
58 vr_init_modules();
60 nmodules = vr_get_num_modules();
61 for(i=0; i<nmodules; i++) {
62 struct vr_module *m = vr_get_module(i);
63 if(m->init() != -1) {
64 /* add to the active modules array */
65 vr_activate_module(i);
66 }
67 }
69 if(!vr_get_num_active_modules()) {
70 return -1;
71 }
73 if((env = getenv("VR_MODULE"))) {
74 vr_use_module_named(env);
75 } else {
76 vr_use_module(0);
77 }
78 return 0;
79 }
81 void vr_shutdown(void)
82 {
83 vr_clear_modules();
84 vrm = 0;
85 fbtex_rect[0] = fbtex_rect[1] = 0;
86 fbtex_rect[2] = fbtex_rect[3] = 1;
87 }
89 int vr_module_count(void)
90 {
91 return vr_get_num_active_modules();
92 }
94 const char *vr_module_name(int idx)
95 {
96 struct vr_module *m = vr_get_active_module(idx);
97 if(!m) {
98 return 0;
99 }
100 return m->name;
101 }
103 int vr_use_module(int idx)
104 {
105 if(idx >= 0 && idx < vr_get_num_active_modules()) {
106 struct vr_module *m = vr_get_active_module(idx);
107 if(m != vrm) {
108 vrm = m;
109 printf("using vr module: %s\n", vrm->name);
110 }
111 return 0;
112 }
113 return -1;
114 }
116 int vr_use_module_named(const char *name)
117 {
118 int i, count = vr_get_num_active_modules();
120 for(i=0; i<count; i++) {
121 struct vr_module *m = vr_get_active_module(i);
122 if(strcmp(m->name, name) == 0) {
123 return vr_use_module(i);
124 }
125 }
126 return -1;
127 }
129 void vr_seti(const char *optname, int val)
130 {
131 if(vrm && vrm->set_option) {
132 vrm->set_option(optname, OTYPE_INT, &val);
133 } else {
134 set_option_int(defopt, optname, val);
135 }
136 }
138 void vr_setf(const char *optname, float val)
139 {
140 if(vrm && vrm->set_option) {
141 vrm->set_option(optname, OTYPE_FLOAT, &val);
142 } else {
143 set_option_float(defopt, optname, val);
144 }
145 }
147 static int def_option_int(const char *optname)
148 {
149 int res = 0;
150 int left, right;
152 if(strcmp(optname, VR_RENDER_XRES) == 0) {
153 if(vrm && vrm->get_option && vrm->get_option(optname, OTYPE_INT, &left) != -1 &&
154 vrm->get_option(optname, OTYPE_INT, &right) != -1) {
155 return left + right;
156 }
157 } else if(strcmp(optname, VR_RENDER_YRES) == 0) {
158 if(vrm && vrm->get_option && vrm->get_option(optname, OTYPE_INT, &left) != -1 &&
159 vrm->get_option(optname, OTYPE_INT, &right) != -1) {
160 return left > right ? left : right;
161 }
162 }
164 get_option_int(defopt, optname, &res);
165 return res;
166 }
168 static float def_option_float(const char *optname)
169 {
170 float res = 0.0f;
172 if(strcmp(optname, VR_RENDER_XRES) == 0 || strcmp(optname, VR_RENDER_YRES) == 0) {
173 return (float)def_option_int(optname);
174 }
176 get_option_float(defopt, optname, &res);
177 return res;
178 }
180 static float *def_option_vec(const char *optname, float *res)
181 {
182 res[0] = res[1] = res[2] = res[3] = 0.0f;
184 get_option_vec(defopt, optname, res);
185 return res;
186 }
188 int vr_geti(const char *optname)
189 {
190 int res = 0;
192 if(!vrm || !vrm->get_option || vrm->get_option(optname, OTYPE_INT, &res) == -1) {
193 res = def_option_int(optname);
194 }
195 return res;
196 }
198 float vr_getf(const char *optname)
199 {
200 float res = 0.0f;
202 if(!vrm || !vrm->get_option || vrm->get_option(optname, OTYPE_FLOAT, &res) == -1) {
203 res = def_option_float(optname);
204 }
205 return res;
206 }
208 float *vr_getfv(const char *optname, float *res)
209 {
210 static float sres[4];
211 if(!res) res = sres;
213 if(!vrm || !vrm->get_option || vrm->get_option(optname, OTYPE_VEC, res) == -1) {
214 def_option_vec(optname, res);
215 }
216 return res;
217 }
219 int vr_geti_def(const char *optname, int def_val)
220 {
221 int res = 0;
223 if(!vrm || !vrm->get_option || vrm->get_option(optname, OTYPE_INT, &res) == -1) {
224 if(get_option_int(defopt, optname, &res) == -1) { /* fallback */
225 return def_val;
226 }
227 }
228 return res;
229 }
231 float vr_getf_def(const char *optname, float def_val)
232 {
233 float res = 0.0f;
235 if(!vrm || !vrm->get_option || vrm->get_option(optname, OTYPE_FLOAT, &res) == -1) {
236 if(get_option_float(defopt, optname, &res) == -1) { /* fallback */
237 return def_val;
238 }
239 }
240 return res;
241 }
243 int vr_view_translation(int eye, float *vec)
244 {
245 if(vrm && vrm->translation) {
246 vrm->translation(eye, vec);
247 return 1;
248 }
249 vec[0] = vec[1] = vec[2] = 0.0f;
250 return 0;
251 }
253 int vr_view_rotation(int eye, float *quat)
254 {
255 if(vrm && vrm->rotation) {
256 vrm->rotation(eye, quat);
257 return 1;
258 }
259 quat[0] = quat[1] = quat[2] = 0.0f;
260 quat[3] = 1.0f;
261 return 0;
262 }
264 int vr_view_matrix(int eye, float *mat)
265 {
266 float offs[3], quat[4], eye_offs[4];
267 float rmat[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
268 float tmat[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
270 if(vrm && vrm->view_matrix) {
271 vrm->view_matrix(eye, mat);
272 return 1;
273 }
275 memcpy(mat, idmat, sizeof idmat);
277 if(vr_view_translation(eye, offs)) {
278 offs[0] = -offs[0];
279 offs[1] = -offs[1];
280 offs[2] = -offs[2];
282 vrimp_translation_matrix(offs, tmat);
283 vrimp_mult_matrix(mat, mat, tmat);
284 }
285 if(vr_view_rotation(eye, quat)) {
286 vrimp_rotation_matrix(quat, rmat);
287 vrimp_mult_matrix(mat, mat, rmat);
288 }
290 vr_getfv(eye == VR_EYE_LEFT ? VR_LEYE_OFFSET : VR_REYE_OFFSET, eye_offs);
291 eye_offs[0] = -eye_offs[0];
292 eye_offs[1] = -eye_offs[1];
293 eye_offs[2] = -eye_offs[2];
294 vrimp_translation_matrix(eye_offs, tmat);
295 vrimp_mult_matrix(mat, mat, tmat);
296 return 1;
297 }
299 int vr_proj_matrix(int eye, float znear, float zfar, float *mat)
300 {
301 if(vrm && vrm->proj_matrix) {
302 vrm->proj_matrix(eye, znear, zfar, mat);
303 return 1;
304 }
305 memcpy(mat, idmat, sizeof idmat);
306 return 0;
307 }
309 void vr_begin(int eye)
310 {
311 if(vrm && vrm->begin) {
312 vrm->begin(eye);
313 }
314 }
316 void vr_end(void)
317 {
318 if(vrm && vrm->end) {
319 vrm->end();
320 }
321 }
323 int vr_swap_buffers(void)
324 {
325 int res = 0;
327 if(vrm && vrm->present) {
328 res = vrm->present();
329 }
331 if(!res) {
332 fallback_present();
333 vrimp_swap_buffers();
334 }
335 return 0;
336 }
338 void vr_output_texture(unsigned int tex, float umin, float vmin, float umax, float vmax)
339 {
340 float halfu = (umax + umin) * 0.5f;
342 vr_output_texture_eye(VR_EYE_LEFT, tex, umin, vmin, halfu, vmax);
343 vr_output_texture_eye(VR_EYE_RIGHT, tex, halfu, vmin, umax, vmax);
344 }
346 void vr_output_texture_eye(int eye, unsigned int tex, float umin, float vmin, float umax, float vmax)
347 {
348 if(vrm && vrm->set_eye_texture) {
349 vrm->set_eye_texture(eye, tex, umin, vmin, umax, vmax);
350 } else {
351 rtarg[eye].tex = tex;
352 rtarg[eye].umin = umin;
353 rtarg[eye].umax = umax;
354 rtarg[eye].vmin = vmin;
355 rtarg[eye].vmax = vmax;
356 }
357 }
359 void vr_recenter(void)
360 {
361 if(vrm && vrm->recenter) {
362 vrm->recenter();
363 }
364 }
366 static void fallback_present(void)
367 {
368 int i, show_sbs = vr_geti(VR_NULL_STEREO_SBS);
369 int use_quadbuf = vr_geti(VR_NULL_STEREO_GL);
370 int use_redcyan = vr_geti(VR_NULL_STEREO_REDCYAN);
372 glPushAttrib(GL_ENABLE_BIT | GL_TRANSFORM_BIT);
374 glDisable(GL_LIGHTING);
375 glDisable(GL_DEPTH_TEST);
376 glDisable(GL_ALPHA_TEST);
377 glDisable(GL_STENCIL_TEST);
378 glDisable(GL_FOG);
379 glDisable(GL_BLEND);
381 glEnable(GL_TEXTURE_2D);
383 glMatrixMode(GL_MODELVIEW);
384 glPushMatrix();
385 glLoadIdentity();
386 glMatrixMode(GL_PROJECTION);
387 glPushMatrix();
388 glLoadIdentity();
390 glClear(GL_COLOR_BUFFER_BIT);
392 for(i=0; i<2; i++) {
393 float x0, x1;
395 if(show_sbs && !use_quadbuf && !use_redcyan) {
396 x0 = i == 0 ? -1 : 0;
397 x1 = i == 0 ? 0 : 1;
398 } else {
399 x0 = -1;
400 x1 = 1;
401 }
403 glBindTexture(GL_TEXTURE_2D, rtarg[i].tex);
405 if(use_quadbuf) {
406 glDrawBuffer(GL_BACK_LEFT + i);
407 }
409 if(use_redcyan) {
410 if(i == 0) {
411 glColorMask(1, 0, 0, 1);
412 } else {
413 glColorMask(0, 1, 1, 1);
415 glEnable(GL_BLEND);
416 glBlendFunc(GL_ONE, GL_ONE);
417 }
418 }
420 glBegin(GL_QUADS);
421 glTexCoord2f(rtarg[i].umin, rtarg[i].vmin);
422 glVertex2f(x0, -1);
423 glTexCoord2f(rtarg[i].umax, rtarg[i].vmin);
424 glVertex2f(x1, -1);
425 glTexCoord2f(rtarg[i].umax, rtarg[i].vmax);
426 glVertex2f(x1, 1);
427 glTexCoord2f(rtarg[i].umin, rtarg[i].vmax);
428 glVertex2f(x0, 1);
429 glEnd();
431 if(!show_sbs && !use_quadbuf && !use_redcyan) break;
432 }
434 if(use_quadbuf) {
435 glDrawBuffer(GL_BACK);
436 }
437 if(use_redcyan) {
438 glColorMask(1, 1, 1, 1);
439 }
441 glPopMatrix();
442 glMatrixMode(GL_MODELVIEW);
443 glPopMatrix();
445 glPopAttrib();
446 }