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