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