nuclear@5: /* Very simple OculusSDK OpenGL usage example. nuclear@5: * Uses SDL2 for event handling and OpenGL context management. nuclear@5: * nuclear@5: * Author: John Tsiombikas nuclear@5: * This code is in the public domain. Do whatever you like with it. nuclear@5: */ nuclear@0: #include nuclear@0: #include nuclear@2: #include nuclear@0: #include nuclear@0: #include nuclear@0: nuclear@2: #ifdef WIN32 nuclear@2: #define OVR_OS_WIN32 nuclear@2: #endif nuclear@2: #ifdef __APPLE__ nuclear@2: #define OVR_OS_MAC nuclear@2: #endif nuclear@2: nuclear@0: #include nuclear@0: #include nuclear@0: nuclear@2: int init(void); nuclear@2: void cleanup(void); nuclear@4: void toggle_hmd_fullscreen(void); nuclear@2: void display(void); nuclear@2: void draw_scene(void); nuclear@2: void draw_box(float xsz, float ysz, float zsz, float norm_sign); nuclear@0: void update_rtarg(int width, int height); nuclear@0: int handle_event(SDL_Event *ev); nuclear@0: int key_event(int key, int state); nuclear@0: void reshape(int x, int y); nuclear@0: unsigned int next_pow2(unsigned int x); nuclear@4: void quat_to_matrix(const float *quat, float *mat); nuclear@4: unsigned int gen_chess_tex(float r0, float g0, float b0, float r1, float g1, float b1); nuclear@0: nuclear@4: /* forward declaration to avoid including non-public headers of libovr */ nuclear@0: OVR_EXPORT void ovrhmd_EnableHSWDisplaySDKRender(ovrHmd hmd, ovrBool enable); nuclear@0: nuclear@0: static SDL_Window *win; nuclear@0: static SDL_GLContext ctx; nuclear@2: static int win_width, win_height; nuclear@0: nuclear@0: static unsigned int fbo, fb_tex, fb_depth; nuclear@0: static int fb_width, fb_height; nuclear@0: static int fb_tex_width, fb_tex_height; nuclear@0: nuclear@0: static ovrHmd hmd; nuclear@0: static ovrSizei eyeres[2]; nuclear@2: static ovrEyeRenderDesc eye_rdesc[2]; nuclear@2: static ovrGLTexture fb_ovr_tex[2]; nuclear@0: nuclear@4: static unsigned int chess_tex; nuclear@0: nuclear@4: nuclear@4: int main(int argc, char **argv) nuclear@0: { nuclear@0: if(init() == -1) { nuclear@0: return 1; nuclear@0: } nuclear@0: nuclear@0: for(;;) { nuclear@0: SDL_Event ev; nuclear@0: while(SDL_PollEvent(&ev)) { nuclear@0: if(handle_event(&ev) == -1) { nuclear@0: goto done; nuclear@0: } nuclear@0: } nuclear@0: display(); nuclear@0: } nuclear@0: nuclear@0: done: nuclear@0: cleanup(); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: nuclear@2: int init(void) nuclear@0: { nuclear@2: int i, x, y; nuclear@0: unsigned int flags, dcaps; nuclear@0: union ovrGLConfig glcfg; nuclear@0: nuclear@4: /* libovr must be initialized before we create the OpenGL context */ nuclear@0: ovr_Initialize(); nuclear@0: nuclear@0: SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER); nuclear@0: nuclear@0: x = y = SDL_WINDOWPOS_UNDEFINED; nuclear@2: flags = SDL_WINDOW_OPENGL; nuclear@4: if(!(win = SDL_CreateWindow("press 'f' to move to the HMD", x, y, 1280, 800, flags))) { nuclear@0: fprintf(stderr, "failed to create window\n"); nuclear@0: return -1; nuclear@0: } nuclear@0: if(!(ctx = SDL_GL_CreateContext(win))) { nuclear@0: fprintf(stderr, "failed to create OpenGL context\n"); nuclear@0: return -1; nuclear@0: } nuclear@0: nuclear@0: glewInit(); nuclear@0: nuclear@0: if(!(hmd = ovrHmd_Create(0))) { nuclear@0: fprintf(stderr, "failed to open Oculus HMD, falling back to virtual debug HMD\n"); nuclear@2: if(!(hmd = ovrHmd_CreateDebug(ovrHmd_DK2))) { nuclear@0: fprintf(stderr, "failed to create virtual debug HMD\n"); nuclear@0: return -1; nuclear@0: } nuclear@0: } nuclear@0: printf("initialized HMD: %s - %s\n", hmd->Manufacturer, hmd->ProductName); nuclear@0: nuclear@5: /* resize our window to match the HMD resolution */ nuclear@2: SDL_SetWindowSize(win, hmd->Resolution.w, hmd->Resolution.h); nuclear@4: SDL_SetWindowPosition(win, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); nuclear@4: win_width = hmd->Resolution.w; nuclear@4: win_height = hmd->Resolution.h; nuclear@0: nuclear@5: /* enable position and rotation tracking (and anything else they might add in the future) */ nuclear@0: ovrHmd_ConfigureTracking(hmd, 0xffffffff, 0); nuclear@5: /* retrieve the optimal render target resolution for each eye */ nuclear@0: eyeres[0] = ovrHmd_GetFovTextureSize(hmd, ovrEye_Left, hmd->DefaultEyeFov[0], 1.0); nuclear@0: eyeres[1] = ovrHmd_GetFovTextureSize(hmd, ovrEye_Right, hmd->DefaultEyeFov[1], 1.0); nuclear@0: nuclear@5: /* and create a single render target texture to encompass both eyes */ nuclear@2: fb_width = eyeres[0].w + eyeres[1].w; nuclear@0: fb_height = eyeres[0].h > eyeres[1].h ? eyeres[0].h : eyeres[1].h; nuclear@0: update_rtarg(fb_width, fb_height); nuclear@0: nuclear@5: /* fill in the ovrGLTexture structures that describe our render target texture */ nuclear@2: for(i=0; i<2; i++) { nuclear@2: fb_ovr_tex[i].OGL.Header.API = ovrRenderAPI_OpenGL; nuclear@2: fb_ovr_tex[i].OGL.Header.TextureSize.w = fb_tex_width; nuclear@2: fb_ovr_tex[i].OGL.Header.TextureSize.h = fb_tex_height; nuclear@5: /* this next field is the only one that differs between the two eyes */ nuclear@3: fb_ovr_tex[i].OGL.Header.RenderViewport.Pos.x = i == 0 ? 0 : fb_width / 2.0; nuclear@3: fb_ovr_tex[i].OGL.Header.RenderViewport.Pos.y = fb_tex_height - fb_height; nuclear@2: fb_ovr_tex[i].OGL.Header.RenderViewport.Size.w = fb_width / 2.0; nuclear@2: fb_ovr_tex[i].OGL.Header.RenderViewport.Size.h = fb_height; nuclear@5: fb_ovr_tex[i].OGL.TexId = fb_tex; /* both eyes will use the same texture id */ nuclear@2: } nuclear@2: nuclear@5: /* fill in the ovrGLConfig structure needed by the SDK to draw our stereo pair nuclear@5: * to the actual HMD display (SDK-distortion mode) nuclear@5: */ nuclear@0: memset(&glcfg, 0, sizeof glcfg); nuclear@0: glcfg.OGL.Header.API = ovrRenderAPI_OpenGL; nuclear@0: glcfg.OGL.Header.RTSize = hmd->Resolution; nuclear@0: glcfg.OGL.Header.Multisample = 1; nuclear@0: nuclear@0: if(hmd->HmdCaps & ovrHmdCap_ExtendDesktop) { nuclear@0: printf("running in \"extended desktop\" mode\n"); nuclear@0: } else { nuclear@5: /* to sucessfully draw to the HMD display in "direct-hmd" mode, we have to nuclear@5: * call ovrHmd_AttachToWindow nuclear@5: * XXX: this doesn't work properly yet due to bugs in the oculus 0.4.1 sdk/driver nuclear@5: */ nuclear@2: #ifdef WIN32 nuclear@2: void *sys_win = GetActiveWindow(); nuclear@2: glcfg.OGL.Window = sys_win; nuclear@2: glcfg.OGL.DC = wglGetCurrentDC(); nuclear@2: ovrHmd_AttachToWindow(hmd, sys_win, 0, 0); nuclear@2: #endif nuclear@0: printf("running in \"direct-hmd\" mode\n"); nuclear@0: } nuclear@5: nuclear@5: /* enable low-persistence display and dynamic prediction for lattency compensation */ nuclear@2: ovrHmd_SetEnabledCaps(hmd, ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction); nuclear@0: nuclear@5: /* configure SDK-rendering and enable chromatic abberation correction, vignetting, and nuclear@5: * timewrap, which shifts the image before drawing to counter any lattency between the call nuclear@5: * to ovrHmd_GetEyePose and ovrHmd_EndFrame. nuclear@5: */ nuclear@4: dcaps = ovrDistortionCap_Chromatic | ovrDistortionCap_Vignette | ovrDistortionCap_TimeWarp; nuclear@0: if(!ovrHmd_ConfigureRendering(hmd, &glcfg.Config, dcaps, hmd->DefaultEyeFov, eye_rdesc)) { nuclear@0: fprintf(stderr, "failed to configure distortion renderer\n"); nuclear@0: } nuclear@0: nuclear@5: /* disable the retarded "health and safety warning" */ nuclear@3: ovrhmd_EnableHSWDisplaySDKRender(hmd, 0); nuclear@0: nuclear@0: glEnable(GL_DEPTH_TEST); nuclear@0: glEnable(GL_CULL_FACE); nuclear@0: glEnable(GL_LIGHTING); nuclear@0: glEnable(GL_LIGHT0); nuclear@4: glEnable(GL_LIGHT1); nuclear@4: glEnable(GL_NORMALIZE); nuclear@0: nuclear@4: glClearColor(0.1, 0.1, 0.1, 1); nuclear@0: nuclear@4: chess_tex = gen_chess_tex(1.0, 0.7, 0.4, 0.4, 0.7, 1.0); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@2: void cleanup(void) nuclear@0: { nuclear@0: if(hmd) { nuclear@0: ovrHmd_Destroy(hmd); nuclear@0: } nuclear@0: ovr_Shutdown(); nuclear@0: nuclear@0: SDL_Quit(); nuclear@0: } nuclear@0: nuclear@4: void toggle_hmd_fullscreen(void) nuclear@4: { nuclear@4: static int fullscr, prev_x, prev_y; nuclear@4: fullscr = !fullscr; nuclear@4: nuclear@4: if(fullscr) { nuclear@5: /* going fullscreen on the rift. save current window position, and move it nuclear@5: * to the rift's part of the desktop before going fullscreen nuclear@5: */ nuclear@4: SDL_GetWindowPosition(win, &prev_x, &prev_y); nuclear@4: SDL_SetWindowPosition(win, hmd->WindowsPos.x, hmd->WindowsPos.y); nuclear@4: SDL_SetWindowFullscreen(win, SDL_WINDOW_FULLSCREEN_DESKTOP); nuclear@4: } else { nuclear@5: /* return to windowed mode and move the window back to its original position */ nuclear@4: SDL_SetWindowFullscreen(win, 0); nuclear@4: SDL_SetWindowPosition(win, prev_x, prev_y); nuclear@4: } nuclear@4: } nuclear@4: nuclear@2: void display(void) nuclear@0: { nuclear@2: int i; nuclear@2: ovrMatrix4f proj; nuclear@2: ovrPosef pose[2]; nuclear@4: float rot_mat[16]; nuclear@2: nuclear@4: /* the drawing starts with a call to ovrHmd_BeginFrame */ nuclear@2: ovrHmd_BeginFrame(hmd, 0); nuclear@2: nuclear@4: /* start drawing onto our texture render target */ nuclear@2: glBindFramebuffer(GL_FRAMEBUFFER, fbo); nuclear@0: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); nuclear@0: nuclear@2: /* for each eye ... */ nuclear@2: for(i=0; i<2; i++) { nuclear@2: int eye = hmd->EyeRenderOrder[i]; nuclear@2: nuclear@4: /* -- viewport transformation -- nuclear@4: * setup the viewport to draw in the left half of the framebuffer when we're nuclear@4: * rendering the left eye's view (0, 0, width/2, height), and in the right half nuclear@4: * of the framebuffer for the right eye's view (width/2, 0, width/2, height) nuclear@4: */ nuclear@2: glViewport(eye == 0 ? 0 : fb_width / 2, 0, fb_width / 2, fb_height); nuclear@2: nuclear@4: /* -- projection transformation -- nuclear@4: * we'll just have to use the projection matrix supplied by the oculus SDK for this eye nuclear@4: * note that libovr matrices are the transpose of what OpenGL expects, so we have to nuclear@4: * use glLoadTransposeMatrixf instead of glLoadMatrixf to load it. nuclear@4: */ nuclear@2: proj = ovrMatrix4f_Projection(hmd->DefaultEyeFov[eye], 0.5, 500.0, 1); nuclear@2: glMatrixMode(GL_PROJECTION); nuclear@4: glLoadTransposeMatrixf(proj.M[0]); nuclear@2: nuclear@4: /* -- view/camera transformation -- nuclear@4: * we need to construct a view matrix by combining all the information provided by the oculus nuclear@4: * SDK, about the position and orientation of the user's head in the world. nuclear@4: */ nuclear@2: pose[eye] = ovrHmd_GetEyePose(hmd, eye); nuclear@2: glMatrixMode(GL_MODELVIEW); nuclear@4: glLoadIdentity(); nuclear@4: glTranslatef(eye_rdesc[eye].ViewAdjust.x, eye_rdesc[eye].ViewAdjust.y, eye_rdesc[eye].ViewAdjust.z); nuclear@4: /* retrieve the orientation quaternion and convert it to a rotation matrix */ nuclear@4: quat_to_matrix(&pose[eye].Orientation.x, rot_mat); nuclear@4: glMultMatrixf(rot_mat); nuclear@4: /* translate the view matrix with the positional tracking */ nuclear@4: glTranslatef(-pose[eye].Position.x, -pose[eye].Position.y, -pose[eye].Position.z); nuclear@4: /* move the camera to the eye level of the user */ nuclear@4: glTranslatef(0, -ovrHmd_GetFloat(hmd, OVR_KEY_EYE_HEIGHT, 1.65), 0); nuclear@2: nuclear@4: /* finally draw the scene for this eye */ nuclear@2: draw_scene(); nuclear@2: } nuclear@2: nuclear@4: /* after drawing both eyes into the texture render target, revert to drawing directly to the nuclear@4: * display, and we call ovrHmd_EndFrame, to let the Oculus SDK draw both images properly nuclear@4: * compensated for lens distortion and chromatic abberation onto the HMD screen. nuclear@4: */ nuclear@2: glBindFramebuffer(GL_FRAMEBUFFER, 0); nuclear@2: glViewport(0, 0, win_width, win_height); nuclear@2: nuclear@2: ovrHmd_EndFrame(hmd, pose, &fb_ovr_tex[0].Texture); nuclear@2: nuclear@2: assert(glGetError() == GL_NO_ERROR); nuclear@2: } nuclear@2: nuclear@2: void draw_scene(void) nuclear@2: { nuclear@2: int i; nuclear@4: float grey[] = {0.8, 0.8, 0.8, 1}; nuclear@4: float col[] = {0, 0, 0, 1}; nuclear@4: float lpos[][4] = { nuclear@4: {-8, 2, 10, 1}, nuclear@4: {0, 15, 0, 1} nuclear@4: }; nuclear@4: float lcol[][4] = { nuclear@4: {0.8, 0.8, 0.8, 1}, nuclear@4: {0.4, 0.3, 0.3, 1} nuclear@4: }; nuclear@4: nuclear@4: for(i=0; i<2; i++) { nuclear@4: glLightfv(GL_LIGHT0 + i, GL_POSITION, lpos[i]); nuclear@4: glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, lcol[i]); nuclear@4: } nuclear@4: nuclear@4: glMatrixMode(GL_MODELVIEW); nuclear@2: nuclear@3: glPushMatrix(); nuclear@4: glTranslatef(0, 10, 0); nuclear@4: glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, grey); nuclear@4: glBindTexture(GL_TEXTURE_2D, chess_tex); nuclear@4: glEnable(GL_TEXTURE_2D); nuclear@4: draw_box(30, 20, 30, -1.0); nuclear@4: glDisable(GL_TEXTURE_2D); nuclear@3: glPopMatrix(); nuclear@3: nuclear@4: for(i=0; i<4; i++) { nuclear@4: glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, grey); nuclear@4: glPushMatrix(); nuclear@4: glTranslatef(i & 1 ? 5 : -5, 1, i & 2 ? -5 : 5); nuclear@4: draw_box(0.5, 2, 0.5, 1.0); nuclear@4: glPopMatrix(); nuclear@2: nuclear@4: col[0] = i & 1 ? 1.0 : 0.3; nuclear@4: col[1] = i == 0 ? 1.0 : 0.3; nuclear@4: col[2] = i & 2 ? 1.0 : 0.3; nuclear@4: glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col); nuclear@4: nuclear@2: glPushMatrix(); nuclear@2: if(i & 1) { nuclear@4: glTranslatef(0, 0.25, i & 2 ? 2 : -2); nuclear@2: } else { nuclear@4: glTranslatef(i & 2 ? 2 : -2, 0.25, 0); nuclear@2: } nuclear@4: draw_box(0.5, 0.5, 0.5, 1.0); nuclear@2: glPopMatrix(); nuclear@2: } nuclear@2: } nuclear@2: nuclear@2: void draw_box(float xsz, float ysz, float zsz, float norm_sign) nuclear@2: { nuclear@2: glMatrixMode(GL_MODELVIEW); nuclear@2: glScalef(xsz * 0.5, ysz * 0.5, zsz * 0.5); nuclear@2: nuclear@2: if(norm_sign < 0.0) { nuclear@2: glFrontFace(GL_CW); nuclear@2: } nuclear@2: nuclear@2: glBegin(GL_QUADS); nuclear@2: glNormal3f(0, 0, 1 * norm_sign); nuclear@2: glTexCoord2f(0, 0); glVertex3f(-1, -1, 1); nuclear@2: glTexCoord2f(1, 0); glVertex3f(1, -1, 1); nuclear@2: glTexCoord2f(1, 1); glVertex3f(1, 1, 1); nuclear@2: glTexCoord2f(0, 1); glVertex3f(-1, 1, 1); nuclear@2: glNormal3f(1 * norm_sign, 0, 0); nuclear@2: glTexCoord2f(0, 0); glVertex3f(1, -1, 1); nuclear@2: glTexCoord2f(1, 0); glVertex3f(1, -1, -1); nuclear@2: glTexCoord2f(1, 1); glVertex3f(1, 1, -1); nuclear@2: glTexCoord2f(0, 1); glVertex3f(1, 1, 1); nuclear@2: glNormal3f(0, 0, -1 * norm_sign); nuclear@2: glTexCoord2f(0, 0); glVertex3f(1, -1, -1); nuclear@2: glTexCoord2f(1, 0); glVertex3f(-1, -1, -1); nuclear@2: glTexCoord2f(1, 1); glVertex3f(-1, 1, -1); nuclear@2: glTexCoord2f(0, 1); glVertex3f(1, 1, -1); nuclear@2: glNormal3f(-1 * norm_sign, 0, 0); nuclear@2: glTexCoord2f(0, 0); glVertex3f(-1, -1, -1); nuclear@2: glTexCoord2f(1, 0); glVertex3f(-1, -1, 1); nuclear@2: glTexCoord2f(1, 1); glVertex3f(-1, 1, 1); nuclear@2: glTexCoord2f(0, 1); glVertex3f(-1, 1, -1); nuclear@4: glEnd(); nuclear@4: glBegin(GL_TRIANGLE_FAN); nuclear@2: glNormal3f(0, 1 * norm_sign, 0); nuclear@4: glTexCoord2f(0.5, 0.5); glVertex3f(0, 1, 0); nuclear@2: glTexCoord2f(0, 0); glVertex3f(-1, 1, 1); nuclear@2: glTexCoord2f(1, 0); glVertex3f(1, 1, 1); nuclear@2: glTexCoord2f(1, 1); glVertex3f(1, 1, -1); nuclear@2: glTexCoord2f(0, 1); glVertex3f(-1, 1, -1); nuclear@4: glTexCoord2f(0, 0); glVertex3f(-1, 1, 1); nuclear@4: glEnd(); nuclear@4: glBegin(GL_TRIANGLE_FAN); nuclear@2: glNormal3f(0, -1 * norm_sign, 0); nuclear@4: glTexCoord2f(0.5, 0.5); glVertex3f(0, -1, 0); nuclear@2: glTexCoord2f(0, 0); glVertex3f(-1, -1, -1); nuclear@2: glTexCoord2f(1, 0); glVertex3f(1, -1, -1); nuclear@2: glTexCoord2f(1, 1); glVertex3f(1, -1, 1); nuclear@2: glTexCoord2f(0, 1); glVertex3f(-1, -1, 1); nuclear@4: glTexCoord2f(0, 0); glVertex3f(-1, -1, -1); nuclear@2: glEnd(); nuclear@2: nuclear@2: glFrontFace(GL_CCW); nuclear@0: } nuclear@0: nuclear@5: /* update_rtarg creates (and/or resizes) the render target used to draw the two stero views */ nuclear@0: void update_rtarg(int width, int height) nuclear@0: { nuclear@0: if(!fbo) { nuclear@5: /* if fbo does not exist, then nothing does... create every opengl object */ nuclear@0: glGenFramebuffers(1, &fbo); nuclear@0: glGenTextures(1, &fb_tex); nuclear@0: glGenRenderbuffers(1, &fb_depth); nuclear@0: nuclear@0: glBindTexture(GL_TEXTURE_2D, fb_tex); nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); nuclear@0: } nuclear@0: nuclear@0: glBindFramebuffer(GL_FRAMEBUFFER, fbo); nuclear@0: nuclear@5: /* calculate the next power of two in both dimensions and use that as a texture size */ nuclear@0: fb_tex_width = next_pow2(width); nuclear@0: fb_tex_height = next_pow2(height); nuclear@0: nuclear@5: /* create and attach the texture that will be used as a color buffer */ nuclear@0: glBindTexture(GL_TEXTURE_2D, fb_tex); nuclear@0: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, fb_tex_width, fb_tex_height, 0, nuclear@0: GL_RGBA, GL_UNSIGNED_BYTE, 0); nuclear@0: glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb_tex, 0); nuclear@0: nuclear@5: /* create and attach the renderbuffer that will serve as our z-buffer */ nuclear@0: glBindRenderbuffer(GL_RENDERBUFFER, fb_depth); nuclear@0: glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, fb_tex_width, fb_tex_height); nuclear@0: glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fb_depth); nuclear@0: nuclear@0: if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { nuclear@0: fprintf(stderr, "incomplete framebuffer!\n"); nuclear@0: } nuclear@0: nuclear@0: glBindFramebuffer(GL_FRAMEBUFFER, 0); nuclear@0: printf("created render target: %dx%d (texture size: %dx%d)\n", width, height, fb_tex_width, fb_tex_height); nuclear@0: } nuclear@0: nuclear@0: int handle_event(SDL_Event *ev) nuclear@0: { nuclear@0: switch(ev->type) { nuclear@4: case SDL_QUIT: nuclear@4: return -1; nuclear@4: nuclear@0: case SDL_KEYDOWN: nuclear@0: case SDL_KEYUP: nuclear@0: if(key_event(ev->key.keysym.sym, ev->key.state == SDL_PRESSED) == -1) { nuclear@0: return -1; nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: default: nuclear@0: break; nuclear@0: } nuclear@0: nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: int key_event(int key, int state) nuclear@0: { nuclear@0: if(state) { nuclear@5: /* nuclear@4: ovrHSWDisplayState hsw; nuclear@4: ovrHmd_GetHSWDisplayState(hmd, &hsw); nuclear@4: if(hsw.Displayed) { nuclear@4: ovrHmd_DismissHSWDisplay(hmd); nuclear@4: } nuclear@5: */ nuclear@4: nuclear@0: switch(key) { nuclear@0: case 27: nuclear@0: return -1; nuclear@0: nuclear@4: case ' ': nuclear@4: /* allow the user to recenter by pressing space */ nuclear@4: ovrHmd_RecenterPose(hmd); nuclear@4: break; nuclear@4: nuclear@4: case 'f': nuclear@4: /* press f to move the window to the HMD */ nuclear@4: toggle_hmd_fullscreen(); nuclear@4: break; nuclear@4: nuclear@0: default: nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: return 0; nuclear@0: } nuclear@4: nuclear@4: unsigned int next_pow2(unsigned int x) nuclear@4: { nuclear@4: x -= 1; nuclear@4: x |= x >> 1; nuclear@4: x |= x >> 2; nuclear@4: x |= x >> 4; nuclear@4: x |= x >> 8; nuclear@4: x |= x >> 16; nuclear@4: return x + 1; nuclear@4: } nuclear@4: nuclear@5: /* convert a quaternion to a rotation matrix */ nuclear@4: void quat_to_matrix(const float *quat, float *mat) nuclear@4: { nuclear@4: mat[0] = 1.0 - 2.0 * quat[1] * quat[1] - 2.0 * quat[2] * quat[2]; nuclear@4: mat[4] = 2.0 * quat[0] * quat[1] + 2.0 * quat[3] * quat[2]; nuclear@4: mat[8] = 2.0 * quat[2] * quat[0] - 2.0 * quat[3] * quat[1]; nuclear@4: mat[12] = 0.0f; nuclear@4: nuclear@4: mat[1] = 2.0 * quat[0] * quat[1] - 2.0 * quat[3] * quat[2]; nuclear@4: mat[5] = 1.0 - 2.0 * quat[0]*quat[0] - 2.0 * quat[2]*quat[2]; nuclear@4: mat[9] = 2.0 * quat[1] * quat[2] + 2.0 * quat[3] * quat[0]; nuclear@4: mat[13] = 0.0f; nuclear@4: nuclear@4: mat[2] = 2.0 * quat[2] * quat[0] + 2.0 * quat[3] * quat[1]; nuclear@4: mat[6] = 2.0 * quat[1] * quat[2] - 2.0 * quat[3] * quat[0]; nuclear@4: mat[10] = 1.0 - 2.0 * quat[0]*quat[0] - 2.0 * quat[1]*quat[1]; nuclear@4: mat[14] = 0.0f; nuclear@4: nuclear@4: mat[3] = mat[7] = mat[11] = 0.0f; nuclear@4: mat[15] = 1.0f; nuclear@4: } nuclear@4: nuclear@5: /* generate a chessboard texture with tiles colored (r0, g0, b0) and (r1, g1, b1) */ nuclear@4: unsigned int gen_chess_tex(float r0, float g0, float b0, float r1, float g1, float b1) nuclear@4: { nuclear@4: int i, j; nuclear@4: unsigned int tex; nuclear@4: unsigned char img[8 * 8 * 3]; nuclear@4: unsigned char *pix = img; nuclear@4: nuclear@4: for(i=0; i<8; i++) { nuclear@4: for(j=0; j<8; j++) { nuclear@4: int black = (i & 1) == (j & 1); nuclear@4: pix[0] = (black ? r0 : r1) * 255; nuclear@4: pix[1] = (black ? g0 : g1) * 255; nuclear@4: pix[2] = (black ? b0 : b1) * 255; nuclear@4: pix += 3; nuclear@4: } nuclear@4: } nuclear@4: nuclear@4: glGenTextures(1, &tex); nuclear@4: glBindTexture(GL_TEXTURE_2D, tex); nuclear@4: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); nuclear@4: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); nuclear@4: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, img); nuclear@4: nuclear@4: return tex; nuclear@2: }