libgoatvr

annotate src/vr_libovr.c @ 19:437fe32ac633

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