libgoatvr

annotate src/vr_libovr.c @ 29:ddaa9c764030

minor fix
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 08 Apr 2015 02:32:22 +0300
parents 5136dfcea7b1
children 1a8343ea54ce
rev   line source
nuclear@0 1 #ifdef WIN32
nuclear@0 2 #define OVR_OS_WIN32
nuclear@24 3 #elif defined(__APPLE__)
nuclear@9 4 #define OVR_OS_MAC
nuclear@24 5 #else
nuclear@24 6 #define OVR_OS_LINUX
nuclear@9 7 #endif
nuclear@0 8
nuclear@0 9 #include "vr_impl.h"
nuclear@0 10
nuclear@0 11 #ifdef USE_LIBOVR
nuclear@0 12 #include <stdio.h>
nuclear@0 13 #include <stdlib.h>
nuclear@9 14 #include <string.h>
nuclear@0 15 #include <assert.h>
nuclear@0 16 #include "opt.h"
nuclear@0 17
nuclear@0 18 #include <OVR_CAPI.h>
nuclear@0 19 #include <OVR_CAPI_GL.h>
nuclear@0 20
nuclear@24 21 #ifdef OVR_OS_LINUX
nuclear@24 22 #include <GL/glx.h>
nuclear@24 23 #endif
nuclear@24 24
nuclear@19 25 /* undef this if you want the retarded health and safety warning screen */
nuclear@28 26 #undef DISABLE_RETARDED_HEALTH_WARNING
nuclear@0 27
nuclear@0 28 /* just dropping the prototype here to avoid including CAPI_HSWDisplay.h */
nuclear@0 29 OVR_EXPORT void ovrhmd_EnableHSWDisplaySDKRender(ovrHmd hmd, ovrBool enabled);
nuclear@0 30
nuclear@0 31 static ovrHmd hmd;
nuclear@0 32 static void *optdb;
nuclear@0 33 static ovrEyeRenderDesc eye_render_desc[2];
nuclear@0 34 static ovrSizei eye_res[2];
nuclear@0 35 static ovrGLTexture eye_tex[2];
nuclear@0 36 static ovrFovPort eye_fov[2];
nuclear@19 37 static ovrPosef pose[2] = {
nuclear@19 38 { {0, 0, 0, 1}, {0, 0, 0} },
nuclear@19 39 { {0, 0, 0, 1}, {0, 0, 0} }
nuclear@19 40 };
nuclear@0 41 static int deferred_init_done;
nuclear@0 42
nuclear@19 43 static int inside_begin_end;
nuclear@19 44
nuclear@0 45 static int init(void)
nuclear@0 46 {
nuclear@0 47 int i, num_hmds;
nuclear@9 48 int use_fake = 0;
nuclear@14 49 ovrTrackingCaps tracking;
nuclear@0 50
nuclear@28 51 if(!ovr_Initialize(0)) {
nuclear@0 52 return -1;
nuclear@0 53 }
nuclear@0 54 printf("initialized LibOVR %s\n", ovr_GetVersionString());
nuclear@0 55
nuclear@0 56 if(!(num_hmds = ovrHmd_Detect())) {
nuclear@9 57 if(getenv("VR_LIBOVR_FAKE")) {
nuclear@9 58 use_fake = 1;
nuclear@9 59 num_hmds = 1;
nuclear@9 60 } else {
nuclear@9 61 ovr_Shutdown();
nuclear@9 62 return -1;
nuclear@9 63 }
nuclear@0 64 }
nuclear@0 65 printf("%d Oculus HMD(s) found\n", num_hmds);
nuclear@0 66
nuclear@0 67 hmd = 0;
nuclear@0 68 for(i=0; i<num_hmds; i++) {
nuclear@9 69 ovrHmd h = use_fake ? ovrHmd_CreateDebug(ovrHmd_DK2) : ovrHmd_Create(i);
nuclear@9 70 if(!h) {
nuclear@0 71 break;
nuclear@0 72 }
nuclear@0 73 printf(" [%d]: %s - %s\n", i, h->Manufacturer, h->ProductName);
nuclear@0 74
nuclear@0 75 if(!hmd) {
nuclear@0 76 hmd = h;
nuclear@0 77 } else {
nuclear@0 78 ovrHmd_Destroy(h);
nuclear@0 79 }
nuclear@0 80 }
nuclear@0 81
nuclear@0 82 if(!hmd) {
nuclear@0 83 fprintf(stderr, "failed to initialize any Oculus HMDs\n");
nuclear@0 84 return -1;
nuclear@0 85 }
nuclear@0 86
nuclear@14 87 tracking = ovrTrackingCap_Orientation | ovrTrackingCap_Position |
nuclear@14 88 ovrTrackingCap_MagYawCorrection;
nuclear@14 89 ovrHmd_ConfigureTracking(hmd, tracking, 0);
nuclear@0 90
nuclear@0 91 eye_fov[0] = hmd->DefaultEyeFov[0];
nuclear@0 92 eye_fov[1] = hmd->DefaultEyeFov[1];
nuclear@0 93
nuclear@0 94 eye_res[0] = ovrHmd_GetFovTextureSize(hmd, ovrEye_Left, eye_fov[0], 1.0);
nuclear@0 95 eye_res[1] = ovrHmd_GetFovTextureSize(hmd, ovrEye_Right, eye_fov[1], 1.0);
nuclear@0 96
nuclear@0 97 /* create the options database */
nuclear@0 98 if((optdb = create_options())) {
nuclear@11 99 set_option_int(optdb, VR_DISPLAY_WIDTH, hmd->Resolution.w);
nuclear@11 100 set_option_int(optdb, VR_DISPLAY_HEIGHT, hmd->Resolution.h);
nuclear@11 101 set_option_int(optdb, VR_LEYE_XRES, eye_res[0].w);
nuclear@11 102 set_option_int(optdb, VR_LEYE_YRES, eye_res[0].h);
nuclear@11 103 set_option_int(optdb, VR_REYE_XRES, eye_res[1].w);
nuclear@11 104 set_option_int(optdb, VR_REYE_YRES, eye_res[1].h);
nuclear@29 105 set_option_int(optdb, VR_RENDER_XRES, eye_res[0].w + eye_res[1].w);
nuclear@29 106 set_option_int(optdb, VR_RENDER_YRES, eye_res[0].h > eye_res[1].h ? eye_res[0].h : eye_res[1].h);
nuclear@16 107 set_option_float(optdb, VR_RENDER_RES_SCALE, 1.0);
nuclear@11 108 set_option_float(optdb, VR_EYE_HEIGHT, ovrHmd_GetFloat(hmd, OVR_KEY_EYE_HEIGHT, OVR_DEFAULT_EYE_HEIGHT));
nuclear@11 109 set_option_float(optdb, VR_IPD, ovrHmd_GetFloat(hmd, OVR_KEY_IPD, OVR_DEFAULT_IPD));
nuclear@11 110 set_option_int(optdb, VR_WIN_XOFFS, hmd->WindowsPos.x);
nuclear@11 111 set_option_int(optdb, VR_WIN_YOFFS, hmd->WindowsPos.y);
nuclear@0 112 }
nuclear@0 113
nuclear@0 114 deferred_init_done = 0;
nuclear@0 115 return 0;
nuclear@0 116 }
nuclear@0 117
nuclear@0 118 static void deferred_init(void)
nuclear@0 119 {
nuclear@0 120 union ovrGLConfig glcfg;
nuclear@0 121 unsigned int dcaps;
nuclear@0 122 void *win = 0;
nuclear@19 123 float leye_offs[3], reye_offs[3];
nuclear@0 124
nuclear@0 125 deferred_init_done = 1;
nuclear@0 126
nuclear@0 127 memset(&glcfg, 0, sizeof glcfg);
nuclear@0 128 glcfg.OGL.Header.API = ovrRenderAPI_OpenGL;
nuclear@21 129 glcfg.OGL.Header.BackBufferSize = hmd->Resolution;
nuclear@0 130 glcfg.OGL.Header.Multisample = 1;
nuclear@0 131 #ifdef WIN32
nuclear@0 132 win = GetActiveWindow();
nuclear@24 133 glcfg.OGL.Window = win;
nuclear@0 134 glcfg.OGL.DC = wglGetCurrentDC();
nuclear@24 135 #else
nuclear@24 136 glcfg.OGL.Disp = glXGetCurrentDisplay();
nuclear@24 137 win = (void*)glXGetCurrentDrawable();
nuclear@24 138
nuclear@24 139 /* on linux the Oculus SDK docs are instructing users to leave the DK2 screen in
nuclear@24 140 * portrait mode. So we'll have to flip width and height
nuclear@24 141 */
nuclear@24 142 glcfg.OGL.Header.BackBufferSize.w = hmd->Resolution.h;
nuclear@24 143 glcfg.OGL.Header.BackBufferSize.h = hmd->Resolution.w;
nuclear@0 144 #endif
nuclear@0 145
nuclear@0 146 if(!(hmd->HmdCaps & ovrHmdCap_ExtendDesktop)) {
nuclear@0 147 ovrHmd_AttachToWindow(hmd, win, 0, 0);
nuclear@0 148 printf("running in \"direct-to-rift\" mode\n");
nuclear@0 149 } else {
nuclear@0 150 printf("running in \"extended desktop\" mode\n");
nuclear@0 151 }
nuclear@0 152 ovrHmd_SetEnabledCaps(hmd, ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction);
nuclear@0 153
nuclear@28 154 dcaps = ovrDistortionCap_TimeWarp | ovrDistortionCap_Overdrive;
nuclear@24 155 #ifdef OVR_OS_LINUX
nuclear@24 156 dcaps |= ovrDistortionCap_LinuxDevFullscreen;
nuclear@24 157 #endif
nuclear@0 158
nuclear@0 159 if(!ovrHmd_ConfigureRendering(hmd, &glcfg.Config, dcaps, eye_fov, eye_render_desc)) {
nuclear@0 160 fprintf(stderr, "failed to configure LibOVR distortion renderer\n");
nuclear@0 161 }
nuclear@0 162
nuclear@19 163 /* set the eye offset options */
nuclear@21 164 leye_offs[0] = eye_render_desc[ovrEye_Left].HmdToEyeViewOffset.x;
nuclear@21 165 leye_offs[1] = eye_render_desc[ovrEye_Left].HmdToEyeViewOffset.y;
nuclear@21 166 leye_offs[2] = eye_render_desc[ovrEye_Left].HmdToEyeViewOffset.z;
nuclear@21 167 reye_offs[0] = eye_render_desc[ovrEye_Right].HmdToEyeViewOffset.x;
nuclear@21 168 reye_offs[1] = eye_render_desc[ovrEye_Right].HmdToEyeViewOffset.y;
nuclear@21 169 reye_offs[2] = eye_render_desc[ovrEye_Right].HmdToEyeViewOffset.z;
nuclear@24 170
nuclear@24 171 /* sanity check ... on linux it seems I'm getting the eye offsets reversed for some reason */
nuclear@24 172 if(leye_offs[0] > reye_offs[0]) {
nuclear@24 173 fprintf(stderr, "BUG %s:%d: eye offset reversed?! fixing but wtf...\n", __FILE__, __LINE__);
nuclear@24 174 set_option_vec(optdb, VR_LEYE_OFFSET, reye_offs);
nuclear@24 175 set_option_vec(optdb, VR_REYE_OFFSET, leye_offs);
nuclear@24 176 } else {
nuclear@24 177 set_option_vec(optdb, VR_LEYE_OFFSET, leye_offs);
nuclear@24 178 set_option_vec(optdb, VR_REYE_OFFSET, reye_offs);
nuclear@24 179 }
nuclear@24 180
nuclear@19 181
nuclear@0 182 #ifdef DISABLE_RETARDED_HEALTH_WARNING
nuclear@0 183 ovrhmd_EnableHSWDisplaySDKRender(hmd, 0);
nuclear@0 184 #endif
nuclear@0 185 }
nuclear@0 186
nuclear@0 187 static void cleanup(void)
nuclear@0 188 {
nuclear@0 189 if(hmd) {
nuclear@0 190 ovrHmd_Destroy(hmd);
nuclear@0 191 ovr_Shutdown();
nuclear@0 192 }
nuclear@5 193 destroy_options(optdb);
nuclear@0 194 }
nuclear@0 195
nuclear@0 196 static int set_option(const char *opt, enum opt_type type, void *valp)
nuclear@0 197 {
nuclear@15 198 float fval;
nuclear@15 199
nuclear@0 200 switch(type) {
nuclear@0 201 case OTYPE_INT:
nuclear@15 202 fval = (float)*(int*)valp;
nuclear@0 203 set_option_int(optdb, opt, *(int*)valp);
nuclear@0 204 break;
nuclear@0 205
nuclear@0 206 case OTYPE_FLOAT:
nuclear@15 207 fval = *(float*)valp;
nuclear@15 208 set_option_float(optdb, opt, fval);
nuclear@0 209 break;
nuclear@24 210
nuclear@24 211 case OTYPE_VEC:
nuclear@24 212 set_option_vec(optdb, opt, valp);
nuclear@24 213 break;
nuclear@0 214 }
nuclear@15 215
nuclear@16 216 if(hmd && strcmp(opt, VR_RENDER_RES_SCALE) == 0) {
nuclear@15 217 eye_res[0] = ovrHmd_GetFovTextureSize(hmd, ovrEye_Left, eye_fov[0], fval);
nuclear@15 218 eye_res[1] = ovrHmd_GetFovTextureSize(hmd, ovrEye_Right, eye_fov[1], fval);
nuclear@15 219
nuclear@15 220 set_option_int(optdb, VR_LEYE_XRES, eye_res[0].w);
nuclear@15 221 set_option_int(optdb, VR_LEYE_YRES, eye_res[0].h);
nuclear@15 222 set_option_int(optdb, VR_REYE_XRES, eye_res[1].w);
nuclear@15 223 set_option_int(optdb, VR_REYE_YRES, eye_res[1].h);
nuclear@15 224 }
nuclear@15 225
nuclear@0 226 return 0;
nuclear@0 227 }
nuclear@0 228
nuclear@0 229 static int get_option(const char *opt, enum opt_type type, void *valp)
nuclear@0 230 {
nuclear@0 231 switch(type) {
nuclear@0 232 case OTYPE_INT:
nuclear@0 233 return get_option_int(optdb, opt, valp);
nuclear@0 234 case OTYPE_FLOAT:
nuclear@0 235 return get_option_float(optdb, opt, valp);
nuclear@24 236 case OTYPE_VEC:
nuclear@24 237 return get_option_vec(optdb, opt, valp);
nuclear@0 238 }
nuclear@0 239 return -1;
nuclear@0 240 }
nuclear@0 241
nuclear@7 242 static void translation(int eye, float *vec)
nuclear@0 243 {
nuclear@0 244 if(!hmd) {
nuclear@0 245 vec[0] = vec[1] = vec[2] = 0;
nuclear@9 246 return;
nuclear@0 247 }
nuclear@0 248
nuclear@19 249 /* if we're inside the begin-end block we can get a fresh pose, otherwise we'll just
nuclear@19 250 * reuse the one we got last frame.
nuclear@19 251 */
nuclear@19 252 if(inside_begin_end) {
nuclear@21 253 pose[eye] = ovrHmd_GetHmdPosePerEye(hmd, eye == VR_EYE_LEFT ? ovrEye_Left : ovrEye_Right);
nuclear@19 254 }
nuclear@19 255
nuclear@19 256 vec[0] = pose[eye].Position.x;
nuclear@19 257 vec[1] = pose[eye].Position.y;
nuclear@19 258 vec[2] = pose[eye].Position.z;
nuclear@0 259 }
nuclear@0 260
nuclear@7 261 static void rotation(int eye, float *quat)
nuclear@0 262 {
nuclear@0 263 if(!hmd) {
nuclear@0 264 quat[0] = quat[1] = quat[2] = 0.0f;
nuclear@0 265 quat[3] = 1.0f;
nuclear@9 266 return;
nuclear@0 267 }
nuclear@0 268
nuclear@19 269 /* same as above (translation) */
nuclear@19 270 if(inside_begin_end) {
nuclear@21 271 pose[eye] = ovrHmd_GetHmdPosePerEye(hmd, eye == VR_EYE_LEFT ? ovrEye_Left : ovrEye_Right);
nuclear@19 272 }
nuclear@19 273
nuclear@0 274 quat[0] = pose[eye].Orientation.x;
nuclear@0 275 quat[1] = pose[eye].Orientation.y;
nuclear@0 276 quat[2] = pose[eye].Orientation.z;
nuclear@0 277 quat[3] = pose[eye].Orientation.w;
nuclear@0 278 }
nuclear@0 279
nuclear@0 280 static const float idmat[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
nuclear@0 281
nuclear@0 282 static void proj_matrix(int eye, float znear, float zfar, float *mat)
nuclear@0 283 {
nuclear@0 284 int i, j;
nuclear@0 285 ovrMatrix4f vmat;
nuclear@0 286
nuclear@0 287 if(!hmd) {
nuclear@0 288 memcpy(mat, idmat, sizeof idmat);
nuclear@0 289 return;
nuclear@0 290 }
nuclear@0 291
nuclear@0 292 vmat = ovrMatrix4f_Projection(eye_render_desc[eye].Fov, znear, zfar, 1);
nuclear@0 293
nuclear@0 294 for(i=0; i<4; i++) {
nuclear@0 295 for(j=0; j<4; j++) {
nuclear@0 296 *mat++ = vmat.M[j][i];
nuclear@0 297 }
nuclear@0 298 }
nuclear@0 299 }
nuclear@0 300
nuclear@0 301 static void begin(int eye)
nuclear@0 302 {
nuclear@0 303 if(!hmd) return;
nuclear@0 304
nuclear@0 305 if(!deferred_init_done) {
nuclear@0 306 deferred_init();
nuclear@0 307 }
nuclear@0 308
nuclear@19 309 if(!inside_begin_end) {
nuclear@0 310 ovrHmd_BeginFrame(hmd, 0);
nuclear@19 311 inside_begin_end = 1;
nuclear@0 312 }
nuclear@0 313 }
nuclear@0 314
nuclear@0 315 static int present(void)
nuclear@0 316 {
nuclear@24 317 int cur_prog;
nuclear@24 318
nuclear@0 319 if(!hmd) return 0;
nuclear@0 320
nuclear@24 321 glGetIntegerv(GL_CURRENT_PROGRAM, &cur_prog);
nuclear@24 322
nuclear@0 323 ovrHmd_EndFrame(hmd, pose, &eye_tex[0].Texture);
nuclear@19 324 inside_begin_end = 0;
nuclear@0 325
nuclear@24 326 if(cur_prog) {
nuclear@28 327 /*glUseProgram(0);*/
nuclear@24 328 }
nuclear@24 329
nuclear@0 330 return 1;
nuclear@0 331 }
nuclear@0 332
nuclear@0 333 static void set_eye_texture(int eye, unsigned int tex, float umin, float vmin, float umax, float vmax)
nuclear@0 334 {
nuclear@0 335 ovrSizei texsz;
nuclear@0 336 ovrRecti rect;
nuclear@0 337
nuclear@0 338 glBindTexture(GL_TEXTURE_2D, tex);
nuclear@0 339 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &texsz.w);
nuclear@0 340 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &texsz.h);
nuclear@0 341
nuclear@0 342 rect.Pos.x = (int)(umin * texsz.w);
nuclear@21 343 rect.Pos.y = (int)(vmin * texsz.h);
nuclear@0 344 rect.Size.w = (int)((umax - umin) * texsz.w);
nuclear@0 345 rect.Size.h = (int)((vmax - vmin) * texsz.h);
nuclear@0 346
nuclear@0 347 eye_tex[eye].OGL.Header.API = ovrRenderAPI_OpenGL;
nuclear@0 348 eye_tex[eye].OGL.Header.TextureSize = texsz;
nuclear@0 349 eye_tex[eye].OGL.Header.RenderViewport = rect;
nuclear@0 350 eye_tex[eye].OGL.TexId = tex;
nuclear@0 351 }
nuclear@0 352
nuclear@0 353 static void recenter(void)
nuclear@0 354 {
nuclear@0 355 if(hmd) {
nuclear@0 356 ovrHmd_RecenterPose(hmd);
nuclear@0 357 }
nuclear@0 358 }
nuclear@0 359
nuclear@0 360 struct vr_module *vr_module_libovr(void)
nuclear@0 361 {
nuclear@0 362 static struct vr_module m;
nuclear@0 363
nuclear@0 364 if(!m.init) {
nuclear@0 365 m.name = "libovr";
nuclear@0 366 m.init = init;
nuclear@0 367 m.cleanup = cleanup;
nuclear@0 368 m.set_option = set_option;
nuclear@0 369 m.get_option = get_option;
nuclear@0 370 m.translation = translation;
nuclear@0 371 m.rotation = rotation;
nuclear@0 372 m.proj_matrix = proj_matrix;
nuclear@0 373 m.begin = begin;
nuclear@0 374 m.present = present;
nuclear@0 375 m.set_eye_texture = set_eye_texture;
nuclear@0 376 m.recenter = recenter;
nuclear@0 377 }
nuclear@0 378 return &m;
nuclear@0 379 }
nuclear@0 380
nuclear@0 381 #else /* no libovr */
nuclear@0 382
nuclear@0 383 static int init(void)
nuclear@0 384 {
nuclear@0 385 return -1;
nuclear@0 386 }
nuclear@0 387
nuclear@0 388 struct vr_module *vr_module_libovr(void)
nuclear@0 389 {
nuclear@0 390 static struct vr_module m;
nuclear@0 391
nuclear@0 392 if(!m.init) {
nuclear@0 393 m.name = "libovr";
nuclear@0 394 m.init = init;
nuclear@0 395 }
nuclear@0 396 return &m;
nuclear@0 397 }
nuclear@0 398
nuclear@0 399 #endif /* USE_LIBOVR */