libgoatvr

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