nuclear@0: #ifdef WIN32 nuclear@0: #define OVR_OS_WIN32 nuclear@0: #endif nuclear@0: nuclear@0: #include "vr_impl.h" nuclear@0: nuclear@0: #ifdef USE_LIBOVR nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include "opt.h" nuclear@0: nuclear@0: #include nuclear@0: #include nuclear@0: nuclear@0: #define DISABLE_RETARDED_HEALTH_WARNING nuclear@0: nuclear@0: /* just dropping the prototype here to avoid including CAPI_HSWDisplay.h */ nuclear@0: OVR_EXPORT void ovrhmd_EnableHSWDisplaySDKRender(ovrHmd hmd, ovrBool enabled); nuclear@0: nuclear@0: static ovrHmd hmd; nuclear@0: static void *optdb; nuclear@0: static ovrEyeRenderDesc eye_render_desc[2]; nuclear@0: static ovrSizei eye_res[2]; nuclear@0: static ovrGLTexture eye_tex[2]; nuclear@0: static ovrFovPort eye_fov[2]; nuclear@0: static ovrPosef pose[2]; nuclear@0: static int deferred_init_done; nuclear@0: nuclear@0: static int init(void) nuclear@0: { nuclear@0: int i, num_hmds; nuclear@0: nuclear@0: if(!ovr_Initialize()) { nuclear@0: return -1; nuclear@0: } nuclear@0: printf("initialized LibOVR %s\n", ovr_GetVersionString()); nuclear@0: nuclear@0: if(!(num_hmds = ovrHmd_Detect())) { nuclear@0: ovr_Shutdown(); nuclear@0: return -1; nuclear@0: } nuclear@0: printf("%d Oculus HMD(s) found\n", num_hmds); nuclear@0: nuclear@0: hmd = 0; nuclear@0: for(i=0; iManufacturer, h->ProductName); nuclear@0: nuclear@0: if(!hmd) { nuclear@0: hmd = h; nuclear@0: } else { nuclear@0: ovrHmd_Destroy(h); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if(!hmd) { nuclear@0: fprintf(stderr, "failed to initialize any Oculus HMDs\n"); nuclear@0: return -1; nuclear@0: } nuclear@0: nuclear@0: ovrHmd_ConfigureTracking(hmd, 0xffffffff, 0); nuclear@0: nuclear@0: eye_fov[0] = hmd->DefaultEyeFov[0]; nuclear@0: eye_fov[1] = hmd->DefaultEyeFov[1]; nuclear@0: nuclear@0: eye_res[0] = ovrHmd_GetFovTextureSize(hmd, ovrEye_Left, eye_fov[0], 1.0); nuclear@0: eye_res[1] = ovrHmd_GetFovTextureSize(hmd, ovrEye_Right, eye_fov[1], 1.0); nuclear@0: nuclear@0: /* create the options database */ nuclear@0: if((optdb = create_options())) { nuclear@0: set_option_int(optdb, VR_OPT_DISPLAY_WIDTH, hmd->Resolution.w); nuclear@0: set_option_int(optdb, VR_OPT_DISPLAY_HEIGHT, hmd->Resolution.h); nuclear@0: set_option_int(optdb, VR_OPT_LEYE_XRES, eye_res[0].w); nuclear@0: set_option_int(optdb, VR_OPT_LEYE_YRES, eye_res[0].h); nuclear@0: set_option_int(optdb, VR_OPT_REYE_XRES, eye_res[1].w); nuclear@0: set_option_int(optdb, VR_OPT_REYE_YRES, eye_res[1].h); nuclear@0: set_option_float(optdb, VR_OPT_EYE_HEIGHT, ovrHmd_GetFloat(hmd, OVR_KEY_EYE_HEIGHT, OVR_DEFAULT_EYE_HEIGHT)); nuclear@0: set_option_float(optdb, VR_OPT_IPD, ovrHmd_GetFloat(hmd, OVR_KEY_IPD, OVR_DEFAULT_IPD)); nuclear@0: set_option_int(optdb, VR_OPT_WIN_XOFFS, hmd->WindowsPos.x); nuclear@0: set_option_int(optdb, VR_OPT_WIN_YOFFS, hmd->WindowsPos.y); nuclear@0: } nuclear@0: nuclear@0: deferred_init_done = 0; nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: static void deferred_init(void) nuclear@0: { nuclear@0: union ovrGLConfig glcfg; nuclear@0: unsigned int dcaps; nuclear@0: void *win = 0; nuclear@0: nuclear@0: deferred_init_done = 1; nuclear@0: nuclear@0: memset(&glcfg, 0, sizeof glcfg); nuclear@0: glcfg.OGL.Header.API = ovrRenderAPI_OpenGL; nuclear@0: glcfg.OGL.Header.RTSize = hmd->Resolution; nuclear@0: glcfg.OGL.Header.Multisample = 1; nuclear@0: #ifdef WIN32 nuclear@0: win = GetActiveWindow(); nuclear@0: /*glcfg.OGL.Window = win; nuclear@0: glcfg.OGL.DC = wglGetCurrentDC(); nuclear@0: assert(glcfg.OGL.Window); nuclear@0: assert(glcfg.OGL.DC);*/ nuclear@0: #endif nuclear@0: nuclear@0: if(!(hmd->HmdCaps & ovrHmdCap_ExtendDesktop)) { nuclear@0: ovrHmd_AttachToWindow(hmd, win, 0, 0); nuclear@0: printf("running in \"direct-to-rift\" mode\n"); nuclear@0: } else { nuclear@0: printf("running in \"extended desktop\" mode\n"); nuclear@0: } nuclear@0: ovrHmd_SetEnabledCaps(hmd, ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction); nuclear@0: nuclear@0: dcaps = ovrDistortionCap_Chromatic | ovrDistortionCap_Vignette | ovrDistortionCap_TimeWarp | nuclear@0: ovrDistortionCap_Overdrive | ovrDistortionCap_NoRestore; nuclear@0: nuclear@0: if(!ovrHmd_ConfigureRendering(hmd, &glcfg.Config, dcaps, eye_fov, eye_render_desc)) { nuclear@0: fprintf(stderr, "failed to configure LibOVR distortion renderer\n"); nuclear@0: } nuclear@0: nuclear@0: #ifdef DISABLE_RETARDED_HEALTH_WARNING nuclear@0: ovrhmd_EnableHSWDisplaySDKRender(hmd, 0); nuclear@0: #endif nuclear@0: } nuclear@0: nuclear@0: static void cleanup(void) nuclear@0: { nuclear@0: if(hmd) { nuclear@0: ovrHmd_Destroy(hmd); nuclear@0: ovr_Shutdown(); nuclear@0: } nuclear@5: destroy_options(optdb); nuclear@0: } nuclear@0: nuclear@0: static int set_option(const char *opt, enum opt_type type, void *valp) nuclear@0: { nuclear@0: switch(type) { nuclear@0: case OTYPE_INT: nuclear@0: set_option_int(optdb, opt, *(int*)valp); nuclear@0: break; nuclear@0: nuclear@0: case OTYPE_FLOAT: nuclear@0: set_option_float(optdb, opt, *(float*)valp); nuclear@0: break; nuclear@0: } nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: static int get_option(const char *opt, enum opt_type type, void *valp) nuclear@0: { nuclear@0: switch(type) { nuclear@0: case OTYPE_INT: nuclear@0: return get_option_int(optdb, opt, valp); nuclear@0: case OTYPE_FLOAT: nuclear@0: return get_option_float(optdb, opt, valp); nuclear@0: } nuclear@0: return -1; nuclear@0: } nuclear@0: nuclear@7: static void translation(int eye, float *vec) nuclear@0: { nuclear@0: if(!hmd) { nuclear@0: vec[0] = vec[1] = vec[2] = 0; nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: pose[eye] = ovrHmd_GetEyePose(hmd, eye == VR_EYE_LEFT ? ovrEye_Left : ovrEye_Right); nuclear@0: vec[0] = pose[eye].Position.x + eye_render_desc[eye].ViewAdjust.x; nuclear@0: vec[1] = pose[eye].Position.y + eye_render_desc[eye].ViewAdjust.y; nuclear@0: vec[2] = pose[eye].Position.z + eye_render_desc[eye].ViewAdjust.z; nuclear@0: nuclear@0: return 1; nuclear@0: } nuclear@0: nuclear@7: static void rotation(int eye, float *quat) nuclear@0: { nuclear@0: if(!hmd) { nuclear@0: quat[0] = quat[1] = quat[2] = 0.0f; nuclear@0: quat[3] = 1.0f; nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: pose[eye] = ovrHmd_GetEyePose(hmd, eye == VR_EYE_LEFT ? ovrEye_Left : ovrEye_Right); nuclear@0: quat[0] = pose[eye].Orientation.x; nuclear@0: quat[1] = pose[eye].Orientation.y; nuclear@0: quat[2] = pose[eye].Orientation.z; nuclear@0: quat[3] = pose[eye].Orientation.w; nuclear@0: return 1; nuclear@0: } nuclear@0: nuclear@0: static const float idmat[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; nuclear@0: nuclear@0: static void proj_matrix(int eye, float znear, float zfar, float *mat) nuclear@0: { nuclear@0: int i, j; nuclear@0: ovrMatrix4f vmat; nuclear@0: nuclear@0: if(!hmd) { nuclear@0: memcpy(mat, idmat, sizeof idmat); nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: vmat = ovrMatrix4f_Projection(eye_render_desc[eye].Fov, znear, zfar, 1); nuclear@0: nuclear@0: for(i=0; i<4; i++) { nuclear@0: for(j=0; j<4; j++) { nuclear@0: *mat++ = vmat.M[j][i]; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: static int new_frame = 1; nuclear@0: nuclear@0: static void begin(int eye) nuclear@0: { nuclear@0: if(!hmd) return; nuclear@0: nuclear@0: if(!deferred_init_done) { nuclear@0: deferred_init(); nuclear@0: } nuclear@0: nuclear@0: if(new_frame) { nuclear@0: ovrHmd_BeginFrame(hmd, 0); nuclear@0: new_frame = 0; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: static int present(void) nuclear@0: { nuclear@0: if(!hmd) return 0; nuclear@0: nuclear@0: ovrHmd_EndFrame(hmd, pose, &eye_tex[0].Texture); nuclear@0: new_frame = 1; nuclear@0: nuclear@0: return 1; nuclear@0: } nuclear@0: nuclear@0: static void set_eye_texture(int eye, unsigned int tex, float umin, float vmin, float umax, float vmax) nuclear@0: { nuclear@0: ovrSizei texsz; nuclear@0: ovrRecti rect; nuclear@0: nuclear@0: glBindTexture(GL_TEXTURE_2D, tex); nuclear@0: glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &texsz.w); nuclear@0: glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &texsz.h); nuclear@0: nuclear@0: rect.Pos.x = (int)(umin * texsz.w); nuclear@0: rect.Pos.y = (int)((vmin + 1.0 - vmax) * texsz.h); nuclear@0: rect.Size.w = (int)((umax - umin) * texsz.w); nuclear@0: rect.Size.h = (int)((vmax - vmin) * texsz.h); nuclear@0: nuclear@0: eye_tex[eye].OGL.Header.API = ovrRenderAPI_OpenGL; nuclear@0: eye_tex[eye].OGL.Header.TextureSize = texsz; nuclear@0: eye_tex[eye].OGL.Header.RenderViewport = rect; nuclear@0: eye_tex[eye].OGL.TexId = tex; nuclear@0: } nuclear@0: nuclear@0: static void recenter(void) nuclear@0: { nuclear@0: if(hmd) { nuclear@0: ovrHmd_RecenterPose(hmd); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: struct vr_module *vr_module_libovr(void) nuclear@0: { nuclear@0: static struct vr_module m; nuclear@0: nuclear@0: if(!m.init) { nuclear@0: m.name = "libovr"; nuclear@0: m.init = init; nuclear@0: m.cleanup = cleanup; nuclear@0: m.set_option = set_option; nuclear@0: m.get_option = get_option; nuclear@0: m.translation = translation; nuclear@0: m.rotation = rotation; nuclear@0: m.proj_matrix = proj_matrix; nuclear@0: m.begin = begin; nuclear@0: m.present = present; nuclear@0: m.set_eye_texture = set_eye_texture; nuclear@0: m.recenter = recenter; nuclear@0: } nuclear@0: return &m; nuclear@0: } nuclear@0: nuclear@0: #else /* no libovr */ nuclear@0: nuclear@0: static int init(void) nuclear@0: { nuclear@0: return -1; nuclear@0: } nuclear@0: nuclear@0: struct vr_module *vr_module_libovr(void) nuclear@0: { nuclear@0: static struct vr_module m; nuclear@0: nuclear@0: if(!m.init) { nuclear@0: m.name = "libovr"; nuclear@0: m.init = init; nuclear@0: } nuclear@0: return &m; nuclear@0: } nuclear@0: nuclear@0: #endif /* USE_LIBOVR */