# HG changeset patch # User John Tsiombikas # Date 1409810461 -10800 # Node ID cd9f1560b909754b6abacf8eea3f812d571f0e40 # Parent d64830551c3278bdb31320bbea54b6ef00b67b32 added a few comments diff -r d64830551c32 -r cd9f1560b909 src/main.c --- a/src/main.c Thu Sep 04 08:31:12 2014 +0300 +++ b/src/main.c Thu Sep 04 09:01:01 2014 +0300 @@ -1,3 +1,9 @@ +/* Very simple OculusSDK OpenGL usage example. + * Uses SDL2 for event handling and OpenGL context management. + * + * Author: John Tsiombikas + * This code is in the public domain. Do whatever you like with it. + */ #include #include #include @@ -102,30 +108,39 @@ } printf("initialized HMD: %s - %s\n", hmd->Manufacturer, hmd->ProductName); + /* resize our window to match the HMD resolution */ SDL_SetWindowSize(win, hmd->Resolution.w, hmd->Resolution.h); SDL_SetWindowPosition(win, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); win_width = hmd->Resolution.w; win_height = hmd->Resolution.h; + /* enable position and rotation tracking (and anything else they might add in the future) */ ovrHmd_ConfigureTracking(hmd, 0xffffffff, 0); + /* retrieve the optimal render target resolution for each eye */ eyeres[0] = ovrHmd_GetFovTextureSize(hmd, ovrEye_Left, hmd->DefaultEyeFov[0], 1.0); eyeres[1] = ovrHmd_GetFovTextureSize(hmd, ovrEye_Right, hmd->DefaultEyeFov[1], 1.0); + /* and create a single render target texture to encompass both eyes */ fb_width = eyeres[0].w + eyeres[1].w; fb_height = eyeres[0].h > eyeres[1].h ? eyeres[0].h : eyeres[1].h; update_rtarg(fb_width, fb_height); + /* fill in the ovrGLTexture structures that describe our render target texture */ for(i=0; i<2; i++) { fb_ovr_tex[i].OGL.Header.API = ovrRenderAPI_OpenGL; fb_ovr_tex[i].OGL.Header.TextureSize.w = fb_tex_width; fb_ovr_tex[i].OGL.Header.TextureSize.h = fb_tex_height; + /* this next field is the only one that differs between the two eyes */ fb_ovr_tex[i].OGL.Header.RenderViewport.Pos.x = i == 0 ? 0 : fb_width / 2.0; fb_ovr_tex[i].OGL.Header.RenderViewport.Pos.y = fb_tex_height - fb_height; fb_ovr_tex[i].OGL.Header.RenderViewport.Size.w = fb_width / 2.0; fb_ovr_tex[i].OGL.Header.RenderViewport.Size.h = fb_height; - fb_ovr_tex[i].OGL.TexId = fb_tex; + fb_ovr_tex[i].OGL.TexId = fb_tex; /* both eyes will use the same texture id */ } + /* fill in the ovrGLConfig structure needed by the SDK to draw our stereo pair + * to the actual HMD display (SDK-distortion mode) + */ memset(&glcfg, 0, sizeof glcfg); glcfg.OGL.Header.API = ovrRenderAPI_OpenGL; glcfg.OGL.Header.RTSize = hmd->Resolution; @@ -134,6 +149,10 @@ if(hmd->HmdCaps & ovrHmdCap_ExtendDesktop) { printf("running in \"extended desktop\" mode\n"); } else { + /* to sucessfully draw to the HMD display in "direct-hmd" mode, we have to + * call ovrHmd_AttachToWindow + * XXX: this doesn't work properly yet due to bugs in the oculus 0.4.1 sdk/driver + */ #ifdef WIN32 void *sys_win = GetActiveWindow(); glcfg.OGL.Window = sys_win; @@ -142,13 +161,20 @@ #endif printf("running in \"direct-hmd\" mode\n"); } + + /* enable low-persistence display and dynamic prediction for lattency compensation */ ovrHmd_SetEnabledCaps(hmd, ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction); + /* configure SDK-rendering and enable chromatic abberation correction, vignetting, and + * timewrap, which shifts the image before drawing to counter any lattency between the call + * to ovrHmd_GetEyePose and ovrHmd_EndFrame. + */ dcaps = ovrDistortionCap_Chromatic | ovrDistortionCap_Vignette | ovrDistortionCap_TimeWarp; if(!ovrHmd_ConfigureRendering(hmd, &glcfg.Config, dcaps, hmd->DefaultEyeFov, eye_rdesc)) { fprintf(stderr, "failed to configure distortion renderer\n"); } + /* disable the retarded "health and safety warning" */ ovrhmd_EnableHSWDisplaySDKRender(hmd, 0); glEnable(GL_DEPTH_TEST); @@ -180,10 +206,14 @@ fullscr = !fullscr; if(fullscr) { + /* going fullscreen on the rift. save current window position, and move it + * to the rift's part of the desktop before going fullscreen + */ SDL_GetWindowPosition(win, &prev_x, &prev_y); SDL_SetWindowPosition(win, hmd->WindowsPos.x, hmd->WindowsPos.y); SDL_SetWindowFullscreen(win, SDL_WINDOW_FULLSCREEN_DESKTOP); } else { + /* return to windowed mode and move the window back to its original position */ SDL_SetWindowFullscreen(win, 0); SDL_SetWindowPosition(win, prev_x, prev_y); } @@ -361,9 +391,11 @@ glFrontFace(GL_CCW); } +/* update_rtarg creates (and/or resizes) the render target used to draw the two stero views */ void update_rtarg(int width, int height) { if(!fbo) { + /* if fbo does not exist, then nothing does... create every opengl object */ glGenFramebuffers(1, &fbo); glGenTextures(1, &fb_tex); glGenRenderbuffers(1, &fb_depth); @@ -375,14 +407,17 @@ glBindFramebuffer(GL_FRAMEBUFFER, fbo); + /* calculate the next power of two in both dimensions and use that as a texture size */ fb_tex_width = next_pow2(width); fb_tex_height = next_pow2(height); + /* create and attach the texture that will be used as a color buffer */ glBindTexture(GL_TEXTURE_2D, fb_tex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, fb_tex_width, fb_tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb_tex, 0); + /* create and attach the renderbuffer that will serve as our z-buffer */ glBindRenderbuffer(GL_RENDERBUFFER, fb_depth); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, fb_tex_width, fb_tex_height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fb_depth); @@ -418,11 +453,13 @@ int key_event(int key, int state) { if(state) { + /* ovrHSWDisplayState hsw; ovrHmd_GetHSWDisplayState(hmd, &hsw); if(hsw.Displayed) { ovrHmd_DismissHSWDisplay(hmd); } + */ switch(key) { case 27: @@ -456,6 +493,7 @@ return x + 1; } +/* convert a quaternion to a rotation matrix */ void quat_to_matrix(const float *quat, float *mat) { mat[0] = 1.0 - 2.0 * quat[1] * quat[1] - 2.0 * quat[2] * quat[2]; @@ -477,6 +515,7 @@ mat[15] = 1.0f; } +/* generate a chessboard texture with tiles colored (r0, g0, b0) and (r1, g1, b1) */ unsigned int gen_chess_tex(float r0, float g0, float b0, float r1, float g1, float b1) { int i, j;