oculus2
changeset 4:d64830551c32
hurray, it works
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 04 Sep 2014 08:31:12 +0300 |
parents | 096b18432ba7 |
children | cd9f1560b909 |
files | src/main.c |
diffstat | 1 files changed, 185 insertions(+), 74 deletions(-) [+] |
line diff
1.1 --- a/src/main.c Tue Aug 26 18:37:24 2014 +0300 1.2 +++ b/src/main.c Thu Sep 04 08:31:12 2014 +0300 1.3 @@ -16,6 +16,7 @@ 1.4 1.5 int init(void); 1.6 void cleanup(void); 1.7 +void toggle_hmd_fullscreen(void); 1.8 void display(void); 1.9 void draw_scene(void); 1.10 void draw_box(float xsz, float ysz, float zsz, float norm_sign); 1.11 @@ -24,7 +25,10 @@ 1.12 int key_event(int key, int state); 1.13 void reshape(int x, int y); 1.14 unsigned int next_pow2(unsigned int x); 1.15 +void quat_to_matrix(const float *quat, float *mat); 1.16 +unsigned int gen_chess_tex(float r0, float g0, float b0, float r1, float g1, float b1); 1.17 1.18 +/* forward declaration to avoid including non-public headers of libovr */ 1.19 OVR_EXPORT void ovrhmd_EnableHSWDisplaySDKRender(ovrHmd hmd, ovrBool enable); 1.20 1.21 static SDL_Window *win; 1.22 @@ -40,8 +44,10 @@ 1.23 static ovrEyeRenderDesc eye_rdesc[2]; 1.24 static ovrGLTexture fb_ovr_tex[2]; 1.25 1.26 +static unsigned int chess_tex; 1.27 1.28 -int main(void) 1.29 + 1.30 +int main(int argc, char **argv) 1.31 { 1.32 if(init() == -1) { 1.33 return 1; 1.34 @@ -49,13 +55,11 @@ 1.35 1.36 for(;;) { 1.37 SDL_Event ev; 1.38 - 1.39 while(SDL_PollEvent(&ev)) { 1.40 if(handle_event(&ev) == -1) { 1.41 goto done; 1.42 } 1.43 } 1.44 - 1.45 display(); 1.46 } 1.47 1.48 @@ -71,14 +75,14 @@ 1.49 unsigned int flags, dcaps; 1.50 union ovrGLConfig glcfg; 1.51 1.52 - // this must be called before any OpenGL init according to the docs 1.53 + /* libovr must be initialized before we create the OpenGL context */ 1.54 ovr_Initialize(); 1.55 1.56 SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER); 1.57 1.58 x = y = SDL_WINDOWPOS_UNDEFINED; 1.59 flags = SDL_WINDOW_OPENGL; 1.60 - if(!(win = SDL_CreateWindow("simple oculus example", x, y, 1280, 800, flags))) { 1.61 + if(!(win = SDL_CreateWindow("press 'f' to move to the HMD", x, y, 1280, 800, flags))) { 1.62 fprintf(stderr, "failed to create window\n"); 1.63 return -1; 1.64 } 1.65 @@ -99,13 +103,14 @@ 1.66 printf("initialized HMD: %s - %s\n", hmd->Manufacturer, hmd->ProductName); 1.67 1.68 SDL_SetWindowSize(win, hmd->Resolution.w, hmd->Resolution.h); 1.69 + SDL_SetWindowPosition(win, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); 1.70 + win_width = hmd->Resolution.w; 1.71 + win_height = hmd->Resolution.h; 1.72 1.73 ovrHmd_ConfigureTracking(hmd, 0xffffffff, 0); 1.74 eyeres[0] = ovrHmd_GetFovTextureSize(hmd, ovrEye_Left, hmd->DefaultEyeFov[0], 1.0); 1.75 eyeres[1] = ovrHmd_GetFovTextureSize(hmd, ovrEye_Right, hmd->DefaultEyeFov[1], 1.0); 1.76 1.77 - SDL_GetWindowSize(win, &win_width, &win_height); 1.78 - 1.79 fb_width = eyeres[0].w + eyeres[1].w; 1.80 fb_height = eyeres[0].h > eyeres[1].h ? eyeres[0].h : eyeres[1].h; 1.81 update_rtarg(fb_width, fb_height); 1.82 @@ -139,7 +144,7 @@ 1.83 } 1.84 ovrHmd_SetEnabledCaps(hmd, ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction); 1.85 1.86 - dcaps = ovrDistortionCap_Chromatic | ovrDistortionCap_Vignette;// | ovrDistortionCap_TimeWarp; 1.87 + dcaps = ovrDistortionCap_Chromatic | ovrDistortionCap_Vignette | ovrDistortionCap_TimeWarp; 1.88 if(!ovrHmd_ConfigureRendering(hmd, &glcfg.Config, dcaps, hmd->DefaultEyeFov, eye_rdesc)) { 1.89 fprintf(stderr, "failed to configure distortion renderer\n"); 1.90 } 1.91 @@ -150,9 +155,12 @@ 1.92 glEnable(GL_CULL_FACE); 1.93 glEnable(GL_LIGHTING); 1.94 glEnable(GL_LIGHT0); 1.95 + glEnable(GL_LIGHT1); 1.96 + glEnable(GL_NORMALIZE); 1.97 1.98 - glClearColor(0.05, 0.05, 0.05, 1); 1.99 + glClearColor(0.1, 0.1, 0.1, 1); 1.100 1.101 + chess_tex = gen_chess_tex(1.0, 0.7, 0.4, 0.4, 0.7, 1.0); 1.102 return 0; 1.103 } 1.104 1.105 @@ -166,77 +174,79 @@ 1.106 SDL_Quit(); 1.107 } 1.108 1.109 +void toggle_hmd_fullscreen(void) 1.110 +{ 1.111 + static int fullscr, prev_x, prev_y; 1.112 + fullscr = !fullscr; 1.113 + 1.114 + if(fullscr) { 1.115 + SDL_GetWindowPosition(win, &prev_x, &prev_y); 1.116 + SDL_SetWindowPosition(win, hmd->WindowsPos.x, hmd->WindowsPos.y); 1.117 + SDL_SetWindowFullscreen(win, SDL_WINDOW_FULLSCREEN_DESKTOP); 1.118 + } else { 1.119 + SDL_SetWindowFullscreen(win, 0); 1.120 + SDL_SetWindowPosition(win, prev_x, prev_y); 1.121 + } 1.122 +} 1.123 + 1.124 void display(void) 1.125 { 1.126 int i; 1.127 ovrMatrix4f proj; 1.128 ovrPosef pose[2]; 1.129 + float rot_mat[16]; 1.130 1.131 + /* the drawing starts with a call to ovrHmd_BeginFrame */ 1.132 ovrHmd_BeginFrame(hmd, 0); 1.133 1.134 + /* start drawing onto our texture render target */ 1.135 glBindFramebuffer(GL_FRAMEBUFFER, fbo); 1.136 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 1.137 1.138 - glViewport(0, 0, fb_width, fb_height); 1.139 - 1.140 - /*glMatrixMode(GL_PROJECTION); 1.141 - glLoadIdentity(); 1.142 - glMatrixMode(GL_MODELVIEW); 1.143 - glLoadIdentity(); 1.144 - 1.145 - glPushAttrib(GL_ENABLE_BIT); 1.146 - glDisable(GL_LIGHTING); 1.147 - glDisable(GL_DEPTH_TEST); 1.148 - 1.149 - glBegin(GL_QUADS); 1.150 - glColor3f(1, 0, 0); 1.151 - glVertex2f(-1, -1); 1.152 - glVertex2f(0, -1); 1.153 - glVertex2f(0, 1); 1.154 - glVertex2f(-1, 1); 1.155 - 1.156 - glColor3f(1, 0, 1); 1.157 - glVertex2f(-0.6, -0.1); 1.158 - glVertex2f(-0.4, -0.1); 1.159 - glVertex2f(-0.4, 0.1); 1.160 - glVertex2f(-0.6, 0.1); 1.161 - 1.162 - glColor3f(0, 1, 0); 1.163 - glVertex2f(0, -1); 1.164 - glVertex2f(1, -1); 1.165 - glVertex2f(1, 1); 1.166 - glVertex2f(0, 1); 1.167 - 1.168 - glColor3f(0, 1, 1); 1.169 - glVertex2f(0.4, -0.1); 1.170 - glVertex2f(0.6, -0.1); 1.171 - glVertex2f(0.6, 0.1); 1.172 - glVertex2f(0.4, 0.1); 1.173 - glEnd(); 1.174 - 1.175 - glPopAttrib();*/ 1.176 - 1.177 /* for each eye ... */ 1.178 for(i=0; i<2; i++) { 1.179 int eye = hmd->EyeRenderOrder[i]; 1.180 1.181 - /* vport0(0, 0, width/2, height), vport1(width/2, 0, width/2, height) */ 1.182 + /* -- viewport transformation -- 1.183 + * setup the viewport to draw in the left half of the framebuffer when we're 1.184 + * rendering the left eye's view (0, 0, width/2, height), and in the right half 1.185 + * of the framebuffer for the right eye's view (width/2, 0, width/2, height) 1.186 + */ 1.187 glViewport(eye == 0 ? 0 : fb_width / 2, 0, fb_width / 2, fb_height); 1.188 1.189 + /* -- projection transformation -- 1.190 + * we'll just have to use the projection matrix supplied by the oculus SDK for this eye 1.191 + * note that libovr matrices are the transpose of what OpenGL expects, so we have to 1.192 + * use glLoadTransposeMatrixf instead of glLoadMatrixf to load it. 1.193 + */ 1.194 proj = ovrMatrix4f_Projection(hmd->DefaultEyeFov[eye], 0.5, 500.0, 1); 1.195 glMatrixMode(GL_PROJECTION); 1.196 - //glLoadMatrixf(proj.M[0]); 1.197 - glLoadIdentity(); 1.198 - gluPerspective(50.0, (float)fb_width / 2.0 / (float)fb_height, 0.5, 500.0); 1.199 + glLoadTransposeMatrixf(proj.M[0]); 1.200 1.201 + /* -- view/camera transformation -- 1.202 + * we need to construct a view matrix by combining all the information provided by the oculus 1.203 + * SDK, about the position and orientation of the user's head in the world. 1.204 + */ 1.205 pose[eye] = ovrHmd_GetEyePose(hmd, eye); 1.206 glMatrixMode(GL_MODELVIEW); 1.207 - /* TODO: get HMD orientation data and use it */ 1.208 - //glTranslatef(0, -ovrHmd_GetFloat(hmd, OVR_KEY_EYE_HEIGHT, 1.65), 0); 1.209 + glLoadIdentity(); 1.210 + glTranslatef(eye_rdesc[eye].ViewAdjust.x, eye_rdesc[eye].ViewAdjust.y, eye_rdesc[eye].ViewAdjust.z); 1.211 + /* retrieve the orientation quaternion and convert it to a rotation matrix */ 1.212 + quat_to_matrix(&pose[eye].Orientation.x, rot_mat); 1.213 + glMultMatrixf(rot_mat); 1.214 + /* translate the view matrix with the positional tracking */ 1.215 + glTranslatef(-pose[eye].Position.x, -pose[eye].Position.y, -pose[eye].Position.z); 1.216 + /* move the camera to the eye level of the user */ 1.217 + glTranslatef(0, -ovrHmd_GetFloat(hmd, OVR_KEY_EYE_HEIGHT, 1.65), 0); 1.218 1.219 + /* finally draw the scene for this eye */ 1.220 draw_scene(); 1.221 } 1.222 1.223 + /* after drawing both eyes into the texture render target, revert to drawing directly to the 1.224 + * display, and we call ovrHmd_EndFrame, to let the Oculus SDK draw both images properly 1.225 + * compensated for lens distortion and chromatic abberation onto the HMD screen. 1.226 + */ 1.227 glBindFramebuffer(GL_FRAMEBUFFER, 0); 1.228 glViewport(0, 0, win_width, win_height); 1.229 1.230 @@ -248,25 +258,52 @@ 1.231 void draw_scene(void) 1.232 { 1.233 int i; 1.234 - float lpos[] = {0, 5, 0, 1}; 1.235 - glLightfv(GL_LIGHT0, GL_POSITION, lpos); 1.236 + float grey[] = {0.8, 0.8, 0.8, 1}; 1.237 + float col[] = {0, 0, 0, 1}; 1.238 + float lpos[][4] = { 1.239 + {-8, 2, 10, 1}, 1.240 + {0, 15, 0, 1} 1.241 + }; 1.242 + float lcol[][4] = { 1.243 + {0.8, 0.8, 0.8, 1}, 1.244 + {0.4, 0.3, 0.3, 1} 1.245 + }; 1.246 + 1.247 + for(i=0; i<2; i++) { 1.248 + glLightfv(GL_LIGHT0 + i, GL_POSITION, lpos[i]); 1.249 + glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, lcol[i]); 1.250 + } 1.251 + 1.252 + glMatrixMode(GL_MODELVIEW); 1.253 1.254 glPushMatrix(); 1.255 - glTranslatef(0, 0, -8); 1.256 - draw_box(2, 2, 2, 1.0); 1.257 + glTranslatef(0, 10, 0); 1.258 + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, grey); 1.259 + glBindTexture(GL_TEXTURE_2D, chess_tex); 1.260 + glEnable(GL_TEXTURE_2D); 1.261 + draw_box(30, 20, 30, -1.0); 1.262 + glDisable(GL_TEXTURE_2D); 1.263 glPopMatrix(); 1.264 1.265 - glTranslatef(0, 5, 0); 1.266 - draw_box(20, 10, 20, -1.0); 1.267 + for(i=0; i<4; i++) { 1.268 + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, grey); 1.269 + glPushMatrix(); 1.270 + glTranslatef(i & 1 ? 5 : -5, 1, i & 2 ? -5 : 5); 1.271 + draw_box(0.5, 2, 0.5, 1.0); 1.272 + glPopMatrix(); 1.273 1.274 - for(i=0; i<4; i++) { 1.275 + col[0] = i & 1 ? 1.0 : 0.3; 1.276 + col[1] = i == 0 ? 1.0 : 0.3; 1.277 + col[2] = i & 2 ? 1.0 : 0.3; 1.278 + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col); 1.279 + 1.280 glPushMatrix(); 1.281 if(i & 1) { 1.282 - glTranslatef(0, 0, i & 2 ? 7.5 : -7.5); 1.283 + glTranslatef(0, 0.25, i & 2 ? 2 : -2); 1.284 } else { 1.285 - glTranslatef(i & 2 ? 7.5 : -7.5, 0, 0); 1.286 + glTranslatef(i & 2 ? 2 : -2, 0.25, 0); 1.287 } 1.288 - draw_box(3, 0, 3, 1.0); 1.289 + draw_box(0.5, 0.5, 0.5, 1.0); 1.290 glPopMatrix(); 1.291 } 1.292 } 1.293 @@ -301,16 +338,24 @@ 1.294 glTexCoord2f(1, 0); glVertex3f(-1, -1, 1); 1.295 glTexCoord2f(1, 1); glVertex3f(-1, 1, 1); 1.296 glTexCoord2f(0, 1); glVertex3f(-1, 1, -1); 1.297 + glEnd(); 1.298 + glBegin(GL_TRIANGLE_FAN); 1.299 glNormal3f(0, 1 * norm_sign, 0); 1.300 + glTexCoord2f(0.5, 0.5); glVertex3f(0, 1, 0); 1.301 glTexCoord2f(0, 0); glVertex3f(-1, 1, 1); 1.302 glTexCoord2f(1, 0); glVertex3f(1, 1, 1); 1.303 glTexCoord2f(1, 1); glVertex3f(1, 1, -1); 1.304 glTexCoord2f(0, 1); glVertex3f(-1, 1, -1); 1.305 + glTexCoord2f(0, 0); glVertex3f(-1, 1, 1); 1.306 + glEnd(); 1.307 + glBegin(GL_TRIANGLE_FAN); 1.308 glNormal3f(0, -1 * norm_sign, 0); 1.309 + glTexCoord2f(0.5, 0.5); glVertex3f(0, -1, 0); 1.310 glTexCoord2f(0, 0); glVertex3f(-1, -1, -1); 1.311 glTexCoord2f(1, 0); glVertex3f(1, -1, -1); 1.312 glTexCoord2f(1, 1); glVertex3f(1, -1, 1); 1.313 glTexCoord2f(0, 1); glVertex3f(-1, -1, 1); 1.314 + glTexCoord2f(0, 0); glVertex3f(-1, -1, -1); 1.315 glEnd(); 1.316 1.317 glFrontFace(GL_CCW); 1.318 @@ -353,6 +398,9 @@ 1.319 int handle_event(SDL_Event *ev) 1.320 { 1.321 switch(ev->type) { 1.322 + case SDL_QUIT: 1.323 + return -1; 1.324 + 1.325 case SDL_KEYDOWN: 1.326 case SDL_KEYUP: 1.327 if(key_event(ev->key.keysym.sym, ev->key.state == SDL_PRESSED) == -1) { 1.328 @@ -370,24 +418,87 @@ 1.329 int key_event(int key, int state) 1.330 { 1.331 if(state) { 1.332 + ovrHSWDisplayState hsw; 1.333 + ovrHmd_GetHSWDisplayState(hmd, &hsw); 1.334 + if(hsw.Displayed) { 1.335 + ovrHmd_DismissHSWDisplay(hmd); 1.336 + } 1.337 + 1.338 switch(key) { 1.339 case 27: 1.340 return -1; 1.341 1.342 + case ' ': 1.343 + /* allow the user to recenter by pressing space */ 1.344 + ovrHmd_RecenterPose(hmd); 1.345 + break; 1.346 + 1.347 + case 'f': 1.348 + /* press f to move the window to the HMD */ 1.349 + toggle_hmd_fullscreen(); 1.350 + break; 1.351 + 1.352 default: 1.353 break; 1.354 } 1.355 } 1.356 return 0; 1.357 } 1.358 - 1.359 -unsigned int next_pow2(unsigned int x) 1.360 -{ 1.361 - x -= 1; 1.362 - x |= x >> 1; 1.363 - x |= x >> 2; 1.364 - x |= x >> 4; 1.365 - x |= x >> 8; 1.366 - x |= x >> 16; 1.367 - return x + 1; 1.368 + 1.369 +unsigned int next_pow2(unsigned int x) 1.370 +{ 1.371 + x -= 1; 1.372 + x |= x >> 1; 1.373 + x |= x >> 2; 1.374 + x |= x >> 4; 1.375 + x |= x >> 8; 1.376 + x |= x >> 16; 1.377 + return x + 1; 1.378 +} 1.379 + 1.380 +void quat_to_matrix(const float *quat, float *mat) 1.381 +{ 1.382 + mat[0] = 1.0 - 2.0 * quat[1] * quat[1] - 2.0 * quat[2] * quat[2]; 1.383 + mat[4] = 2.0 * quat[0] * quat[1] + 2.0 * quat[3] * quat[2]; 1.384 + mat[8] = 2.0 * quat[2] * quat[0] - 2.0 * quat[3] * quat[1]; 1.385 + mat[12] = 0.0f; 1.386 + 1.387 + mat[1] = 2.0 * quat[0] * quat[1] - 2.0 * quat[3] * quat[2]; 1.388 + mat[5] = 1.0 - 2.0 * quat[0]*quat[0] - 2.0 * quat[2]*quat[2]; 1.389 + mat[9] = 2.0 * quat[1] * quat[2] + 2.0 * quat[3] * quat[0]; 1.390 + mat[13] = 0.0f; 1.391 + 1.392 + mat[2] = 2.0 * quat[2] * quat[0] + 2.0 * quat[3] * quat[1]; 1.393 + mat[6] = 2.0 * quat[1] * quat[2] - 2.0 * quat[3] * quat[0]; 1.394 + mat[10] = 1.0 - 2.0 * quat[0]*quat[0] - 2.0 * quat[1]*quat[1]; 1.395 + mat[14] = 0.0f; 1.396 + 1.397 + mat[3] = mat[7] = mat[11] = 0.0f; 1.398 + mat[15] = 1.0f; 1.399 +} 1.400 + 1.401 +unsigned int gen_chess_tex(float r0, float g0, float b0, float r1, float g1, float b1) 1.402 +{ 1.403 + int i, j; 1.404 + unsigned int tex; 1.405 + unsigned char img[8 * 8 * 3]; 1.406 + unsigned char *pix = img; 1.407 + 1.408 + for(i=0; i<8; i++) { 1.409 + for(j=0; j<8; j++) { 1.410 + int black = (i & 1) == (j & 1); 1.411 + pix[0] = (black ? r0 : r1) * 255; 1.412 + pix[1] = (black ? g0 : g1) * 255; 1.413 + pix[2] = (black ? b0 : b1) * 255; 1.414 + pix += 3; 1.415 + } 1.416 + } 1.417 + 1.418 + glGenTextures(1, &tex); 1.419 + glBindTexture(GL_TEXTURE_2D, tex); 1.420 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 1.421 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 1.422 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, img); 1.423 + 1.424 + return tex; 1.425 } 1.426 \ No newline at end of file