oculus1

view src/main.cc @ 21:ef4c9d8eeca7

added shaderless distortion method
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 02 Oct 2013 04:09:37 +0300
parents ff3bfd4da86b
children 9dc19419f52b 9f783284a503
line source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <assert.h>
5 #include "opengl.h"
6 #include "vr.h"
7 #include "camera.h"
8 #include "sdr.h"
10 #ifdef __APPLE__
11 #include <OpenGL/OpenGL.h>
12 #include <OpenGL/CGLCurrent.h>
13 #include <ApplicationServices/ApplicationServices.h>
14 #endif
16 static bool init();
17 static void cleanup();
18 static void disp();
19 static void disp_vr();
20 static void draw_scene();
21 static void draw_teapot(float size);
22 static void draw_squares();
23 static void draw_grid(float size, float spacing);
24 static void toggle_mouselook();
25 static void toggle_fullscreen();
26 static void idle();
27 static void reshape(int x, int y);
28 static void keyb(unsigned char key, int x, int y);
29 static void keyup(unsigned char key, int x, int y);
30 static void mouse(int bn, int st, int x, int y);
31 static void motion(int x, int y);
32 static void passive(int x, int y);
33 static void sball_rotate(int rx, int ry, int rz);
34 static bool parse_args(int argc, char **argv);
35 static void printfps();
36 static int next_pow2(int x);
38 static VRFpsCamera cam;
39 static int width, height;
40 static bool use_vr = false;
42 static bool keystate[256];
44 static int rtarg_width, rtarg_height, rtarg_tex_width, rtarg_tex_height;
45 static float tex_scale_x, tex_scale_y;
46 static unsigned int fbo, tex[2], zbuf;
48 static unsigned int teapot_sdr;
50 static bool fullscreen_pending;
53 int main(int argc, char **argv)
54 {
55 glutInitWindowSize(1280, 800);
56 glutInit(&argc, argv);
58 if(!parse_args(argc, argv)) {
59 return 1;
60 }
62 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
63 glutCreateWindow("oculus vr test 01");
65 width = glutGet(GLUT_WINDOW_WIDTH);
66 height = glutGet(GLUT_WINDOW_HEIGHT);
68 glutDisplayFunc(use_vr ? disp_vr : disp);
69 glutIdleFunc(idle);
70 glutReshapeFunc(reshape);
71 glutKeyboardFunc(keyb);
72 glutKeyboardUpFunc(keyup);
73 glutMouseFunc(mouse);
74 glutMotionFunc(motion);
75 glutSpaceballRotateFunc(sball_rotate);
77 if(!init()) {
78 return 1;
79 }
80 atexit(cleanup);
82 glutMainLoop();
83 return 0;
84 }
86 static bool init()
87 {
88 glewInit(); // this must be first
90 glEnable(GL_DEPTH_TEST);
91 glEnable(GL_LIGHTING);
92 glEnable(GL_CULL_FACE);
94 glEnable(GL_LIGHT0);
95 glEnable(GL_LIGHTING);
96 glEnable(GL_NORMALIZE);
98 // y = height of neck
99 cam.input_move(0, 1.65, 0);
101 if(use_vr) {
102 if(vr_init(VR_INIT_OCULUS) == -1) {
103 return false;
104 }
106 // reshape to the size of the VR display
107 int xsz = vr_get_width();
108 int ysz = vr_get_height();
110 glutReshapeWindow(xsz, ysz);
112 rtarg_width = (xsz + xsz / 2) / 2;
113 rtarg_height = ysz + ysz / 2;
115 rtarg_tex_width = next_pow2(rtarg_width);
116 rtarg_tex_height = next_pow2(rtarg_height);
117 tex_scale_x = (float)rtarg_width / (float)rtarg_tex_width;
118 tex_scale_y = (float)rtarg_height / (float)rtarg_tex_height;
120 printf("render target: %dx%d (%dx%d)\n", rtarg_width, rtarg_height, rtarg_tex_width, rtarg_tex_height);
122 // create render targets for each eye
123 GLenum wrap_mode = GL_CLAMP_TO_EDGE;
124 if(!GLEW_SGIS_texture_edge_clamp) {
125 wrap_mode = GL_CLAMP;
126 }
128 glGenTextures(2, tex);
129 for(int i=0; i<2; i++) {
130 glBindTexture(GL_TEXTURE_2D, tex[i]);
131 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
132 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
133 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_mode);
134 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_mode);
135 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, rtarg_tex_width, rtarg_tex_height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
136 }
138 // create the depth render buffer
139 glGenRenderbuffersEXT(1, &zbuf);
140 glBindRenderbufferEXT(GL_RENDERBUFFER, zbuf);
141 glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, rtarg_tex_width, rtarg_tex_height);
143 // create the FBO
144 glGenFramebuffersEXT(1, &fbo);
145 glBindFramebufferEXT(GL_FRAMEBUFFER, fbo);
146 glFramebufferTextureEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex[0], 0);
147 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, zbuf);
148 }
150 teapot_sdr = create_program_load("sdr/phong.v.glsl", "sdr/phong.p.glsl");
152 // enable vsync
153 #ifdef __APPLE__
154 int swapint = 1;
155 CGLContextObj ctx = CGLGetCurrentContext();
156 CGLSetParameter(ctx, kCGLCPSwapInterval, &swapint);
157 #endif
159 #ifdef __APPLE__
160 // this is required for glutWarpPointer to work correctly, otherwise after every
161 // warp, mac os x freezes event processing for 1/4 second.
162 CGSetLocalEventsSuppressionInterval(0.0);
163 #endif
164 return true;
165 }
167 static void cleanup()
168 {
169 glDeleteTextures(2, tex);
170 glDeleteRenderbuffersEXT(1, &zbuf);
171 glDeleteFramebuffersEXT(1, &fbo);
172 vr_shutdown();
173 }
175 static void handle_input(float dt)
176 {
177 Vector3 inpv;
178 float offs = dt * 2.0;
180 if(keystate['w'] || keystate['W']) {
181 inpv.z -= offs;
182 }
183 if(keystate['s'] || keystate['S']) {
184 inpv.z += offs;
185 }
186 if(keystate['d'] || keystate['D']) {
187 inpv.x += offs;
188 }
189 if(keystate['a'] || keystate['A']) {
190 inpv.x -= offs;
191 }
193 cam.input_move(inpv.x, inpv.y, inpv.z);
194 }
196 // display function used in regular mode
197 static void disp()
198 {
199 static long prev_msec;
200 long msec = glutGet(GLUT_ELAPSED_TIME);
201 float dt = (msec - prev_msec) / 1000.0;
202 prev_msec = msec;
204 handle_input(dt);
206 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
208 glMatrixMode(GL_PROJECTION);
209 glLoadIdentity();
210 gluPerspective(45, (float)width / (float)height, 0.25, 500.0);
212 glMatrixMode(GL_MODELVIEW);
213 glLoadIdentity();
214 cam.use_inverse();
215 draw_scene();
217 glutSwapBuffers();
218 assert(glGetError() == GL_NO_ERROR);
220 printfps();
221 }
223 // display function used in VR mode
224 static void disp_vr()
225 {
226 static long prev_msec;
227 long msec = glutGet(GLUT_ELAPSED_TIME);
228 float dt = (msec - prev_msec) / 1000.0;
229 prev_msec = msec;
231 handle_input(dt);
232 cam.track_vr();
234 float proj_matrix[16];
236 float eye_dist = vr_get_eyedist();
238 glViewport(0, 0, rtarg_width, rtarg_height);
240 glClearColor(0.1, 0.1, 0.1, 1.0);
242 // draw left view
243 glBindFramebufferEXT(GL_FRAMEBUFFER, fbo);
244 glFramebufferTextureEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex[0], 0);
246 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
248 glMatrixMode(GL_PROJECTION);
249 vr_get_proj_matrix(proj_matrix, VR_EYE_LEFT);
250 glLoadTransposeMatrixf(proj_matrix);
252 glMatrixMode(GL_MODELVIEW);
253 glLoadIdentity();
254 glTranslatef(eye_dist / 2.0, 0, 0);
255 cam.use_inverse();
256 draw_scene();
259 // draw right view
260 glBindFramebufferEXT(GL_FRAMEBUFFER, fbo);
261 glFramebufferTextureEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex[1], 0);
263 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
265 glMatrixMode(GL_PROJECTION);
266 vr_get_proj_matrix(proj_matrix, VR_EYE_RIGHT);
267 glLoadTransposeMatrixf(proj_matrix);
269 glMatrixMode(GL_MODELVIEW);
270 glLoadIdentity();
271 glTranslatef(-eye_dist / 2.0, 0, 0);
272 cam.use_inverse();
273 draw_scene();
275 // return to the regular window framebuffer
276 glBindFramebuffer(GL_FRAMEBUFFER, 0);
277 glViewport(0, 0, width, height);
279 glClearColor(0, 0, 0, 0);
280 glClear(GL_COLOR_BUFFER_BIT);
282 vr_draw_eye(VR_EYE_LEFT, tex[0], tex_scale_x, tex_scale_y);
283 vr_draw_eye(VR_EYE_RIGHT, tex[1], tex_scale_x, tex_scale_y);
285 glutSwapBuffers();
286 assert(glGetError() == GL_NO_ERROR);
288 glFinish();
290 printfps();
291 }
293 static void draw_scene()
294 {
295 float lpos[] = {0, 60, 0, 1};
296 glLightfv(GL_LIGHT0, GL_POSITION, lpos);
298 draw_grid(50.0, 2.5);
300 static const Vector2 teapos[] = {
301 Vector2(-8, -8), Vector2(8, -8), Vector2(8, 8), Vector2(-8, 8)
302 };
303 static const float teasize[] = { 1.0, 2.0, 1.7, 1.4 };
304 static const float teacolor[][4] = {
305 {1.0, 0.4, 0.2, 1.0}, {0.2, 0.35, 1.0, 1.0}, {1.0, 0.9, 0.3, 1.0}, {0.3, 1.0, 0.4, 1.0}
306 };
307 static const float spec[] = {0.8, 0.8, 0.8, 1.0};
309 glUseProgram(teapot_sdr);
311 for(int i=0; i<4; i++) {
312 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, teacolor[i]);
313 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
314 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 70.0);
316 glPushMatrix();
317 glTranslatef(teapos[i].x, 0, teapos[i].y);
318 draw_teapot(teasize[i]);
319 glPopMatrix();
320 }
321 glUseProgram(0);
323 draw_squares();
324 }
326 static void draw_teapot(float size)
327 {
328 static int tealist;
330 if(!tealist) {
331 tealist = glGenLists(1);
332 glNewList(tealist, GL_COMPILE);
333 glutSolidTeapot(1.0);
334 glEndList();
335 }
337 glMatrixMode(GL_MODELVIEW);
338 glPushMatrix();
339 glScalef(size, size, size);
340 glTranslatef(0, 0.73, 0);
342 glFrontFace(GL_CW);
343 glCallList(tealist);
344 glFrontFace(GL_CCW);
346 glPopMatrix();
347 }
349 static void draw_squares()
350 {
351 static const int num_sq = 8;
353 glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT);
354 glDisable(GL_LIGHTING);
356 glMatrixMode(GL_MODELVIEW);
357 glPushMatrix();
358 glTranslatef(0, 1, 0);
361 glLineWidth(2.0);
362 glColor3f(1.0, 0.7, 0.2);
364 float zdist = 2.0;
365 for(int i=0; i<num_sq; i++) {
366 glBegin(GL_LINE_LOOP);
367 glVertex3f(-1, -1, -zdist);
368 glVertex3f(1, -1, -zdist);
369 glVertex3f(1, 1, -zdist);
370 glVertex3f(-1, 1, -zdist);
371 glEnd();
373 zdist += 2.0;
374 }
376 glPopMatrix();
377 glPopAttrib();
378 }
380 static void draw_grid(float size, float spacing)
381 {
382 int num_lines = size / spacing;
383 float dist = size / 2.0;
385 glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT);
386 glDisable(GL_LIGHTING);
388 glLineWidth(1.0);
390 glBegin(GL_LINES);
391 glColor3f(0.4, 0.4, 0.4);
393 float x = -dist;
394 for(int i=0; i<=num_lines; i++) {
395 if(i != num_lines / 2) {
396 glVertex3f(-dist, 0, x);
397 glVertex3f(dist, 0, x);
398 glVertex3f(x, 0, -dist);
399 glVertex3f(x, 0, dist);
400 }
401 x += spacing;
402 }
403 glEnd();
405 glLineWidth(2.0);
407 glBegin(GL_LINES);
408 glColor3f(1.0, 0, 0);
409 glVertex3f(-dist, 0, 0);
410 glVertex3f(dist, 0, 0);
411 glColor3f(0, 1.0, 0);
412 glVertex3f(0, 0, -dist);
413 glVertex3f(0, 0, dist);
414 glEnd();
416 glPopAttrib();
417 }
419 static bool mouselook;
421 static void toggle_mouselook()
422 {
423 mouselook = !mouselook;
424 if(mouselook) {
425 glutPassiveMotionFunc(passive);
426 glutSetCursor(GLUT_CURSOR_NONE);
427 glutWarpPointer(width / 2, height / 2);
428 } else {
429 glutPassiveMotionFunc(0);
430 glutSetCursor(GLUT_CURSOR_INHERIT);
431 }
432 }
434 static void toggle_fullscreen()
435 {
436 static bool fullscreen;
437 static int prev_x, prev_y;
438 static int prev_xsz, prev_ysz;
440 fullscreen = !fullscreen;
442 if(fullscreen) {
443 prev_x = glutGet(GLUT_WINDOW_X);
444 prev_y = glutGet(GLUT_WINDOW_Y);
445 prev_xsz = width;
446 prev_ysz = height;
448 if(use_vr) {
449 // go fullscreen to the correct monitor
450 int x, y;
451 vr_get_display_pos(&x, &y);
452 glutPositionWindow(x, y);
454 // also warp the mouse and enable mouselook
455 glutWarpPointer(x + width / 2, y + height / 2);
457 /* Ok this next line needs some explanation:
458 * glutPositionWindow, doesn't necessarilly get executed directly.
459 * GLUT might defer it for the next round of event processing, just
460 * so that it may coalesce multiple positioning requests.
461 * However that means that if we just called glutFullScreen right
462 * here, the window manager would have no idea that the window will
463 * move to another monitor, thus making it the size of the monitor
464 * it occupied before the move.
465 * So I'm setting a flag here, and execute the glutFullScreen call
466 * at the next idle invocation. (would display be a safer place?).
467 */
468 fullscreen_pending = true;
469 } else {
470 glutFullScreen();
471 toggle_mouselook();
472 }
473 } else {
474 glutReshapeWindow(prev_xsz, prev_ysz);
475 glutPositionWindow(prev_x, prev_y);
477 if(mouselook) {
478 toggle_mouselook();
479 }
480 }
481 glutPostRedisplay();
482 }
485 static void idle()
486 {
487 if(fullscreen_pending) {
488 glutFullScreen();
490 if(!mouselook) {
491 toggle_mouselook();
492 }
493 fullscreen_pending = false;
494 }
495 glutPostRedisplay();
496 }
499 static void reshape(int x, int y)
500 {
501 width = x;
502 height = y;
503 }
505 static void keyb(unsigned char key, int x, int y)
506 {
507 switch(key) {
508 case 27:
509 exit(0);
511 case 'm':
512 toggle_mouselook();
513 break;
515 case 'f':
516 toggle_fullscreen();
517 break;
519 case '\\':
520 {
521 extern bool dbg_enable;
522 dbg_enable = !dbg_enable;
523 }
524 break;
525 }
527 keystate[key] = true;
528 glutPostRedisplay();
529 }
531 static void keyup(unsigned char key, int x, int y)
532 {
533 keystate[key] = false;
534 glutPostRedisplay();
535 }
537 static bool bnstate[32];
538 static int prev_x, prev_y;
540 static void mouse(int bn, int st, int x, int y)
541 {
542 prev_x = x;
543 prev_y = y;
544 bnstate[bn - GLUT_LEFT_BUTTON] = st == GLUT_DOWN;
545 }
547 static void motion(int x, int y)
548 {
549 if(mouselook) {
550 // just call passive, it does what we need
551 passive(x, y);
552 }
553 }
555 static void passive(int x, int y)
556 {
557 // no need to test mouselook; this callback is only set when mouselook is enabled
558 int center_x = width / 2;
559 int center_y = height / 2;
561 int dx = x - center_x;
562 int dy = use_vr ? 0 : y - center_y;
564 if(!dx && !dy) {
565 return;
566 }
568 float dtheta_deg = dy * 0.1;
569 float dphi_deg = dx * 0.1;
571 cam.input_rotate(DEG_TO_RAD(dtheta_deg), DEG_TO_RAD(dphi_deg), 0);
573 glutWarpPointer(center_x, center_y);
574 glutPostRedisplay();
575 }
577 static void sball_rotate(int rx, int ry, int rz)
578 {
579 }
581 static bool parse_args(int argc, char **argv)
582 {
583 for(int i=1; i<argc; i++) {
584 if(argv[i][0] == '-') {
585 if(strcmp(argv[i], "-vr") == 0) {
586 use_vr = true;
587 } else if(strcmp(argv[i], "-novr") == 0) {
588 use_vr = false;
589 } else {
590 fprintf(stderr, "invalid option: %s\n", argv[i]);
591 return false;
592 }
593 } else {
594 fprintf(stderr, "unexpected argument: %s\n", argv[i]);
595 return false;
596 }
597 }
598 return true;
599 }
601 static void printfps()
602 {
603 static unsigned int last_upd, frames;
604 unsigned int msec = glutGet(GLUT_ELAPSED_TIME);
605 unsigned int dmsec = msec - last_upd;
607 frames++;
609 if(dmsec > 2000) {
610 float dt = (float)dmsec / 1000.0f;
612 printf("fps: %.2f \r", (float)frames / dt);
613 fflush(stdout);
615 frames = 0;
616 last_upd = msec;
617 }
618 }
620 static int next_pow2(int x)
621 {
622 x--;
623 x = (x >> 1) | x;
624 x = (x >> 2) | x;
625 x = (x >> 4) | x;
626 x = (x >> 8) | x;
627 x = (x >> 16) | x;
628 return x + 1;
629 }