libgoatvr

view src/vr_libovr.c @ 30:1a8343ea54ce

fixed on windows
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 11 Apr 2015 04:01:47 +0300
parents ddaa9c764030
children
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 "opengl.h"
17 #include "opt.h"
19 #include <OVR_CAPI.h>
20 #include <OVR_CAPI_GL.h>
22 static PFNGLUSEPROGRAMPROC gl_use_program;
24 static ovrHmd hmd;
25 static void *optdb;
26 static ovrEyeRenderDesc eye_render_desc[2];
27 static ovrSizei eye_res[2];
28 static ovrGLTexture eye_tex[2];
29 static ovrFovPort eye_fov[2];
30 static ovrPosef pose[2] = {
31 { {0, 0, 0, 1}, {0, 0, 0} },
32 { {0, 0, 0, 1}, {0, 0, 0} }
33 };
34 static int deferred_init_done;
36 static int inside_begin_end;
38 static int init(void)
39 {
40 int i, num_hmds;
41 int use_fake = 0;
42 ovrTrackingCaps tracking;
44 if(!ovr_Initialize(0)) {
45 return -1;
46 }
47 printf("initialized LibOVR %s\n", ovr_GetVersionString());
49 if(!(num_hmds = ovrHmd_Detect())) {
50 if(getenv("VR_LIBOVR_FAKE")) {
51 use_fake = 1;
52 num_hmds = 1;
53 } else {
54 ovr_Shutdown();
55 return -1;
56 }
57 }
58 printf("%d Oculus HMD(s) found\n", num_hmds);
60 hmd = 0;
61 for(i=0; i<num_hmds; i++) {
62 ovrHmd h = use_fake ? ovrHmd_CreateDebug(ovrHmd_DK2) : ovrHmd_Create(i);
63 if(!h) {
64 break;
65 }
66 printf(" [%d]: %s - %s\n", i, h->Manufacturer, h->ProductName);
68 if(!hmd) {
69 hmd = h;
70 } else {
71 ovrHmd_Destroy(h);
72 }
73 }
75 if(!hmd) {
76 fprintf(stderr, "failed to initialize any Oculus HMDs\n");
77 return -1;
78 }
80 tracking = ovrTrackingCap_Orientation | ovrTrackingCap_Position |
81 ovrTrackingCap_MagYawCorrection;
82 ovrHmd_ConfigureTracking(hmd, tracking, 0);
84 eye_fov[0] = hmd->DefaultEyeFov[0];
85 eye_fov[1] = hmd->DefaultEyeFov[1];
87 eye_res[0] = ovrHmd_GetFovTextureSize(hmd, ovrEye_Left, eye_fov[0], 1.0);
88 eye_res[1] = ovrHmd_GetFovTextureSize(hmd, ovrEye_Right, eye_fov[1], 1.0);
90 /* create the options database */
91 if((optdb = create_options())) {
92 set_option_int(optdb, VR_DISPLAY_WIDTH, hmd->Resolution.w);
93 set_option_int(optdb, VR_DISPLAY_HEIGHT, hmd->Resolution.h);
94 set_option_int(optdb, VR_LEYE_XRES, eye_res[0].w);
95 set_option_int(optdb, VR_LEYE_YRES, eye_res[0].h);
96 set_option_int(optdb, VR_REYE_XRES, eye_res[1].w);
97 set_option_int(optdb, VR_REYE_YRES, eye_res[1].h);
98 set_option_int(optdb, VR_RENDER_XRES, eye_res[0].w + eye_res[1].w);
99 set_option_int(optdb, VR_RENDER_YRES, eye_res[0].h > eye_res[1].h ? eye_res[0].h : 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 if(!(gl_use_program = (PFNGLUSEPROGRAMPROC)vrimp_glfunc("glUseProgram"))) {
108 gl_use_program = (PFNGLUSEPROGRAMPROC)vrimp_glfunc("glUseProgramObjectARB");
109 }
111 deferred_init_done = 0;
112 return 0;
113 }
115 static void deferred_init(void)
116 {
117 union ovrGLConfig glcfg;
118 unsigned int dcaps;
119 void *win = 0;
120 float leye_offs[3], reye_offs[3];
122 deferred_init_done = 1;
124 memset(&glcfg, 0, sizeof glcfg);
125 glcfg.OGL.Header.API = ovrRenderAPI_OpenGL;
126 glcfg.OGL.Header.BackBufferSize = hmd->Resolution;
127 glcfg.OGL.Header.Multisample = 1;
128 #ifdef WIN32
129 win = GetActiveWindow();
130 glcfg.OGL.Window = win;
131 glcfg.OGL.DC = wglGetCurrentDC();
132 #else
133 glcfg.OGL.Disp = glXGetCurrentDisplay();
134 win = (void*)glXGetCurrentDrawable();
136 /* on linux the Oculus SDK docs are instructing users to leave the DK2 screen in
137 * portrait mode. So we'll have to flip width and height
138 */
139 glcfg.OGL.Header.BackBufferSize.w = hmd->Resolution.h;
140 glcfg.OGL.Header.BackBufferSize.h = hmd->Resolution.w;
141 #endif
143 if(!(hmd->HmdCaps & ovrHmdCap_ExtendDesktop)) {
144 ovrHmd_AttachToWindow(hmd, win, 0, 0);
145 printf("running in \"direct-to-rift\" mode\n");
146 } else {
147 printf("running in \"extended desktop\" mode\n");
148 }
149 ovrHmd_SetEnabledCaps(hmd, ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction);
151 dcaps = ovrDistortionCap_TimeWarp | ovrDistortionCap_Overdrive;
152 #ifdef OVR_OS_LINUX
153 dcaps |= ovrDistortionCap_LinuxDevFullscreen;
154 #endif
156 if(!ovrHmd_ConfigureRendering(hmd, &glcfg.Config, dcaps, eye_fov, eye_render_desc)) {
157 fprintf(stderr, "failed to configure LibOVR distortion renderer\n");
158 }
160 /* set the eye offset options */
161 leye_offs[0] = eye_render_desc[ovrEye_Left].HmdToEyeViewOffset.x;
162 leye_offs[1] = eye_render_desc[ovrEye_Left].HmdToEyeViewOffset.y;
163 leye_offs[2] = eye_render_desc[ovrEye_Left].HmdToEyeViewOffset.z;
164 reye_offs[0] = eye_render_desc[ovrEye_Right].HmdToEyeViewOffset.x;
165 reye_offs[1] = eye_render_desc[ovrEye_Right].HmdToEyeViewOffset.y;
166 reye_offs[2] = eye_render_desc[ovrEye_Right].HmdToEyeViewOffset.z;
168 /* sanity check ... on linux it seems I'm getting the eye offsets reversed for some reason */
169 if(leye_offs[0] > reye_offs[0]) {
170 fprintf(stderr, "BUG %s:%d: eye offset reversed?! fixing but wtf...\n", __FILE__, __LINE__);
171 set_option_vec(optdb, VR_LEYE_OFFSET, reye_offs);
172 set_option_vec(optdb, VR_REYE_OFFSET, leye_offs);
173 } else {
174 set_option_vec(optdb, VR_LEYE_OFFSET, leye_offs);
175 set_option_vec(optdb, VR_REYE_OFFSET, reye_offs);
176 }
177 }
179 static void cleanup(void)
180 {
181 if(hmd) {
182 ovrHmd_Destroy(hmd);
183 ovr_Shutdown();
184 }
185 destroy_options(optdb);
186 }
188 static int set_option(const char *opt, enum opt_type type, void *valp)
189 {
190 float fval;
192 switch(type) {
193 case OTYPE_INT:
194 fval = (float)*(int*)valp;
195 set_option_int(optdb, opt, *(int*)valp);
196 break;
198 case OTYPE_FLOAT:
199 fval = *(float*)valp;
200 set_option_float(optdb, opt, fval);
201 break;
203 case OTYPE_VEC:
204 set_option_vec(optdb, opt, valp);
205 break;
206 }
208 if(hmd && strcmp(opt, VR_RENDER_RES_SCALE) == 0) {
209 eye_res[0] = ovrHmd_GetFovTextureSize(hmd, ovrEye_Left, eye_fov[0], fval);
210 eye_res[1] = ovrHmd_GetFovTextureSize(hmd, ovrEye_Right, eye_fov[1], fval);
212 set_option_int(optdb, VR_LEYE_XRES, eye_res[0].w);
213 set_option_int(optdb, VR_LEYE_YRES, eye_res[0].h);
214 set_option_int(optdb, VR_REYE_XRES, eye_res[1].w);
215 set_option_int(optdb, VR_REYE_YRES, eye_res[1].h);
216 }
218 return 0;
219 }
221 static int get_option(const char *opt, enum opt_type type, void *valp)
222 {
223 switch(type) {
224 case OTYPE_INT:
225 return get_option_int(optdb, opt, valp);
226 case OTYPE_FLOAT:
227 return get_option_float(optdb, opt, valp);
228 case OTYPE_VEC:
229 return get_option_vec(optdb, opt, valp);
230 }
231 return -1;
232 }
234 static void translation(int eye, float *vec)
235 {
236 if(!hmd) {
237 vec[0] = vec[1] = vec[2] = 0;
238 return;
239 }
241 /* if we're inside the begin-end block we can get a fresh pose, otherwise we'll just
242 * reuse the one we got last frame.
243 */
244 if(inside_begin_end) {
245 pose[eye] = ovrHmd_GetHmdPosePerEye(hmd, eye == VR_EYE_LEFT ? ovrEye_Left : ovrEye_Right);
246 }
248 vec[0] = pose[eye].Position.x;
249 vec[1] = pose[eye].Position.y;
250 vec[2] = pose[eye].Position.z;
251 }
253 static void rotation(int eye, float *quat)
254 {
255 if(!hmd) {
256 quat[0] = quat[1] = quat[2] = 0.0f;
257 quat[3] = 1.0f;
258 return;
259 }
261 /* same as above (translation) */
262 if(inside_begin_end) {
263 pose[eye] = ovrHmd_GetHmdPosePerEye(hmd, eye == VR_EYE_LEFT ? ovrEye_Left : ovrEye_Right);
264 }
266 quat[0] = pose[eye].Orientation.x;
267 quat[1] = pose[eye].Orientation.y;
268 quat[2] = pose[eye].Orientation.z;
269 quat[3] = pose[eye].Orientation.w;
270 }
272 static const float idmat[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
274 static void proj_matrix(int eye, float znear, float zfar, float *mat)
275 {
276 int i, j;
277 ovrMatrix4f vmat;
279 if(!hmd) {
280 memcpy(mat, idmat, sizeof idmat);
281 return;
282 }
284 vmat = ovrMatrix4f_Projection(eye_render_desc[eye].Fov, znear, zfar, 1);
286 for(i=0; i<4; i++) {
287 for(j=0; j<4; j++) {
288 *mat++ = vmat.M[j][i];
289 }
290 }
291 }
293 static void begin(int eye)
294 {
295 if(!hmd) return;
297 if(!deferred_init_done) {
298 deferred_init();
299 }
301 if(!inside_begin_end) {
302 ovrHmd_BeginFrame(hmd, 0);
303 inside_begin_end = 1;
304 }
305 }
307 static int present(void)
308 {
309 int cur_prog = 0;
311 if(!hmd) return 0;
313 if(gl_use_program) {
314 glGetIntegerv(GL_CURRENT_PROGRAM, &cur_prog);
315 }
317 ovrHmd_EndFrame(hmd, pose, &eye_tex[0].Texture);
318 inside_begin_end = 0;
320 if(gl_use_program) {
321 gl_use_program(cur_prog);
322 }
324 return 1;
325 }
327 static void set_eye_texture(int eye, unsigned int tex, float umin, float vmin, float umax, float vmax)
328 {
329 ovrSizei texsz;
330 ovrRecti rect;
332 glBindTexture(GL_TEXTURE_2D, tex);
333 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &texsz.w);
334 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &texsz.h);
336 rect.Pos.x = (int)(umin * texsz.w);
337 rect.Pos.y = (int)(vmin * texsz.h);
338 rect.Size.w = (int)((umax - umin) * texsz.w);
339 rect.Size.h = (int)((vmax - vmin) * texsz.h);
341 eye_tex[eye].OGL.Header.API = ovrRenderAPI_OpenGL;
342 eye_tex[eye].OGL.Header.TextureSize = texsz;
343 eye_tex[eye].OGL.Header.RenderViewport = rect;
344 eye_tex[eye].OGL.TexId = tex;
345 }
347 static void recenter(void)
348 {
349 if(hmd) {
350 ovrHmd_RecenterPose(hmd);
351 }
352 }
354 struct vr_module *vr_module_libovr(void)
355 {
356 static struct vr_module m;
358 if(!m.init) {
359 m.name = "libovr";
360 m.init = init;
361 m.cleanup = cleanup;
362 m.set_option = set_option;
363 m.get_option = get_option;
364 m.translation = translation;
365 m.rotation = rotation;
366 m.proj_matrix = proj_matrix;
367 m.begin = begin;
368 m.present = present;
369 m.set_eye_texture = set_eye_texture;
370 m.recenter = recenter;
371 }
372 return &m;
373 }
375 #else /* no libovr */
377 static int init(void)
378 {
379 return -1;
380 }
382 struct vr_module *vr_module_libovr(void)
383 {
384 static struct vr_module m;
386 if(!m.init) {
387 m.name = "libovr";
388 m.init = init;
389 }
390 return &m;
391 }
393 #endif /* USE_LIBOVR */