oculus1

annotate src/main.cc @ 22:251bc9e2e4a1

made mouselook only affect horizontal movement in VR mode
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 28 Sep 2013 04:13:09 +0300
parents f3672317e5c2
children 0c76f70fb7e9
rev   line source
nuclear@0 1 #include <stdio.h>
nuclear@0 2 #include <stdlib.h>
nuclear@1 3 #include <string.h>
nuclear@0 4 #include <assert.h>
nuclear@8 5 #include "opengl.h"
nuclear@1 6 #include "vr.h"
nuclear@0 7 #include "camera.h"
nuclear@16 8 #include "sdr.h"
nuclear@0 9
nuclear@0 10 static bool init();
nuclear@0 11 static void cleanup();
nuclear@0 12 static void disp();
nuclear@16 13 static void disp_vr();
nuclear@9 14 static void draw_scene();
nuclear@16 15 static void draw_teapot(float size);
nuclear@13 16 static void draw_squares();
nuclear@12 17 static void draw_grid(float size, float spacing);
nuclear@16 18 static void toggle_mouselook();
nuclear@16 19 static void toggle_fullscreen();
nuclear@0 20 static void idle();
nuclear@0 21 static void reshape(int x, int y);
nuclear@0 22 static void keyb(unsigned char key, int x, int y);
nuclear@8 23 static void keyup(unsigned char key, int x, int y);
nuclear@8 24 static void mouse(int bn, int st, int x, int y);
nuclear@8 25 static void motion(int x, int y);
nuclear@8 26 static void passive(int x, int y);
nuclear@0 27 static void sball_rotate(int rx, int ry, int rz);
nuclear@1 28 static bool parse_args(int argc, char **argv);
nuclear@0 29
nuclear@10 30 static VRFpsCamera cam;
nuclear@0 31 static int width, height;
nuclear@1 32 static bool use_vr = false;
nuclear@8 33
nuclear@8 34 static bool keystate[256];
nuclear@8 35
nuclear@12 36 static int rtarg_width, rtarg_height;
nuclear@12 37 static unsigned int fbo, tex[2], zbuf;
nuclear@12 38
nuclear@16 39 static unsigned int teapot_sdr;
nuclear@16 40
nuclear@16 41 static bool fullscreen_pending;
nuclear@16 42
nuclear@0 43 int main(int argc, char **argv)
nuclear@0 44 {
nuclear@3 45 glutInitWindowSize(1280, 800);
nuclear@0 46 glutInit(&argc, argv);
nuclear@1 47
nuclear@1 48 if(!parse_args(argc, argv)) {
nuclear@1 49 return 1;
nuclear@1 50 }
nuclear@1 51
nuclear@12 52 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
nuclear@12 53 glutCreateWindow("oculus vr test 01");
nuclear@12 54
nuclear@12 55 width = glutGet(GLUT_WINDOW_WIDTH);
nuclear@12 56 height = glutGet(GLUT_WINDOW_HEIGHT);
nuclear@0 57
nuclear@16 58 glutDisplayFunc(use_vr ? disp_vr : disp);
nuclear@0 59 glutIdleFunc(idle);
nuclear@0 60 glutReshapeFunc(reshape);
nuclear@0 61 glutKeyboardFunc(keyb);
nuclear@8 62 glutKeyboardUpFunc(keyup);
nuclear@8 63 glutMouseFunc(mouse);
nuclear@8 64 glutMotionFunc(motion);
nuclear@0 65 glutSpaceballRotateFunc(sball_rotate);
nuclear@0 66
nuclear@0 67 if(!init()) {
nuclear@0 68 return 1;
nuclear@0 69 }
nuclear@0 70 atexit(cleanup);
nuclear@0 71
nuclear@0 72 glutMainLoop();
nuclear@0 73 return 0;
nuclear@0 74 }
nuclear@0 75
nuclear@0 76 static bool init()
nuclear@0 77 {
nuclear@9 78 glewInit(); // this must be first
nuclear@9 79
nuclear@0 80 glEnable(GL_DEPTH_TEST);
nuclear@0 81 glEnable(GL_LIGHTING);
nuclear@0 82 glEnable(GL_CULL_FACE);
nuclear@0 83
nuclear@0 84 glEnable(GL_LIGHT0);
nuclear@0 85 glEnable(GL_LIGHTING);
nuclear@16 86 glEnable(GL_NORMALIZE);
nuclear@0 87
nuclear@11 88 // y = height of neck
nuclear@11 89 cam.input_move(0, 1.65, 0);
nuclear@9 90
nuclear@12 91 if(use_vr) {
nuclear@12 92 if(vr_init(VR_INIT_OCULUS) == -1) {
nuclear@12 93 return false;
nuclear@12 94 }
nuclear@12 95
nuclear@12 96 // reshape to the size of the VR display
nuclear@12 97 int xsz = vr_get_width();
nuclear@12 98 int ysz = vr_get_height();
nuclear@12 99
nuclear@12 100 glutReshapeWindow(xsz, ysz);
nuclear@12 101
nuclear@12 102 rtarg_width = (xsz + xsz / 2) / 2;
nuclear@12 103 rtarg_height = ysz + ysz / 2;
nuclear@16 104
nuclear@16 105 printf("render target: %dx%d\n", rtarg_width, rtarg_height);
nuclear@16 106
nuclear@16 107 // create render targets for each eye
nuclear@16 108 GLenum wrap_mode = GL_CLAMP_TO_EDGE;
nuclear@16 109 if(!GLEW_SGIS_texture_edge_clamp) {
nuclear@16 110 wrap_mode = GL_CLAMP;
nuclear@16 111 }
nuclear@16 112
nuclear@16 113 glGenTextures(2, tex);
nuclear@16 114 for(int i=0; i<2; i++) {
nuclear@16 115 glBindTexture(GL_TEXTURE_2D, tex[i]);
nuclear@16 116 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
nuclear@16 117 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
nuclear@16 118 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_mode);
nuclear@16 119 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_mode);
nuclear@16 120 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, rtarg_width, rtarg_height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
nuclear@16 121 }
nuclear@16 122
nuclear@16 123 // create the depth render buffer
nuclear@16 124 glGenRenderbuffers(1, &zbuf);
nuclear@16 125 glBindRenderbuffer(GL_RENDERBUFFER, zbuf);
nuclear@16 126 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, rtarg_width, rtarg_height);
nuclear@16 127
nuclear@16 128 // create the FBO
nuclear@16 129 glGenFramebuffers(1, &fbo);
nuclear@16 130 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
nuclear@16 131 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex[0], 0);
nuclear@16 132 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, zbuf);
nuclear@0 133 }
nuclear@12 134
nuclear@16 135 teapot_sdr = create_program_load("sdr/phong.v.glsl", "sdr/phong.p.glsl");
nuclear@12 136
nuclear@0 137 return true;
nuclear@0 138 }
nuclear@0 139
nuclear@0 140 static void cleanup()
nuclear@0 141 {
nuclear@12 142 glDeleteTextures(2, tex);
nuclear@12 143 glDeleteRenderbuffers(1, &zbuf);
nuclear@12 144 glDeleteFramebuffers(1, &fbo);
nuclear@1 145 vr_shutdown();
nuclear@0 146 }
nuclear@0 147
nuclear@14 148 static void handle_input(float dt)
nuclear@14 149 {
nuclear@14 150 Vector3 inpv;
nuclear@14 151 float offs = dt * 2.0;
nuclear@14 152
nuclear@14 153 if(keystate['w'] || keystate['W']) {
nuclear@14 154 inpv.z -= offs;
nuclear@14 155 }
nuclear@14 156 if(keystate['s'] || keystate['S']) {
nuclear@14 157 inpv.z += offs;
nuclear@14 158 }
nuclear@14 159 if(keystate['d'] || keystate['D']) {
nuclear@14 160 inpv.x += offs;
nuclear@14 161 }
nuclear@14 162 if(keystate['a'] || keystate['A']) {
nuclear@14 163 inpv.x -= offs;
nuclear@14 164 }
nuclear@14 165
nuclear@14 166 cam.input_move(inpv.x, inpv.y, inpv.z);
nuclear@14 167 }
nuclear@14 168
nuclear@16 169 // display function used in regular mode
nuclear@0 170 static void disp()
nuclear@0 171 {
nuclear@14 172 static long prev_msec;
nuclear@14 173 long msec = glutGet(GLUT_ELAPSED_TIME);
nuclear@14 174 float dt = (msec - prev_msec) / 1000.0;
nuclear@14 175 prev_msec = msec;
nuclear@4 176
nuclear@14 177 handle_input(dt);
nuclear@16 178
nuclear@16 179 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
nuclear@16 180
nuclear@16 181 glMatrixMode(GL_PROJECTION);
nuclear@16 182 glLoadIdentity();
nuclear@16 183 gluPerspective(45, (float)width / (float)height, 0.25, 500.0);
nuclear@16 184
nuclear@16 185 glMatrixMode(GL_MODELVIEW);
nuclear@16 186 glLoadIdentity();
nuclear@16 187 cam.use_inverse();
nuclear@16 188 draw_scene();
nuclear@16 189
nuclear@16 190 glutSwapBuffers();
nuclear@16 191 assert(glGetError() == GL_NO_ERROR);
nuclear@16 192 }
nuclear@16 193
nuclear@16 194 // display function used in VR mode
nuclear@16 195 static void disp_vr()
nuclear@16 196 {
nuclear@16 197 static long prev_msec;
nuclear@16 198 long msec = glutGet(GLUT_ELAPSED_TIME);
nuclear@16 199 float dt = (msec - prev_msec) / 1000.0;
nuclear@16 200 prev_msec = msec;
nuclear@16 201
nuclear@16 202 handle_input(dt);
nuclear@12 203 cam.track_vr();
nuclear@0 204
nuclear@13 205 float proj_matrix[16];
nuclear@13 206
nuclear@13 207 float eye_dist = vr_get_eyedist();
nuclear@12 208
nuclear@12 209 glViewport(0, 0, rtarg_width, rtarg_height);
nuclear@12 210
nuclear@12 211 glClearColor(0.1, 0.1, 0.1, 1.0);
nuclear@12 212
nuclear@12 213 // draw left view
nuclear@12 214 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
nuclear@12 215 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex[0], 0);
nuclear@12 216
nuclear@12 217 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
nuclear@0 218
nuclear@13 219 glMatrixMode(GL_PROJECTION);
nuclear@13 220 vr_get_proj_matrix(proj_matrix, VR_EYE_LEFT);
nuclear@13 221 glLoadTransposeMatrixf(proj_matrix);
nuclear@13 222
nuclear@0 223 glMatrixMode(GL_MODELVIEW);
nuclear@9 224 glLoadIdentity();
nuclear@13 225 glTranslatef(eye_dist / 2.0, 0, 0);
nuclear@12 226 cam.use_inverse();
nuclear@12 227 draw_scene();
nuclear@0 228
nuclear@12 229
nuclear@12 230 // draw right view
nuclear@12 231 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
nuclear@12 232 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex[1], 0);
nuclear@12 233
nuclear@12 234 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
nuclear@12 235
nuclear@13 236 glMatrixMode(GL_PROJECTION);
nuclear@13 237 vr_get_proj_matrix(proj_matrix, VR_EYE_RIGHT);
nuclear@13 238 glLoadTransposeMatrixf(proj_matrix);
nuclear@13 239
nuclear@12 240 glMatrixMode(GL_MODELVIEW);
nuclear@12 241 glLoadIdentity();
nuclear@13 242 glTranslatef(-eye_dist / 2.0, 0, 0);
nuclear@9 243 cam.use_inverse();
nuclear@12 244 draw_scene();
nuclear@9 245
nuclear@12 246 // return to the regular window framebuffer
nuclear@12 247 glBindFramebuffer(GL_FRAMEBUFFER, 0);
nuclear@12 248 glViewport(0, 0, width, height);
nuclear@12 249
nuclear@12 250 glClearColor(0, 0, 0, 0);
nuclear@12 251 glClear(GL_COLOR_BUFFER_BIT);
nuclear@12 252
nuclear@12 253 vr_draw_eye(tex[0], VR_EYE_LEFT);
nuclear@12 254 vr_draw_eye(tex[1], VR_EYE_RIGHT);
nuclear@9 255
nuclear@9 256 glutSwapBuffers();
nuclear@9 257 assert(glGetError() == GL_NO_ERROR);
nuclear@13 258
nuclear@13 259 glFinish();
nuclear@9 260 }
nuclear@9 261
nuclear@12 262 static void draw_scene()
nuclear@12 263 {
nuclear@12 264 float lpos[] = {0, 60, 0, 1};
nuclear@12 265 glLightfv(GL_LIGHT0, GL_POSITION, lpos);
nuclear@12 266
nuclear@14 267 draw_grid(50.0, 2.5);
nuclear@13 268
nuclear@16 269 static const Vector2 teapos[] = {
nuclear@16 270 Vector2(-8, -8), Vector2(8, -8), Vector2(8, 8), Vector2(-8, 8)
nuclear@12 271 };
nuclear@16 272 static const float teasize[] = { 1.0, 2.0, 1.7, 1.4 };
nuclear@16 273 static const float teacolor[][4] = {
nuclear@16 274 {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}
nuclear@16 275 };
nuclear@16 276 static const float spec[] = {0.8, 0.8, 0.8, 1.0};
nuclear@16 277
nuclear@16 278 glUseProgram(teapot_sdr);
nuclear@12 279
nuclear@12 280 for(int i=0; i<4; i++) {
nuclear@16 281 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, teacolor[i]);
nuclear@16 282 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
nuclear@16 283 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 70.0);
nuclear@16 284
nuclear@12 285 glPushMatrix();
nuclear@12 286 glTranslatef(teapos[i].x, 0, teapos[i].y);
nuclear@16 287 draw_teapot(teasize[i]);
nuclear@12 288 glPopMatrix();
nuclear@12 289 }
nuclear@16 290 glUseProgram(0);
nuclear@12 291
nuclear@13 292 draw_squares();
nuclear@12 293 }
nuclear@12 294
nuclear@16 295 static void draw_teapot(float size)
nuclear@9 296 {
nuclear@9 297 static int tealist;
nuclear@9 298
nuclear@9 299 if(!tealist) {
nuclear@9 300 tealist = glGenLists(1);
nuclear@9 301 glNewList(tealist, GL_COMPILE);
nuclear@9 302 glutSolidTeapot(1.0);
nuclear@9 303 glEndList();
nuclear@9 304 }
nuclear@9 305
nuclear@16 306 glMatrixMode(GL_MODELVIEW);
nuclear@16 307 glPushMatrix();
nuclear@16 308 glScalef(size, size, size);
nuclear@16 309 glTranslatef(0, 0.73, 0);
nuclear@16 310
nuclear@9 311 glFrontFace(GL_CW);
nuclear@9 312 glCallList(tealist);
nuclear@9 313 glFrontFace(GL_CCW);
nuclear@16 314
nuclear@16 315 glPopMatrix();
nuclear@9 316 }
nuclear@9 317
nuclear@13 318 static void draw_squares()
nuclear@13 319 {
nuclear@14 320 static const int num_sq = 8;
nuclear@13 321
nuclear@13 322 glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT);
nuclear@13 323 glDisable(GL_LIGHTING);
nuclear@13 324
nuclear@13 325 glMatrixMode(GL_MODELVIEW);
nuclear@13 326 glPushMatrix();
nuclear@13 327 glTranslatef(0, 1, 0);
nuclear@13 328
nuclear@13 329
nuclear@14 330 glLineWidth(2.0);
nuclear@13 331 glColor3f(1.0, 0.7, 0.2);
nuclear@13 332
nuclear@13 333 float zdist = 2.0;
nuclear@13 334 for(int i=0; i<num_sq; i++) {
nuclear@13 335 glBegin(GL_LINE_LOOP);
nuclear@13 336 glVertex3f(-1, -1, -zdist);
nuclear@13 337 glVertex3f(1, -1, -zdist);
nuclear@13 338 glVertex3f(1, 1, -zdist);
nuclear@13 339 glVertex3f(-1, 1, -zdist);
nuclear@13 340 glEnd();
nuclear@13 341
nuclear@14 342 zdist += 2.0;
nuclear@13 343 }
nuclear@13 344
nuclear@13 345 glPopMatrix();
nuclear@13 346 glPopAttrib();
nuclear@13 347 }
nuclear@13 348
nuclear@12 349 static void draw_grid(float size, float spacing)
nuclear@9 350 {
nuclear@9 351 int num_lines = size / spacing;
nuclear@9 352 float dist = size / 2.0;
nuclear@9 353
nuclear@9 354 glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT);
nuclear@9 355 glDisable(GL_LIGHTING);
nuclear@9 356
nuclear@9 357 glLineWidth(1.0);
nuclear@9 358
nuclear@9 359 glBegin(GL_LINES);
nuclear@9 360 glColor3f(0.4, 0.4, 0.4);
nuclear@9 361
nuclear@9 362 float x = -dist;
nuclear@9 363 for(int i=0; i<=num_lines; i++) {
nuclear@9 364 if(i != num_lines / 2) {
nuclear@9 365 glVertex3f(-dist, 0, x);
nuclear@9 366 glVertex3f(dist, 0, x);
nuclear@9 367 glVertex3f(x, 0, -dist);
nuclear@9 368 glVertex3f(x, 0, dist);
nuclear@9 369 }
nuclear@9 370 x += spacing;
nuclear@9 371 }
nuclear@9 372 glEnd();
nuclear@9 373
nuclear@9 374 glLineWidth(2.0);
nuclear@9 375
nuclear@9 376 glBegin(GL_LINES);
nuclear@9 377 glColor3f(1.0, 0, 0);
nuclear@9 378 glVertex3f(-dist, 0, 0);
nuclear@9 379 glVertex3f(dist, 0, 0);
nuclear@9 380 glColor3f(0, 1.0, 0);
nuclear@9 381 glVertex3f(0, 0, -dist);
nuclear@9 382 glVertex3f(0, 0, dist);
nuclear@9 383 glEnd();
nuclear@9 384
nuclear@9 385 glPopAttrib();
nuclear@9 386 }
nuclear@9 387
nuclear@16 388 static bool mouselook;
nuclear@16 389
nuclear@16 390 static void toggle_mouselook()
nuclear@16 391 {
nuclear@16 392 mouselook = !mouselook;
nuclear@16 393 if(mouselook) {
nuclear@16 394 glutPassiveMotionFunc(passive);
nuclear@16 395 glutSetCursor(GLUT_CURSOR_NONE);
nuclear@16 396 glutWarpPointer(width / 2, height / 2);
nuclear@16 397 } else {
nuclear@16 398 glutPassiveMotionFunc(0);
nuclear@16 399 glutSetCursor(GLUT_CURSOR_INHERIT);
nuclear@16 400 }
nuclear@16 401 }
nuclear@16 402
nuclear@22 403 static bool fullscreen;
nuclear@16 404 static void toggle_fullscreen()
nuclear@16 405 {
nuclear@16 406 static int prev_x, prev_y;
nuclear@16 407 static int prev_xsz, prev_ysz;
nuclear@16 408
nuclear@16 409 fullscreen = !fullscreen;
nuclear@16 410
nuclear@16 411 if(fullscreen) {
nuclear@16 412 prev_x = glutGet(GLUT_WINDOW_X);
nuclear@16 413 prev_y = glutGet(GLUT_WINDOW_Y);
nuclear@16 414 prev_xsz = width;
nuclear@16 415 prev_ysz = height;
nuclear@16 416
nuclear@16 417 if(use_vr) {
nuclear@16 418 // go fullscreen to the correct monitor
nuclear@16 419 int x, y;
nuclear@16 420 vr_get_display_pos(&x, &y);
nuclear@16 421 glutPositionWindow(x, y);
nuclear@16 422
nuclear@16 423 // also warp the mouse and enable mouselook
nuclear@16 424 glutWarpPointer(x + width / 2, y + height / 2);
nuclear@16 425
nuclear@16 426 /* Ok this next line needs some explanation:
nuclear@16 427 * glutPositionWindow, doesn't necessarilly get executed directly.
nuclear@16 428 * GLUT might defer it for the next round of event processing, just
nuclear@16 429 * so that it may coalesce multiple positioning requests.
nuclear@16 430 * However that means that if we just called glutFullScreen right
nuclear@16 431 * here, the window manager would have no idea that the window will
nuclear@16 432 * move to another monitor, thus making it the size of the monitor
nuclear@16 433 * it occupied before the move.
nuclear@16 434 * So I'm setting a flag here, and execute the glutFullScreen call
nuclear@16 435 * at the next idle invocation. (would display be a safer place?).
nuclear@16 436 */
nuclear@16 437 fullscreen_pending = true;
nuclear@16 438 } else {
nuclear@16 439 glutFullScreen();
nuclear@16 440 toggle_mouselook();
nuclear@16 441 }
nuclear@16 442 } else {
nuclear@16 443 glutReshapeWindow(prev_xsz, prev_ysz);
nuclear@16 444 glutPositionWindow(prev_x, prev_y);
nuclear@16 445
nuclear@16 446 if(mouselook) {
nuclear@16 447 toggle_mouselook();
nuclear@16 448 }
nuclear@16 449 }
nuclear@16 450 glutPostRedisplay();
nuclear@16 451 }
nuclear@16 452
nuclear@16 453
nuclear@0 454 static void idle()
nuclear@0 455 {
nuclear@16 456 if(fullscreen_pending) {
nuclear@16 457 glutFullScreen();
nuclear@16 458
nuclear@16 459 if(!mouselook) {
nuclear@16 460 toggle_mouselook();
nuclear@16 461 }
nuclear@16 462 fullscreen_pending = false;
nuclear@16 463 }
nuclear@0 464 glutPostRedisplay();
nuclear@0 465 }
nuclear@0 466
nuclear@0 467
nuclear@0 468 static void reshape(int x, int y)
nuclear@0 469 {
nuclear@0 470 width = x;
nuclear@0 471 height = y;
nuclear@12 472
nuclear@12 473 if(!use_vr) {
nuclear@12 474 rtarg_width = width;
nuclear@12 475 rtarg_height = height;
nuclear@12 476 }
nuclear@0 477 }
nuclear@0 478
nuclear@0 479 static void keyb(unsigned char key, int x, int y)
nuclear@0 480 {
nuclear@0 481 switch(key) {
nuclear@0 482 case 27:
nuclear@0 483 exit(0);
nuclear@8 484
nuclear@8 485 case 'm':
nuclear@16 486 toggle_mouselook();
nuclear@8 487 break;
nuclear@12 488
nuclear@12 489 case 'f':
nuclear@16 490 toggle_fullscreen();
nuclear@12 491 break;
nuclear@0 492 }
nuclear@8 493
nuclear@8 494 keystate[key] = true;
nuclear@8 495 glutPostRedisplay();
nuclear@8 496 }
nuclear@8 497
nuclear@8 498 static void keyup(unsigned char key, int x, int y)
nuclear@8 499 {
nuclear@8 500 keystate[key] = false;
nuclear@8 501 glutPostRedisplay();
nuclear@8 502 }
nuclear@8 503
nuclear@8 504 static bool bnstate[32];
nuclear@8 505 static int prev_x, prev_y;
nuclear@8 506
nuclear@8 507 static void mouse(int bn, int st, int x, int y)
nuclear@8 508 {
nuclear@8 509 prev_x = x;
nuclear@8 510 prev_y = y;
nuclear@8 511 bnstate[bn - GLUT_LEFT_BUTTON] = st == GLUT_DOWN;
nuclear@8 512 }
nuclear@8 513
nuclear@8 514 static void motion(int x, int y)
nuclear@8 515 {
nuclear@8 516 if(mouselook) {
nuclear@8 517 // just call passive, it does what we need
nuclear@8 518 passive(x, y);
nuclear@8 519 }
nuclear@8 520 }
nuclear@8 521
nuclear@8 522 static void passive(int x, int y)
nuclear@8 523 {
nuclear@8 524 // no need to test mouselook; this callback is only set when mouselook is enabled
nuclear@8 525 int center_x = width / 2;
nuclear@8 526 int center_y = height / 2;
nuclear@8 527
nuclear@8 528 int dx = x - center_x;
nuclear@8 529 int dy = y - center_y;
nuclear@8 530
nuclear@22 531 if(use_vr && fullscreen) {
nuclear@22 532 dy = 0;
nuclear@22 533 }
nuclear@22 534
nuclear@8 535 if(!dx && !dy) {
nuclear@8 536 return;
nuclear@8 537 }
nuclear@8 538
nuclear@9 539 float dtheta_deg = dy * 0.1;
nuclear@9 540 float dphi_deg = dx * 0.1;
nuclear@9 541
nuclear@9 542 cam.input_rotate(DEG_TO_RAD(dtheta_deg), DEG_TO_RAD(dphi_deg), 0);
nuclear@9 543
nuclear@8 544 glutPostRedisplay();
nuclear@8 545 glutWarpPointer(center_x, center_y);
nuclear@0 546 }
nuclear@0 547
nuclear@0 548 static void sball_rotate(int rx, int ry, int rz)
nuclear@0 549 {
nuclear@0 550 }
nuclear@1 551
nuclear@1 552 static bool parse_args(int argc, char **argv)
nuclear@1 553 {
nuclear@1 554 for(int i=1; i<argc; i++) {
nuclear@1 555 if(argv[i][0] == '-') {
nuclear@1 556 if(strcmp(argv[i], "-vr") == 0) {
nuclear@1 557 use_vr = true;
nuclear@1 558 } else if(strcmp(argv[i], "-novr") == 0) {
nuclear@1 559 use_vr = false;
nuclear@1 560 } else {
nuclear@1 561 fprintf(stderr, "invalid option: %s\n", argv[i]);
nuclear@1 562 return false;
nuclear@1 563 }
nuclear@1 564 } else {
nuclear@1 565 fprintf(stderr, "unexpected argument: %s\n", argv[i]);
nuclear@1 566 return false;
nuclear@1 567 }
nuclear@1 568 }
nuclear@1 569 return true;
nuclear@1 570 }