openvr_test1

view src/app.cc @ 0:806d30b46748

OpenVR test initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 13 Apr 2016 09:39:37 +0300
parents
children
line source
1 #include <stdio.h>
2 #include <assert.h>
3 #include <GL/glew.h>
4 #include <openvr.h>
5 #include <gmath/gmath.h>
6 #include "app.h"
8 using namespace vr; // OpenVR namespace
10 static void draw_scene();
11 static void draw_box(float xsz, float ysz, float zsz, float norm_sign);
12 static Mat4 openvr_matrix4(const HmdMatrix44_t &mat);
13 static Mat4 openvr_matrix(const HmdMatrix34_t &mat);
14 static VRTextureBounds_t openvr_tex_bounds(float umin, float vmin, float umax, float vmax);
15 static void update_rtarg(int width, int height);
16 static unsigned int next_pow2(unsigned int x);
17 static unsigned int gen_chess_tex(float r0, float g0, float b0, float r1, float g1, float b1);
19 static int win_width, win_height;
21 static unsigned int fbo, fb_tex, fb_depth;
22 static int fb_width, fb_height;
23 static int fb_tex_width, fb_tex_height;
25 static unsigned int chess_tex;
27 // openvr stuff
28 static IVRSystem *vrsys;
29 static IVRCompositor *vrcomp;
30 static bool vrdev_state[k_unMaxTrackedDeviceCount];
31 static TrackedDevicePose_t vrdev_pose[k_unMaxTrackedDeviceCount];
32 static Mat4 eye_matrix[2];
33 static Mat4 proj_matrix[2];
34 static Texture_t vrtex = {0, API_OpenGL, ColorSpace_Linear};
35 static VRTextureBounds_t vrtex_bounds[2];
37 bool app_init()
38 {
39 glewInit();
41 glEnable(GL_DEPTH_TEST);
42 glEnable(GL_CULL_FACE);
43 glEnable(GL_LIGHTING);
44 glEnable(GL_LIGHT0);
45 glEnable(GL_LIGHT1);
46 glEnable(GL_NORMALIZE);
48 glClearColor(0.1, 0.1, 0.1, 1);
50 chess_tex = gen_chess_tex(1.0, 0.7, 0.4, 0.4, 0.7, 1.0);
52 // Initialize OpenVR
53 EVRInitError vrerr;
54 if(!(vrsys = VR_Init(&vrerr, VRApplication_Scene))) {
55 fprintf(stderr, "failed to initialize OpenVR: %s\n",
56 VR_GetVRInitErrorAsEnglishDescription(vrerr));
57 return false;
58 }
59 if(!(vrcomp = VRCompositor())) {
60 fprintf(stderr, "failed to initialize OpenVR compositor\n");
61 return false;
62 }
64 uint32_t xsz, ysz;
65 vrsys->GetRecommendedRenderTargetSize(&xsz, &ysz);
66 fb_width = xsz * 2;
67 fb_height = ysz;
68 update_rtarg(fb_width, fb_height); // create render target
70 for(int i=0; i<2; i++) {
71 EVREye eye = i == 0 ? Eye_Left : Eye_Right;
73 // projection matrix for each eye
74 proj_matrix[i] = openvr_matrix4(vrsys->GetProjectionMatrix(eye, 0.5, 500.0, API_OpenGL));
75 // eye (relative to head) matrix
76 eye_matrix[i] = openvr_matrix(vrsys->GetEyeToHeadTransform(eye));
77 }
79 // XXX this doesn't seem to work correctly for some reason
80 //vrcomp->ShowMirrorWindow();
82 assert(glGetError() == GL_NO_ERROR);
83 return true;
84 }
86 void app_shutdown()
87 {
88 // if we call VR_Shutdown while a frame is pending, we'll crash
89 vrcomp->ClearLastSubmittedFrame();
90 VR_Shutdown();
91 }
93 static void update()
94 {
95 // process OpenVR events (TODO: I think there are more events to handle)
96 VREvent_t ev;
97 while(vrsys->PollNextEvent(&ev, sizeof ev)) {
98 switch(ev.eventType) {
99 case VREvent_TrackedDeviceActivated:
100 printf("Device %u activated\n", ev.trackedDeviceIndex);
101 break;
103 case VREvent_TrackedDeviceDeactivated:
104 printf("Device %u lost\n", ev.trackedDeviceIndex);
105 break;
107 case VREvent_TrackedDeviceUpdated:
108 printf("Device %u updated(?)\n", ev.trackedDeviceIndex);
109 break;
110 }
111 }
113 // TODO implement controllers
114 for(int i=0; i<k_unMaxTrackedDeviceCount; i++) {
115 VRControllerState_t st;
116 if(vrsys->GetControllerState(i, &st)) {
117 // XXX ?
118 vrdev_state[i] = st.ulButtonPressed == 0;
119 }
120 }
122 // this will probably block at some point... investigate further
123 vrcomp->WaitGetPoses(vrdev_pose, k_unMaxTrackedDeviceCount, 0, 0);
124 }
126 void app_draw()
127 {
128 update();
130 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
131 glClearColor(0, 0, 0, 1);
132 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
134 for(int i=0; i<2; i++) {
135 EVREye eye = i == 0 ? Eye_Left : Eye_Right;
137 glViewport(i == 0 ? 0 : fb_width / 2, 0, fb_width / 2, fb_height);
139 glMatrixMode(GL_PROJECTION);
140 glLoadMatrixf(proj_matrix[i][0]);
142 Mat4 hmd_mat = openvr_matrix(vrdev_pose[k_unTrackedDeviceIndex_Hmd].mDeviceToAbsoluteTracking);
143 Mat4 view_mat = inverse(eye_matrix[i] * hmd_mat);
145 glMatrixMode(GL_MODELVIEW);
146 glLoadMatrixf(view_mat[0]);
148 draw_scene();
149 vrcomp->Submit(eye, &vrtex, vrtex_bounds + i);
150 }
151 /* this is supposed to tell the compositor to get on with showing the frame without waiting for
152 * the next WaitGetPoses call.
153 */
154 vrcomp->PostPresentHandoff();
156 glUseProgram(0);
158 // render window output
159 glBindFramebuffer(GL_FRAMEBUFFER, 0);
160 glViewport(0, 0, win_width, win_height);
162 glMatrixMode(GL_PROJECTION);
163 glLoadIdentity();
164 glMatrixMode(GL_MODELVIEW);
165 glLoadIdentity();
167 glPushAttrib(GL_ENABLE_BIT);
168 glBindTexture(GL_TEXTURE_2D, fb_tex);
169 glEnable(GL_TEXTURE_2D);
170 glDisable(GL_LIGHTING);
171 glDisable(GL_DEPTH_TEST);
173 glBegin(GL_QUADS);
174 float umax = (float)fb_width / fb_tex_width;
175 float vmax = (float)fb_height / fb_tex_height;
176 glTexCoord2f(0, 0); glVertex2f(-1, -1);
177 glTexCoord2f(umax, 0); glVertex2f(1, -1);
178 glTexCoord2f(umax, vmax); glVertex2f(1, 1);
179 glTexCoord2f(0, vmax); glVertex2f(-1, 1);
180 glEnd();
182 glPopAttrib();
184 app_swap_buffers();
185 }
187 void app_reshape(int x, int y)
188 {
189 win_width = x;
190 win_height = y;
191 glViewport(0, 0, x, y);
193 glMatrixMode(GL_PROJECTION);
194 glLoadIdentity();
195 gluPerspective(50, (float)x / (float)y, 0.5, 500.0);
196 }
198 static void draw_scene(void)
199 {
200 float grey[] = {0.8, 0.8, 0.8, 1};
201 float col[] = {0, 0, 0, 1};
202 float lpos[][4] = {
203 {-8, 2, 10, 1},
204 {0, 15, 0, 1}
205 };
206 float lcol[][4] = {
207 {0.8, 0.8, 0.8, 1},
208 {0.4, 0.3, 0.3, 1}
209 };
211 for(int i=0; i<2; i++) {
212 glLightfv(GL_LIGHT0 + i, GL_POSITION, lpos[i]);
213 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, lcol[i]);
214 }
216 glMatrixMode(GL_MODELVIEW);
218 glPushMatrix();
219 glTranslatef(0, 10, 0);
220 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, grey);
221 glBindTexture(GL_TEXTURE_2D, chess_tex);
222 glEnable(GL_TEXTURE_2D);
223 draw_box(30, 20, 30, -1.0);
224 glDisable(GL_TEXTURE_2D);
225 glPopMatrix();
227 for(int i=0; i<4; i++) {
228 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, grey);
229 glPushMatrix();
230 glTranslatef(i & 1 ? 5 : -5, 1, i & 2 ? -5 : 5);
231 draw_box(0.5, 2, 0.5, 1.0);
232 glPopMatrix();
234 col[0] = i & 1 ? 1.0 : 0.3;
235 col[1] = i == 0 ? 1.0 : 0.3;
236 col[2] = i & 2 ? 1.0 : 0.3;
237 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
239 glPushMatrix();
240 if(i & 1) {
241 glTranslatef(0, 0.25, i & 2 ? 2 : -2);
242 } else {
243 glTranslatef(i & 2 ? 2 : -2, 0.25, 0);
244 }
245 draw_box(0.5, 0.5, 0.5, 1.0);
246 glPopMatrix();
247 }
249 col[0] = 1;
250 col[1] = 1;
251 col[2] = 0.4;
252 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
253 draw_box(0.05, 1.2, 6, 1.0);
254 draw_box(6, 1.2, 0.05, 1.0);
255 }
257 static void draw_box(float xsz, float ysz, float zsz, float norm_sign)
258 {
259 glMatrixMode(GL_MODELVIEW);
260 glPushMatrix();
261 glScalef(xsz * 0.5, ysz * 0.5, zsz * 0.5);
263 if(norm_sign < 0.0) {
264 glFrontFace(GL_CW);
265 }
267 glBegin(GL_QUADS);
268 glNormal3f(0, 0, 1 * norm_sign);
269 glTexCoord2f(0, 0); glVertex3f(-1, -1, 1);
270 glTexCoord2f(1, 0); glVertex3f(1, -1, 1);
271 glTexCoord2f(1, 1); glVertex3f(1, 1, 1);
272 glTexCoord2f(0, 1); glVertex3f(-1, 1, 1);
273 glNormal3f(1 * norm_sign, 0, 0);
274 glTexCoord2f(0, 0); glVertex3f(1, -1, 1);
275 glTexCoord2f(1, 0); glVertex3f(1, -1, -1);
276 glTexCoord2f(1, 1); glVertex3f(1, 1, -1);
277 glTexCoord2f(0, 1); glVertex3f(1, 1, 1);
278 glNormal3f(0, 0, -1 * norm_sign);
279 glTexCoord2f(0, 0); glVertex3f(1, -1, -1);
280 glTexCoord2f(1, 0); glVertex3f(-1, -1, -1);
281 glTexCoord2f(1, 1); glVertex3f(-1, 1, -1);
282 glTexCoord2f(0, 1); glVertex3f(1, 1, -1);
283 glNormal3f(-1 * norm_sign, 0, 0);
284 glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
285 glTexCoord2f(1, 0); glVertex3f(-1, -1, 1);
286 glTexCoord2f(1, 1); glVertex3f(-1, 1, 1);
287 glTexCoord2f(0, 1); glVertex3f(-1, 1, -1);
288 glEnd();
289 glBegin(GL_TRIANGLE_FAN);
290 glNormal3f(0, 1 * norm_sign, 0);
291 glTexCoord2f(0.5, 0.5); glVertex3f(0, 1, 0);
292 glTexCoord2f(0, 0); glVertex3f(-1, 1, 1);
293 glTexCoord2f(1, 0); glVertex3f(1, 1, 1);
294 glTexCoord2f(1, 1); glVertex3f(1, 1, -1);
295 glTexCoord2f(0, 1); glVertex3f(-1, 1, -1);
296 glTexCoord2f(0, 0); glVertex3f(-1, 1, 1);
297 glEnd();
298 glBegin(GL_TRIANGLE_FAN);
299 glNormal3f(0, -1 * norm_sign, 0);
300 glTexCoord2f(0.5, 0.5); glVertex3f(0, -1, 0);
301 glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
302 glTexCoord2f(1, 0); glVertex3f(1, -1, -1);
303 glTexCoord2f(1, 1); glVertex3f(1, -1, 1);
304 glTexCoord2f(0, 1); glVertex3f(-1, -1, 1);
305 glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
306 glEnd();
308 glFrontFace(GL_CCW);
309 glPopMatrix();
310 }
312 static Mat4 openvr_matrix4(const HmdMatrix44_t &mat)
313 {
314 return Mat4(mat.m[0][0], mat.m[1][0], mat.m[2][0], mat.m[3][0],
315 mat.m[0][1], mat.m[1][1], mat.m[2][1], mat.m[3][1],
316 mat.m[0][2], mat.m[1][2], mat.m[2][2], mat.m[3][2],
317 mat.m[0][3], mat.m[1][3], mat.m[2][3], mat.m[3][3]);
318 }
320 static Mat4 openvr_matrix(const HmdMatrix34_t &mat)
321 {
322 return Mat4(mat.m[0][0], mat.m[1][0], mat.m[2][0], 0,
323 mat.m[0][1], mat.m[1][1], mat.m[2][1], 0,
324 mat.m[0][2], mat.m[1][2], mat.m[2][2], 0,
325 mat.m[0][3], mat.m[1][3], mat.m[2][3], 1);
326 }
328 static VRTextureBounds_t openvr_tex_bounds(float umin, float vmin, float umax, float vmax)
329 {
330 VRTextureBounds_t res;
331 res.uMin = umin;
332 res.uMax = umax;
333 res.vMin = vmin;
334 res.vMax = vmax;
335 return res;
336 }
338 /* update_rtarg creates (and/or resizes) the render target used to draw the two stero views */
339 static void update_rtarg(int width, int height)
340 {
341 if(!fbo) {
342 /* if fbo does not exist, then nothing does... create every opengl object */
343 glGenFramebuffers(1, &fbo);
344 glGenTextures(1, &fb_tex);
345 glGenRenderbuffers(1, &fb_depth);
347 glBindTexture(GL_TEXTURE_2D, fb_tex);
348 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
349 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
350 }
352 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
354 /* calculate the next power of two in both dimensions and use that as a texture size */
355 fb_tex_width = next_pow2(width);
356 fb_tex_height = next_pow2(height);
358 /* create and attach the texture that will be used as a color buffer */
359 glBindTexture(GL_TEXTURE_2D, fb_tex);
360 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, fb_tex_width, fb_tex_height, 0,
361 GL_RGBA, GL_UNSIGNED_BYTE, 0);
362 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb_tex, 0);
364 /* create and attach the renderbuffer that will serve as our z-buffer */
365 glBindRenderbuffer(GL_RENDERBUFFER, fb_depth);
366 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, fb_tex_width, fb_tex_height);
367 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fb_depth);
369 if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
370 fprintf(stderr, "incomplete framebuffer!\n");
371 }
373 glBindFramebuffer(GL_FRAMEBUFFER, 0);
374 printf("created render target: %dx%d (texture size: %dx%d)\n", width, height, fb_tex_width, fb_tex_height);
376 /* update the OpenVR texture descriptors */
377 vrtex.handle = (void*)fb_tex;
378 float umax = (float)fb_width / fb_tex_width;
379 float vmax = (float)fb_height / fb_tex_height;
380 vrtex_bounds[0] = openvr_tex_bounds(0, 1.0 - vmax, 0.5 * umax, 1.0);
381 vrtex_bounds[1] = openvr_tex_bounds(0.5 * umax, 1.0 - vmax, umax, 1.0);
382 }
385 void app_keyboard(int key, bool pressed)
386 {
387 if(pressed) {
388 switch(key) {
389 case 27:
390 app_quit();
391 break;
393 case ' ':
394 case 'r':
395 vrsys->ResetSeatedZeroPose();
396 break;
398 default:
399 break;
400 }
401 }
402 }
404 static unsigned int next_pow2(unsigned int x)
405 {
406 x -= 1;
407 x |= x >> 1;
408 x |= x >> 2;
409 x |= x >> 4;
410 x |= x >> 8;
411 x |= x >> 16;
412 return x + 1;
413 }
415 /* generate a chessboard texture with tiles colored (r0, g0, b0) and (r1, g1, b1) */
416 unsigned int gen_chess_tex(float r0, float g0, float b0, float r1, float g1, float b1)
417 {
418 unsigned int tex;
419 unsigned char img[8 * 8 * 3];
420 unsigned char *pix = img;
422 for(int i=0; i<8; i++) {
423 for(int j=0; j<8; j++) {
424 int black = (i & 1) == (j & 1);
425 pix[0] = (black ? r0 : r1) * 255;
426 pix[1] = (black ? g0 : g1) * 255;
427 pix[2] = (black ? b0 : b1) * 255;
428 pix += 3;
429 }
430 }
432 glGenTextures(1, &tex);
433 glBindTexture(GL_TEXTURE_2D, tex);
434 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
435 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
436 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, img);
438 return tex;
439 }