oculus2_psprite

annotate src/main.c @ 23:fe9600396f65

fixed visual studio project
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 22 Jan 2015 14:03:24 +0200
parents dc7af0f549b2
children
rev   line source
nuclear@0 1 #include <stdio.h>
nuclear@0 2 #include <stdlib.h>
nuclear@2 3 #include <assert.h>
nuclear@0 4 #include <SDL2/SDL.h>
nuclear@0 5 #include <GL/glew.h>
nuclear@0 6
nuclear@2 7 #ifdef WIN32
nuclear@2 8 #define OVR_OS_WIN32
nuclear@10 9 #elif defined(__APPLE__)
nuclear@2 10 #define OVR_OS_MAC
nuclear@10 11 #else
nuclear@10 12 #define OVR_OS_LINUX
nuclear@14 13 #include <X11/Xlib.h>
nuclear@14 14 #include <GL/glx.h>
nuclear@2 15 #endif
nuclear@2 16
nuclear@0 17 #include <OVR_CAPI.h>
nuclear@0 18 #include <OVR_CAPI_GL.h>
nuclear@21 19 #include "projectile.h"
nuclear@21 20
nuclear@21 21 #define GUN_Y 1.5
nuclear@0 22
nuclear@2 23 int init(void);
nuclear@21 24 int init_rift(void);
nuclear@2 25 void cleanup(void);
nuclear@4 26 void toggle_hmd_fullscreen(void);
nuclear@2 27 void display(void);
nuclear@21 28 void display_rift(void);
nuclear@2 29 void draw_scene(void);
nuclear@2 30 void draw_box(float xsz, float ysz, float zsz, float norm_sign);
nuclear@0 31 void update_rtarg(int width, int height);
nuclear@0 32 int handle_event(SDL_Event *ev);
nuclear@0 33 int key_event(int key, int state);
nuclear@0 34 void reshape(int x, int y);
nuclear@0 35 unsigned int next_pow2(unsigned int x);
nuclear@4 36 void quat_to_matrix(const float *quat, float *mat);
nuclear@4 37 unsigned int gen_chess_tex(float r0, float g0, float b0, float r1, float g1, float b1);
nuclear@21 38 int parse_args(int argc, char **argv);
nuclear@0 39
nuclear@4 40 /* forward declaration to avoid including non-public headers of libovr */
nuclear@0 41 OVR_EXPORT void ovrhmd_EnableHSWDisplaySDKRender(ovrHmd hmd, ovrBool enable);
nuclear@0 42
nuclear@0 43 static SDL_Window *win;
nuclear@0 44 static SDL_GLContext ctx;
nuclear@2 45 static int win_width, win_height;
nuclear@0 46
nuclear@0 47 static unsigned int fbo, fb_tex, fb_depth;
nuclear@0 48 static int fb_width, fb_height;
nuclear@0 49 static int fb_tex_width, fb_tex_height;
nuclear@0 50
nuclear@21 51 static int use_rift = 1;
nuclear@0 52 static ovrHmd hmd;
nuclear@0 53 static ovrSizei eyeres[2];
nuclear@2 54 static ovrEyeRenderDesc eye_rdesc[2];
nuclear@2 55 static ovrGLTexture fb_ovr_tex[2];
nuclear@15 56 static union ovrGLConfig glcfg;
nuclear@15 57 static unsigned int distort_caps;
nuclear@15 58 static unsigned int hmd_caps;
nuclear@0 59
nuclear@4 60 static unsigned int chess_tex;
nuclear@0 61
nuclear@21 62 static float cam_theta, cam_phi;
nuclear@21 63
nuclear@4 64
nuclear@4 65 int main(int argc, char **argv)
nuclear@0 66 {
nuclear@23 67 unsigned int msec, prev_frame_msec = 0;
nuclear@21 68
nuclear@21 69 if(parse_args(argc, argv) == -1) {
nuclear@21 70 return 1;
nuclear@21 71 }
nuclear@0 72 if(init() == -1) {
nuclear@0 73 return 1;
nuclear@0 74 }
nuclear@0 75
nuclear@0 76 for(;;) {
nuclear@0 77 SDL_Event ev;
nuclear@0 78 while(SDL_PollEvent(&ev)) {
nuclear@0 79 if(handle_event(&ev) == -1) {
nuclear@0 80 goto done;
nuclear@0 81 }
nuclear@0 82 }
nuclear@21 83
nuclear@21 84 msec = SDL_GetTicks();
nuclear@21 85 update_shots((msec - prev_frame_msec) / 1000.0);
nuclear@21 86 prev_frame_msec = msec;
nuclear@21 87
nuclear@21 88 if(use_rift) {
nuclear@21 89 display_rift();
nuclear@21 90 } else {
nuclear@21 91 display();
nuclear@21 92 }
nuclear@0 93 }
nuclear@0 94
nuclear@0 95 done:
nuclear@0 96 cleanup();
nuclear@0 97 return 0;
nuclear@0 98 }
nuclear@0 99
nuclear@0 100
nuclear@2 101 int init(void)
nuclear@0 102 {
nuclear@21 103 int x, y;
nuclear@15 104 unsigned int flags;
nuclear@0 105
nuclear@21 106 if(use_rift) {
nuclear@21 107 /* libovr must be initialized before we create the OpenGL context */
nuclear@21 108 ovr_Initialize();
nuclear@21 109 }
nuclear@0 110
nuclear@0 111 SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
nuclear@0 112
nuclear@0 113 x = y = SDL_WINDOWPOS_UNDEFINED;
nuclear@2 114 flags = SDL_WINDOW_OPENGL;
nuclear@20 115 if(!(win = SDL_CreateWindow("press 'f' to move to the HMD", x, y, 1024, 640, flags))) {
nuclear@0 116 fprintf(stderr, "failed to create window\n");
nuclear@0 117 return -1;
nuclear@0 118 }
nuclear@0 119 if(!(ctx = SDL_GL_CreateContext(win))) {
nuclear@0 120 fprintf(stderr, "failed to create OpenGL context\n");
nuclear@0 121 return -1;
nuclear@0 122 }
nuclear@0 123
nuclear@0 124 glewInit();
nuclear@0 125
nuclear@21 126 if(use_rift && init_rift() == -1) {
nuclear@21 127 return -1;
nuclear@21 128 }
nuclear@21 129
nuclear@21 130 if(init_shots() == -1) {
nuclear@21 131 return -1;
nuclear@21 132 }
nuclear@21 133
nuclear@21 134 glEnable(GL_DEPTH_TEST);
nuclear@21 135 glEnable(GL_CULL_FACE);
nuclear@21 136 glEnable(GL_LIGHTING);
nuclear@21 137 glEnable(GL_LIGHT0);
nuclear@21 138 glEnable(GL_LIGHT1);
nuclear@21 139 glEnable(GL_NORMALIZE);
nuclear@21 140
nuclear@21 141 glClearColor(0.1, 0.1, 0.1, 1);
nuclear@21 142
nuclear@21 143 chess_tex = gen_chess_tex(1.0, 0.7, 0.4, 0.4, 0.7, 1.0);
nuclear@21 144 return 0;
nuclear@21 145 }
nuclear@21 146
nuclear@21 147 int init_rift(void)
nuclear@21 148 {
nuclear@21 149 int i;
nuclear@21 150
nuclear@0 151 if(!(hmd = ovrHmd_Create(0))) {
nuclear@0 152 fprintf(stderr, "failed to open Oculus HMD, falling back to virtual debug HMD\n");
nuclear@2 153 if(!(hmd = ovrHmd_CreateDebug(ovrHmd_DK2))) {
nuclear@0 154 fprintf(stderr, "failed to create virtual debug HMD\n");
nuclear@0 155 return -1;
nuclear@0 156 }
nuclear@0 157 }
nuclear@0 158 printf("initialized HMD: %s - %s\n", hmd->Manufacturer, hmd->ProductName);
nuclear@0 159
nuclear@5 160 /* resize our window to match the HMD resolution */
nuclear@2 161 SDL_SetWindowSize(win, hmd->Resolution.w, hmd->Resolution.h);
nuclear@4 162 SDL_SetWindowPosition(win, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
nuclear@4 163 win_width = hmd->Resolution.w;
nuclear@4 164 win_height = hmd->Resolution.h;
nuclear@0 165
nuclear@11 166 /* enable position and rotation tracking */
nuclear@11 167 ovrHmd_ConfigureTracking(hmd, ovrTrackingCap_Orientation | ovrTrackingCap_MagYawCorrection | ovrTrackingCap_Position, 0);
nuclear@5 168 /* retrieve the optimal render target resolution for each eye */
nuclear@0 169 eyeres[0] = ovrHmd_GetFovTextureSize(hmd, ovrEye_Left, hmd->DefaultEyeFov[0], 1.0);
nuclear@0 170 eyeres[1] = ovrHmd_GetFovTextureSize(hmd, ovrEye_Right, hmd->DefaultEyeFov[1], 1.0);
nuclear@0 171
nuclear@5 172 /* and create a single render target texture to encompass both eyes */
nuclear@2 173 fb_width = eyeres[0].w + eyeres[1].w;
nuclear@0 174 fb_height = eyeres[0].h > eyeres[1].h ? eyeres[0].h : eyeres[1].h;
nuclear@0 175 update_rtarg(fb_width, fb_height);
nuclear@0 176
nuclear@5 177 /* fill in the ovrGLTexture structures that describe our render target texture */
nuclear@2 178 for(i=0; i<2; i++) {
nuclear@2 179 fb_ovr_tex[i].OGL.Header.API = ovrRenderAPI_OpenGL;
nuclear@2 180 fb_ovr_tex[i].OGL.Header.TextureSize.w = fb_tex_width;
nuclear@2 181 fb_ovr_tex[i].OGL.Header.TextureSize.h = fb_tex_height;
nuclear@5 182 /* this next field is the only one that differs between the two eyes */
nuclear@3 183 fb_ovr_tex[i].OGL.Header.RenderViewport.Pos.x = i == 0 ? 0 : fb_width / 2.0;
nuclear@15 184 fb_ovr_tex[i].OGL.Header.RenderViewport.Pos.y = 0;
nuclear@2 185 fb_ovr_tex[i].OGL.Header.RenderViewport.Size.w = fb_width / 2.0;
nuclear@2 186 fb_ovr_tex[i].OGL.Header.RenderViewport.Size.h = fb_height;
nuclear@5 187 fb_ovr_tex[i].OGL.TexId = fb_tex; /* both eyes will use the same texture id */
nuclear@2 188 }
nuclear@2 189
nuclear@5 190 /* fill in the ovrGLConfig structure needed by the SDK to draw our stereo pair
nuclear@5 191 * to the actual HMD display (SDK-distortion mode)
nuclear@5 192 */
nuclear@0 193 memset(&glcfg, 0, sizeof glcfg);
nuclear@0 194 glcfg.OGL.Header.API = ovrRenderAPI_OpenGL;
nuclear@20 195 glcfg.OGL.Header.BackBufferSize.w = win_width;
nuclear@20 196 glcfg.OGL.Header.BackBufferSize.h = win_height;
nuclear@0 197 glcfg.OGL.Header.Multisample = 1;
nuclear@0 198
nuclear@20 199 #ifdef OVR_OS_WIN32
nuclear@11 200 glcfg.OGL.Window = GetActiveWindow();
nuclear@11 201 glcfg.OGL.DC = wglGetCurrentDC();
nuclear@20 202 #elif defined(OVR_OS_LINUX)
nuclear@11 203 glcfg.OGL.Disp = glXGetCurrentDisplay();
nuclear@11 204 #endif
nuclear@11 205
nuclear@0 206 if(hmd->HmdCaps & ovrHmdCap_ExtendDesktop) {
nuclear@0 207 printf("running in \"extended desktop\" mode\n");
nuclear@0 208 } else {
nuclear@5 209 /* to sucessfully draw to the HMD display in "direct-hmd" mode, we have to
nuclear@5 210 * call ovrHmd_AttachToWindow
nuclear@5 211 * XXX: this doesn't work properly yet due to bugs in the oculus 0.4.1 sdk/driver
nuclear@5 212 */
nuclear@2 213 #ifdef WIN32
nuclear@11 214 ovrHmd_AttachToWindow(hmd, glcfg.OGL.Window, 0, 0);
nuclear@20 215 #elif defined(OVR_OS_LINUX)
nuclear@19 216 ovrHmd_AttachToWindow(hmd, (void*)glXGetCurrentDrawable(), 0, 0);
nuclear@2 217 #endif
nuclear@0 218 printf("running in \"direct-hmd\" mode\n");
nuclear@0 219 }
nuclear@5 220
nuclear@5 221 /* enable low-persistence display and dynamic prediction for lattency compensation */
nuclear@15 222 hmd_caps = ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction;
nuclear@15 223 ovrHmd_SetEnabledCaps(hmd, hmd_caps);
nuclear@0 224
nuclear@5 225 /* configure SDK-rendering and enable chromatic abberation correction, vignetting, and
nuclear@5 226 * timewrap, which shifts the image before drawing to counter any lattency between the call
nuclear@5 227 * to ovrHmd_GetEyePose and ovrHmd_EndFrame.
nuclear@5 228 */
nuclear@20 229 distort_caps = ovrDistortionCap_Chromatic | ovrDistortionCap_TimeWarp |
nuclear@7 230 ovrDistortionCap_Overdrive;
nuclear@15 231 if(!ovrHmd_ConfigureRendering(hmd, &glcfg.Config, distort_caps, hmd->DefaultEyeFov, eye_rdesc)) {
nuclear@0 232 fprintf(stderr, "failed to configure distortion renderer\n");
nuclear@0 233 }
nuclear@0 234
nuclear@5 235 /* disable the retarded "health and safety warning" */
nuclear@3 236 ovrhmd_EnableHSWDisplaySDKRender(hmd, 0);
nuclear@0 237 return 0;
nuclear@0 238 }
nuclear@0 239
nuclear@2 240 void cleanup(void)
nuclear@0 241 {
nuclear@21 242 if(use_rift) {
nuclear@21 243 if(hmd) {
nuclear@21 244 ovrHmd_Destroy(hmd);
nuclear@21 245 }
nuclear@21 246 ovr_Shutdown();
nuclear@0 247 }
nuclear@0 248
nuclear@0 249 SDL_Quit();
nuclear@0 250 }
nuclear@0 251
nuclear@4 252 void toggle_hmd_fullscreen(void)
nuclear@4 253 {
nuclear@4 254 static int fullscr, prev_x, prev_y;
nuclear@4 255 fullscr = !fullscr;
nuclear@4 256
nuclear@4 257 if(fullscr) {
nuclear@5 258 /* going fullscreen on the rift. save current window position, and move it
nuclear@5 259 * to the rift's part of the desktop before going fullscreen
nuclear@5 260 */
nuclear@4 261 SDL_GetWindowPosition(win, &prev_x, &prev_y);
nuclear@21 262 if(use_rift) {
nuclear@21 263 SDL_SetWindowPosition(win, hmd->WindowsPos.x, hmd->WindowsPos.y);
nuclear@21 264 }
nuclear@4 265 SDL_SetWindowFullscreen(win, SDL_WINDOW_FULLSCREEN_DESKTOP);
nuclear@15 266
nuclear@15 267 #ifdef OVR_OS_LINUX
nuclear@21 268 if(use_rift) {
nuclear@21 269 /* on linux for now we have to deal with screen rotation during rendering. The docs are promoting
nuclear@21 270 * not rotating the DK2 screen globally
nuclear@21 271 */
nuclear@21 272 glcfg.OGL.Header.BackBufferSize.w = hmd->Resolution.h;
nuclear@21 273 glcfg.OGL.Header.BackBufferSize.h = hmd->Resolution.w;
nuclear@15 274
nuclear@21 275 distort_caps |= ovrDistortionCap_LinuxDevFullscreen;
nuclear@21 276 ovrHmd_ConfigureRendering(hmd, &glcfg.Config, distort_caps, hmd->DefaultEyeFov, eye_rdesc);
nuclear@21 277 }
nuclear@15 278 #endif
nuclear@4 279 } else {
nuclear@5 280 /* return to windowed mode and move the window back to its original position */
nuclear@4 281 SDL_SetWindowFullscreen(win, 0);
nuclear@4 282 SDL_SetWindowPosition(win, prev_x, prev_y);
nuclear@15 283
nuclear@15 284 #ifdef OVR_OS_LINUX
nuclear@21 285 if(use_rift) {
nuclear@21 286 glcfg.OGL.Header.BackBufferSize = hmd->Resolution;
nuclear@15 287
nuclear@21 288 distort_caps &= ~ovrDistortionCap_LinuxDevFullscreen;
nuclear@21 289 ovrHmd_ConfigureRendering(hmd, &glcfg.Config, distort_caps, hmd->DefaultEyeFov, eye_rdesc);
nuclear@21 290 }
nuclear@15 291 #endif
nuclear@4 292 }
nuclear@4 293 }
nuclear@4 294
nuclear@2 295 void display(void)
nuclear@0 296 {
nuclear@21 297 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
nuclear@21 298
nuclear@21 299 glMatrixMode(GL_PROJECTION);
nuclear@21 300 glLoadIdentity();
nuclear@21 301 gluPerspective(50.0, (float)win_width / (float)win_height, 0.5, 500.0);
nuclear@21 302
nuclear@21 303 glMatrixMode(GL_MODELVIEW);
nuclear@21 304 glLoadIdentity();
nuclear@21 305 glRotatef(cam_phi, 1, 0, 0);
nuclear@21 306 glRotatef(cam_theta, 0, 1, 0);
nuclear@21 307 glTranslatef(0, -1.6, 0); /* player height */
nuclear@21 308
nuclear@21 309 draw_scene();
nuclear@21 310
nuclear@21 311 SDL_GL_SwapWindow(win);
nuclear@21 312 assert(glGetError() == GL_NO_ERROR);
nuclear@21 313 }
nuclear@21 314
nuclear@21 315 void display_rift(void)
nuclear@21 316 {
nuclear@2 317 int i;
nuclear@2 318 ovrMatrix4f proj;
nuclear@2 319 ovrPosef pose[2];
nuclear@4 320 float rot_mat[16];
nuclear@2 321
nuclear@4 322 /* the drawing starts with a call to ovrHmd_BeginFrame */
nuclear@2 323 ovrHmd_BeginFrame(hmd, 0);
nuclear@2 324
nuclear@4 325 /* start drawing onto our texture render target */
nuclear@2 326 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
nuclear@0 327 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
nuclear@0 328
nuclear@2 329 /* for each eye ... */
nuclear@2 330 for(i=0; i<2; i++) {
nuclear@7 331 ovrEyeType eye = hmd->EyeRenderOrder[i];
nuclear@2 332
nuclear@4 333 /* -- viewport transformation --
nuclear@4 334 * setup the viewport to draw in the left half of the framebuffer when we're
nuclear@4 335 * rendering the left eye's view (0, 0, width/2, height), and in the right half
nuclear@4 336 * of the framebuffer for the right eye's view (width/2, 0, width/2, height)
nuclear@4 337 */
nuclear@7 338 glViewport(eye == ovrEye_Left ? 0 : fb_width / 2, 0, fb_width / 2, fb_height);
nuclear@2 339
nuclear@4 340 /* -- projection transformation --
nuclear@4 341 * we'll just have to use the projection matrix supplied by the oculus SDK for this eye
nuclear@4 342 * note that libovr matrices are the transpose of what OpenGL expects, so we have to
nuclear@4 343 * use glLoadTransposeMatrixf instead of glLoadMatrixf to load it.
nuclear@4 344 */
nuclear@2 345 proj = ovrMatrix4f_Projection(hmd->DefaultEyeFov[eye], 0.5, 500.0, 1);
nuclear@2 346 glMatrixMode(GL_PROJECTION);
nuclear@4 347 glLoadTransposeMatrixf(proj.M[0]);
nuclear@2 348
nuclear@4 349 /* -- view/camera transformation --
nuclear@4 350 * we need to construct a view matrix by combining all the information provided by the oculus
nuclear@4 351 * SDK, about the position and orientation of the user's head in the world.
nuclear@4 352 */
nuclear@8 353 /* TODO: use ovrHmd_GetEyePoses out of the loop instead */
nuclear@8 354 pose[eye] = ovrHmd_GetHmdPosePerEye(hmd, eye);
nuclear@2 355 glMatrixMode(GL_MODELVIEW);
nuclear@4 356 glLoadIdentity();
nuclear@8 357 glTranslatef(eye_rdesc[eye].HmdToEyeViewOffset.x,
nuclear@8 358 eye_rdesc[eye].HmdToEyeViewOffset.y,
nuclear@8 359 eye_rdesc[eye].HmdToEyeViewOffset.z);
nuclear@4 360 /* retrieve the orientation quaternion and convert it to a rotation matrix */
nuclear@4 361 quat_to_matrix(&pose[eye].Orientation.x, rot_mat);
nuclear@4 362 glMultMatrixf(rot_mat);
nuclear@4 363 /* translate the view matrix with the positional tracking */
nuclear@4 364 glTranslatef(-pose[eye].Position.x, -pose[eye].Position.y, -pose[eye].Position.z);
nuclear@4 365 /* move the camera to the eye level of the user */
nuclear@4 366 glTranslatef(0, -ovrHmd_GetFloat(hmd, OVR_KEY_EYE_HEIGHT, 1.65), 0);
nuclear@2 367
nuclear@4 368 /* finally draw the scene for this eye */
nuclear@2 369 draw_scene();
nuclear@2 370 }
nuclear@2 371
nuclear@4 372 /* after drawing both eyes into the texture render target, revert to drawing directly to the
nuclear@4 373 * display, and we call ovrHmd_EndFrame, to let the Oculus SDK draw both images properly
nuclear@4 374 * compensated for lens distortion and chromatic abberation onto the HMD screen.
nuclear@4 375 */
nuclear@2 376 glBindFramebuffer(GL_FRAMEBUFFER, 0);
nuclear@2 377
nuclear@2 378 ovrHmd_EndFrame(hmd, pose, &fb_ovr_tex[0].Texture);
nuclear@2 379
nuclear@17 380 /* workaround for the oculus sdk distortion renderer bug, which uses a shader
nuclear@17 381 * program, and doesn't restore the original binding when it's done.
nuclear@17 382 */
nuclear@17 383 glUseProgram(0);
nuclear@17 384
nuclear@2 385 assert(glGetError() == GL_NO_ERROR);
nuclear@2 386 }
nuclear@2 387
nuclear@15 388 void reshape(int x, int y)
nuclear@15 389 {
nuclear@15 390 win_width = x;
nuclear@15 391 win_height = y;
nuclear@21 392
nuclear@21 393 glViewport(0, 0, x, y);
nuclear@15 394 }
nuclear@15 395
nuclear@2 396 void draw_scene(void)
nuclear@2 397 {
nuclear@2 398 int i;
nuclear@4 399 float grey[] = {0.8, 0.8, 0.8, 1};
nuclear@4 400 float col[] = {0, 0, 0, 1};
nuclear@4 401 float lpos[][4] = {
nuclear@4 402 {-8, 2, 10, 1},
nuclear@4 403 {0, 15, 0, 1}
nuclear@4 404 };
nuclear@4 405 float lcol[][4] = {
nuclear@4 406 {0.8, 0.8, 0.8, 1},
nuclear@4 407 {0.4, 0.3, 0.3, 1}
nuclear@4 408 };
nuclear@4 409
nuclear@4 410 for(i=0; i<2; i++) {
nuclear@4 411 glLightfv(GL_LIGHT0 + i, GL_POSITION, lpos[i]);
nuclear@4 412 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, lcol[i]);
nuclear@4 413 }
nuclear@4 414
nuclear@4 415 glMatrixMode(GL_MODELVIEW);
nuclear@2 416
nuclear@3 417 glPushMatrix();
nuclear@4 418 glTranslatef(0, 10, 0);
nuclear@4 419 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, grey);
nuclear@4 420 glBindTexture(GL_TEXTURE_2D, chess_tex);
nuclear@4 421 glEnable(GL_TEXTURE_2D);
nuclear@4 422 draw_box(30, 20, 30, -1.0);
nuclear@4 423 glDisable(GL_TEXTURE_2D);
nuclear@3 424 glPopMatrix();
nuclear@3 425
nuclear@4 426 for(i=0; i<4; i++) {
nuclear@4 427 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, grey);
nuclear@4 428 glPushMatrix();
nuclear@4 429 glTranslatef(i & 1 ? 5 : -5, 1, i & 2 ? -5 : 5);
nuclear@4 430 draw_box(0.5, 2, 0.5, 1.0);
nuclear@4 431 glPopMatrix();
nuclear@2 432
nuclear@4 433 col[0] = i & 1 ? 1.0 : 0.3;
nuclear@4 434 col[1] = i == 0 ? 1.0 : 0.3;
nuclear@4 435 col[2] = i & 2 ? 1.0 : 0.3;
nuclear@4 436 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
nuclear@4 437
nuclear@2 438 glPushMatrix();
nuclear@2 439 if(i & 1) {
nuclear@4 440 glTranslatef(0, 0.25, i & 2 ? 2 : -2);
nuclear@2 441 } else {
nuclear@4 442 glTranslatef(i & 2 ? 2 : -2, 0.25, 0);
nuclear@2 443 }
nuclear@4 444 draw_box(0.5, 0.5, 0.5, 1.0);
nuclear@2 445 glPopMatrix();
nuclear@2 446 }
nuclear@12 447
nuclear@12 448 col[0] = 1;
nuclear@12 449 col[1] = 1;
nuclear@12 450 col[2] = 0.4;
nuclear@12 451 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
nuclear@12 452 draw_box(0.05, 1.2, 6, 1.0);
nuclear@12 453 draw_box(6, 1.2, 0.05, 1.0);
nuclear@21 454
nuclear@21 455 /* draw laser sight */
nuclear@21 456 glPushMatrix();
nuclear@21 457 glTranslatef(0, GUN_Y, 0);
nuclear@21 458 glRotatef(-cam_theta, 0, 1, 0);
nuclear@21 459 glRotatef(-cam_phi, 1, 0, 0);
nuclear@21 460
nuclear@21 461 glPushAttrib(GL_ENABLE_BIT);
nuclear@21 462 glDisable(GL_LIGHTING);
nuclear@21 463 glEnable(GL_BLEND);
nuclear@21 464 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
nuclear@21 465
nuclear@21 466 glDepthMask(0);
nuclear@21 467 glLineWidth(3.0);
nuclear@21 468
nuclear@21 469 glBegin(GL_LINES);
nuclear@21 470 glColor4f(1.0, 0.2, 0.15, 0.4);
nuclear@21 471 glVertex3f(0, 0, 0);
nuclear@21 472 glVertex3f(0, 0, -100.0);
nuclear@21 473 glEnd();
nuclear@21 474 glLineWidth(1.0);
nuclear@21 475
nuclear@21 476 glPopAttrib();
nuclear@21 477
nuclear@21 478 glPopMatrix();
nuclear@21 479
nuclear@21 480 draw_shots();
nuclear@2 481 }
nuclear@2 482
nuclear@2 483 void draw_box(float xsz, float ysz, float zsz, float norm_sign)
nuclear@2 484 {
nuclear@2 485 glMatrixMode(GL_MODELVIEW);
nuclear@12 486 glPushMatrix();
nuclear@2 487 glScalef(xsz * 0.5, ysz * 0.5, zsz * 0.5);
nuclear@2 488
nuclear@2 489 if(norm_sign < 0.0) {
nuclear@2 490 glFrontFace(GL_CW);
nuclear@2 491 }
nuclear@2 492
nuclear@2 493 glBegin(GL_QUADS);
nuclear@2 494 glNormal3f(0, 0, 1 * norm_sign);
nuclear@2 495 glTexCoord2f(0, 0); glVertex3f(-1, -1, 1);
nuclear@2 496 glTexCoord2f(1, 0); glVertex3f(1, -1, 1);
nuclear@2 497 glTexCoord2f(1, 1); glVertex3f(1, 1, 1);
nuclear@2 498 glTexCoord2f(0, 1); glVertex3f(-1, 1, 1);
nuclear@2 499 glNormal3f(1 * norm_sign, 0, 0);
nuclear@2 500 glTexCoord2f(0, 0); glVertex3f(1, -1, 1);
nuclear@2 501 glTexCoord2f(1, 0); glVertex3f(1, -1, -1);
nuclear@2 502 glTexCoord2f(1, 1); glVertex3f(1, 1, -1);
nuclear@2 503 glTexCoord2f(0, 1); glVertex3f(1, 1, 1);
nuclear@2 504 glNormal3f(0, 0, -1 * norm_sign);
nuclear@2 505 glTexCoord2f(0, 0); glVertex3f(1, -1, -1);
nuclear@2 506 glTexCoord2f(1, 0); glVertex3f(-1, -1, -1);
nuclear@2 507 glTexCoord2f(1, 1); glVertex3f(-1, 1, -1);
nuclear@2 508 glTexCoord2f(0, 1); glVertex3f(1, 1, -1);
nuclear@2 509 glNormal3f(-1 * norm_sign, 0, 0);
nuclear@2 510 glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
nuclear@2 511 glTexCoord2f(1, 0); glVertex3f(-1, -1, 1);
nuclear@2 512 glTexCoord2f(1, 1); glVertex3f(-1, 1, 1);
nuclear@2 513 glTexCoord2f(0, 1); glVertex3f(-1, 1, -1);
nuclear@4 514 glEnd();
nuclear@4 515 glBegin(GL_TRIANGLE_FAN);
nuclear@2 516 glNormal3f(0, 1 * norm_sign, 0);
nuclear@4 517 glTexCoord2f(0.5, 0.5); glVertex3f(0, 1, 0);
nuclear@2 518 glTexCoord2f(0, 0); glVertex3f(-1, 1, 1);
nuclear@2 519 glTexCoord2f(1, 0); glVertex3f(1, 1, 1);
nuclear@2 520 glTexCoord2f(1, 1); glVertex3f(1, 1, -1);
nuclear@2 521 glTexCoord2f(0, 1); glVertex3f(-1, 1, -1);
nuclear@4 522 glTexCoord2f(0, 0); glVertex3f(-1, 1, 1);
nuclear@4 523 glEnd();
nuclear@4 524 glBegin(GL_TRIANGLE_FAN);
nuclear@2 525 glNormal3f(0, -1 * norm_sign, 0);
nuclear@4 526 glTexCoord2f(0.5, 0.5); glVertex3f(0, -1, 0);
nuclear@2 527 glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
nuclear@2 528 glTexCoord2f(1, 0); glVertex3f(1, -1, -1);
nuclear@2 529 glTexCoord2f(1, 1); glVertex3f(1, -1, 1);
nuclear@2 530 glTexCoord2f(0, 1); glVertex3f(-1, -1, 1);
nuclear@4 531 glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
nuclear@2 532 glEnd();
nuclear@2 533
nuclear@2 534 glFrontFace(GL_CCW);
nuclear@12 535 glPopMatrix();
nuclear@0 536 }
nuclear@0 537
nuclear@5 538 /* update_rtarg creates (and/or resizes) the render target used to draw the two stero views */
nuclear@0 539 void update_rtarg(int width, int height)
nuclear@0 540 {
nuclear@0 541 if(!fbo) {
nuclear@5 542 /* if fbo does not exist, then nothing does... create every opengl object */
nuclear@0 543 glGenFramebuffers(1, &fbo);
nuclear@0 544 glGenTextures(1, &fb_tex);
nuclear@0 545 glGenRenderbuffers(1, &fb_depth);
nuclear@0 546
nuclear@0 547 glBindTexture(GL_TEXTURE_2D, fb_tex);
nuclear@0 548 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
nuclear@0 549 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
nuclear@0 550 }
nuclear@0 551
nuclear@0 552 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
nuclear@0 553
nuclear@5 554 /* calculate the next power of two in both dimensions and use that as a texture size */
nuclear@0 555 fb_tex_width = next_pow2(width);
nuclear@0 556 fb_tex_height = next_pow2(height);
nuclear@0 557
nuclear@5 558 /* create and attach the texture that will be used as a color buffer */
nuclear@0 559 glBindTexture(GL_TEXTURE_2D, fb_tex);
nuclear@0 560 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, fb_tex_width, fb_tex_height, 0,
nuclear@0 561 GL_RGBA, GL_UNSIGNED_BYTE, 0);
nuclear@0 562 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb_tex, 0);
nuclear@0 563
nuclear@5 564 /* create and attach the renderbuffer that will serve as our z-buffer */
nuclear@0 565 glBindRenderbuffer(GL_RENDERBUFFER, fb_depth);
nuclear@0 566 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, fb_tex_width, fb_tex_height);
nuclear@0 567 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fb_depth);
nuclear@0 568
nuclear@0 569 if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
nuclear@0 570 fprintf(stderr, "incomplete framebuffer!\n");
nuclear@0 571 }
nuclear@0 572
nuclear@0 573 glBindFramebuffer(GL_FRAMEBUFFER, 0);
nuclear@0 574 printf("created render target: %dx%d (texture size: %dx%d)\n", width, height, fb_tex_width, fb_tex_height);
nuclear@0 575 }
nuclear@0 576
nuclear@21 577 void fire(void)
nuclear@21 578 {
nuclear@21 579 vec3_t pos = {0, GUN_Y, 0};
nuclear@21 580 vec3_t dir;
nuclear@21 581 float theta = DEG_TO_RAD(cam_theta);
nuclear@21 582 float phi = DEG_TO_RAD(cam_phi);
nuclear@21 583
nuclear@21 584 dir.x = -sin(-theta) * cos(phi);
nuclear@21 585 dir.y = -sin(phi);
nuclear@21 586 dir.z = -cos(-theta) * cos(phi);
nuclear@21 587
nuclear@21 588 shoot(pos, v3_scale(dir, 10.0));
nuclear@21 589 }
nuclear@21 590
nuclear@0 591 int handle_event(SDL_Event *ev)
nuclear@0 592 {
nuclear@0 593 switch(ev->type) {
nuclear@4 594 case SDL_QUIT:
nuclear@4 595 return -1;
nuclear@4 596
nuclear@0 597 case SDL_KEYDOWN:
nuclear@0 598 case SDL_KEYUP:
nuclear@0 599 if(key_event(ev->key.keysym.sym, ev->key.state == SDL_PRESSED) == -1) {
nuclear@0 600 return -1;
nuclear@0 601 }
nuclear@0 602 break;
nuclear@0 603
nuclear@15 604 case SDL_WINDOWEVENT:
nuclear@15 605 if(ev->window.event == SDL_WINDOWEVENT_RESIZED) {
nuclear@15 606 reshape(ev->window.data1, ev->window.data2);
nuclear@21 607 } else if(ev->window.event == SDL_WINDOWEVENT_SHOWN) {
nuclear@21 608 int xsz, ysz;
nuclear@21 609 SDL_GetWindowSize(win, &xsz, &ysz);
nuclear@21 610 reshape(xsz, ysz);
nuclear@21 611 }
nuclear@21 612 break;
nuclear@21 613
nuclear@21 614 case SDL_MOUSEBUTTONDOWN:
nuclear@21 615 if(ev->button.button == SDL_BUTTON_LEFT) {
nuclear@21 616 fire();
nuclear@21 617 }
nuclear@21 618 break;
nuclear@21 619
nuclear@21 620 case SDL_MOUSEMOTION:
nuclear@21 621 {
nuclear@21 622 static int prev_x, prev_y;
nuclear@21 623 int dx = ev->motion.x - prev_x;
nuclear@21 624 int dy = ev->motion.y - prev_y;
nuclear@21 625 prev_x = ev->motion.x;
nuclear@21 626 prev_y = ev->motion.y;
nuclear@21 627
nuclear@21 628 if(ev->motion.state & SDL_BUTTON_RMASK) {
nuclear@21 629 cam_theta += dx * 0.5;
nuclear@21 630 cam_phi += dy * 0.5;
nuclear@21 631
nuclear@21 632 if(cam_phi < -90) cam_phi = -90;
nuclear@21 633 if(cam_phi > 90) cam_phi = 90;
nuclear@21 634 }
nuclear@15 635 }
nuclear@15 636 break;
nuclear@15 637
nuclear@0 638 default:
nuclear@0 639 break;
nuclear@0 640 }
nuclear@0 641
nuclear@0 642 return 0;
nuclear@0 643 }
nuclear@0 644
nuclear@0 645 int key_event(int key, int state)
nuclear@0 646 {
nuclear@0 647 if(state) {
nuclear@5 648 /*
nuclear@4 649 ovrHSWDisplayState hsw;
nuclear@4 650 ovrHmd_GetHSWDisplayState(hmd, &hsw);
nuclear@4 651 if(hsw.Displayed) {
nuclear@4 652 ovrHmd_DismissHSWDisplay(hmd);
nuclear@4 653 }
nuclear@5 654 */
nuclear@4 655
nuclear@0 656 switch(key) {
nuclear@0 657 case 27:
nuclear@0 658 return -1;
nuclear@0 659
nuclear@4 660 case ' ':
nuclear@15 661 case 'r':
nuclear@4 662 /* allow the user to recenter by pressing space */
nuclear@4 663 ovrHmd_RecenterPose(hmd);
nuclear@4 664 break;
nuclear@4 665
nuclear@4 666 case 'f':
nuclear@4 667 /* press f to move the window to the HMD */
nuclear@4 668 toggle_hmd_fullscreen();
nuclear@4 669 break;
nuclear@4 670
nuclear@15 671 case 'v':
nuclear@15 672 distort_caps ^= ovrDistortionCap_Vignette;
nuclear@15 673 printf("Vignette: %s\n", distort_caps & ovrDistortionCap_Vignette ? "on" : "off");
nuclear@15 674 ovrHmd_ConfigureRendering(hmd, &glcfg.Config, distort_caps, hmd->DefaultEyeFov, eye_rdesc);
nuclear@15 675 break;
nuclear@15 676
nuclear@15 677 case 't':
nuclear@15 678 distort_caps ^= ovrDistortionCap_TimeWarp;
nuclear@15 679 printf("Time-warp: %s\n", distort_caps & ovrDistortionCap_TimeWarp ? "on" : "off");
nuclear@15 680 ovrHmd_ConfigureRendering(hmd, &glcfg.Config, distort_caps, hmd->DefaultEyeFov, eye_rdesc);
nuclear@15 681 break;
nuclear@15 682
nuclear@15 683 case 'o':
nuclear@15 684 distort_caps ^= ovrDistortionCap_Overdrive;
nuclear@15 685 printf("OLED over-drive: %s\n", distort_caps & ovrDistortionCap_Overdrive ? "on" : "off");
nuclear@15 686 ovrHmd_ConfigureRendering(hmd, &glcfg.Config, distort_caps, hmd->DefaultEyeFov, eye_rdesc);
nuclear@15 687 break;
nuclear@15 688
nuclear@15 689 case 'l':
nuclear@15 690 hmd_caps ^= ovrHmdCap_LowPersistence;
nuclear@15 691 printf("Low-persistence display: %s\n", hmd_caps & ovrHmdCap_LowPersistence ? "on" : "off");
nuclear@15 692 ovrHmd_SetEnabledCaps(hmd, hmd_caps);
nuclear@15 693 break;
nuclear@15 694
nuclear@0 695 default:
nuclear@0 696 break;
nuclear@0 697 }
nuclear@0 698 }
nuclear@0 699 return 0;
nuclear@0 700 }
nuclear@4 701
nuclear@4 702 unsigned int next_pow2(unsigned int x)
nuclear@4 703 {
nuclear@4 704 x -= 1;
nuclear@4 705 x |= x >> 1;
nuclear@4 706 x |= x >> 2;
nuclear@4 707 x |= x >> 4;
nuclear@4 708 x |= x >> 8;
nuclear@4 709 x |= x >> 16;
nuclear@4 710 return x + 1;
nuclear@4 711 }
nuclear@4 712
nuclear@5 713 /* convert a quaternion to a rotation matrix */
nuclear@4 714 void quat_to_matrix(const float *quat, float *mat)
nuclear@4 715 {
nuclear@4 716 mat[0] = 1.0 - 2.0 * quat[1] * quat[1] - 2.0 * quat[2] * quat[2];
nuclear@4 717 mat[4] = 2.0 * quat[0] * quat[1] + 2.0 * quat[3] * quat[2];
nuclear@4 718 mat[8] = 2.0 * quat[2] * quat[0] - 2.0 * quat[3] * quat[1];
nuclear@4 719 mat[12] = 0.0f;
nuclear@4 720
nuclear@4 721 mat[1] = 2.0 * quat[0] * quat[1] - 2.0 * quat[3] * quat[2];
nuclear@4 722 mat[5] = 1.0 - 2.0 * quat[0]*quat[0] - 2.0 * quat[2]*quat[2];
nuclear@4 723 mat[9] = 2.0 * quat[1] * quat[2] + 2.0 * quat[3] * quat[0];
nuclear@4 724 mat[13] = 0.0f;
nuclear@4 725
nuclear@4 726 mat[2] = 2.0 * quat[2] * quat[0] + 2.0 * quat[3] * quat[1];
nuclear@4 727 mat[6] = 2.0 * quat[1] * quat[2] - 2.0 * quat[3] * quat[0];
nuclear@4 728 mat[10] = 1.0 - 2.0 * quat[0]*quat[0] - 2.0 * quat[1]*quat[1];
nuclear@4 729 mat[14] = 0.0f;
nuclear@4 730
nuclear@4 731 mat[3] = mat[7] = mat[11] = 0.0f;
nuclear@4 732 mat[15] = 1.0f;
nuclear@4 733 }
nuclear@4 734
nuclear@5 735 /* generate a chessboard texture with tiles colored (r0, g0, b0) and (r1, g1, b1) */
nuclear@4 736 unsigned int gen_chess_tex(float r0, float g0, float b0, float r1, float g1, float b1)
nuclear@4 737 {
nuclear@4 738 int i, j;
nuclear@4 739 unsigned int tex;
nuclear@4 740 unsigned char img[8 * 8 * 3];
nuclear@4 741 unsigned char *pix = img;
nuclear@4 742
nuclear@4 743 for(i=0; i<8; i++) {
nuclear@4 744 for(j=0; j<8; j++) {
nuclear@4 745 int black = (i & 1) == (j & 1);
nuclear@4 746 pix[0] = (black ? r0 : r1) * 255;
nuclear@4 747 pix[1] = (black ? g0 : g1) * 255;
nuclear@4 748 pix[2] = (black ? b0 : b1) * 255;
nuclear@4 749 pix += 3;
nuclear@4 750 }
nuclear@4 751 }
nuclear@4 752
nuclear@4 753 glGenTextures(1, &tex);
nuclear@4 754 glBindTexture(GL_TEXTURE_2D, tex);
nuclear@4 755 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
nuclear@4 756 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
nuclear@4 757 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, img);
nuclear@4 758
nuclear@4 759 return tex;
nuclear@8 760 }
nuclear@21 761
nuclear@21 762 int parse_args(int argc, char **argv)
nuclear@21 763 {
nuclear@21 764 int i;
nuclear@21 765
nuclear@21 766 for(i=1; i<argc; i++) {
nuclear@21 767 if(argv[i][0] == '-') {
nuclear@21 768 if(strcmp(argv[i], "-novr") == 0) {
nuclear@21 769 use_rift = 0;
nuclear@21 770 } else {
nuclear@21 771 fprintf(stderr, "invalid option: %s\n", argv[i]);
nuclear@21 772 return -1;
nuclear@21 773 }
nuclear@21 774 } else {
nuclear@21 775 fprintf(stderr, "unexpected argument: %s\n", argv[i]);
nuclear@21 776 return -1;
nuclear@21 777 }
nuclear@21 778 }
nuclear@21 779 return 0;
nuclear@21 780 }