oculus1

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