oculus1

annotate src/main.cc @ 29:9a973ef0e2a3

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