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@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@0: 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@0: nuclear@0: int main(void) 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: nuclear@0: while(SDL_PollEvent(&ev)) { nuclear@0: if(handle_event(&ev) == -1) { nuclear@0: goto done; nuclear@0: } 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@0: // this must be called before any OpenGL init according to the docs 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@0: if(!(win = SDL_CreateWindow("simple oculus example", 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@2: SDL_SetWindowSize(win, hmd->Resolution.w, hmd->Resolution.h); nuclear@0: nuclear@0: ovrHmd_ConfigureTracking(hmd, 0xffffffff, 0); 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@2: SDL_GetWindowSize(win, &win_width, &win_height); nuclear@2: 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@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@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@2: fb_ovr_tex[i].OGL.TexId = fb_tex; nuclear@2: } nuclear@2: 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@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@2: ovrHmd_SetEnabledCaps(hmd, ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction); nuclear@0: nuclear@3: 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@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@0: nuclear@3: glClearColor(0.05, 0.05, 0.05, 1); nuclear@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@2: void display(void) nuclear@0: { nuclear@2: int i; nuclear@2: ovrMatrix4f proj; nuclear@2: ovrPosef pose[2]; nuclear@2: nuclear@2: ovrHmd_BeginFrame(hmd, 0); nuclear@2: nuclear@2: glBindFramebuffer(GL_FRAMEBUFFER, fbo); nuclear@0: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); nuclear@0: nuclear@3: glViewport(0, 0, fb_width, fb_height); nuclear@3: nuclear@3: /*glMatrixMode(GL_PROJECTION); nuclear@3: glLoadIdentity(); nuclear@3: glMatrixMode(GL_MODELVIEW); nuclear@3: glLoadIdentity(); nuclear@3: nuclear@3: glPushAttrib(GL_ENABLE_BIT); nuclear@3: glDisable(GL_LIGHTING); nuclear@3: glDisable(GL_DEPTH_TEST); nuclear@3: nuclear@3: glBegin(GL_QUADS); nuclear@3: glColor3f(1, 0, 0); nuclear@3: glVertex2f(-1, -1); nuclear@3: glVertex2f(0, -1); nuclear@3: glVertex2f(0, 1); nuclear@3: glVertex2f(-1, 1); nuclear@3: nuclear@3: glColor3f(1, 0, 1); nuclear@3: glVertex2f(-0.6, -0.1); nuclear@3: glVertex2f(-0.4, -0.1); nuclear@3: glVertex2f(-0.4, 0.1); nuclear@3: glVertex2f(-0.6, 0.1); nuclear@3: nuclear@3: glColor3f(0, 1, 0); nuclear@3: glVertex2f(0, -1); nuclear@3: glVertex2f(1, -1); nuclear@3: glVertex2f(1, 1); nuclear@3: glVertex2f(0, 1); nuclear@3: nuclear@3: glColor3f(0, 1, 1); nuclear@3: glVertex2f(0.4, -0.1); nuclear@3: glVertex2f(0.6, -0.1); nuclear@3: glVertex2f(0.6, 0.1); nuclear@3: glVertex2f(0.4, 0.1); nuclear@3: glEnd(); nuclear@3: nuclear@3: glPopAttrib();*/ nuclear@3: nuclear@2: /* for each eye ... */ nuclear@2: for(i=0; i<2; i++) { nuclear@2: int eye = hmd->EyeRenderOrder[i]; nuclear@2: nuclear@2: /* vport0(0, 0, width/2, height), vport1(width/2, 0, width/2, height) */ nuclear@2: glViewport(eye == 0 ? 0 : fb_width / 2, 0, fb_width / 2, fb_height); nuclear@2: nuclear@2: proj = ovrMatrix4f_Projection(hmd->DefaultEyeFov[eye], 0.5, 500.0, 1); nuclear@2: glMatrixMode(GL_PROJECTION); nuclear@3: //glLoadMatrixf(proj.M[0]); nuclear@3: glLoadIdentity(); nuclear@3: gluPerspective(50.0, (float)fb_width / 2.0 / (float)fb_height, 0.5, 500.0); nuclear@2: nuclear@2: pose[eye] = ovrHmd_GetEyePose(hmd, eye); nuclear@2: glMatrixMode(GL_MODELVIEW); nuclear@3: /* TODO: get HMD orientation data and use it */ nuclear@3: //glTranslatef(0, -ovrHmd_GetFloat(hmd, OVR_KEY_EYE_HEIGHT, 1.65), 0); nuclear@2: nuclear@2: draw_scene(); nuclear@2: } nuclear@2: 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@2: float lpos[] = {0, 5, 0, 1}; nuclear@2: glLightfv(GL_LIGHT0, GL_POSITION, lpos); nuclear@2: nuclear@3: glPushMatrix(); nuclear@3: glTranslatef(0, 0, -8); nuclear@3: draw_box(2, 2, 2, 1.0); nuclear@3: glPopMatrix(); nuclear@3: nuclear@2: glTranslatef(0, 5, 0); nuclear@2: draw_box(20, 10, 20, -1.0); nuclear@2: nuclear@2: for(i=0; i<4; i++) { nuclear@2: glPushMatrix(); nuclear@2: if(i & 1) { nuclear@2: glTranslatef(0, 0, i & 2 ? 7.5 : -7.5); nuclear@2: } else { nuclear@2: glTranslatef(i & 2 ? 7.5 : -7.5, 0, 0); nuclear@2: } nuclear@2: draw_box(3, 0, 3, 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@2: glNormal3f(0, 1 * norm_sign, 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, -1 * norm_sign, 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: glEnd(); nuclear@2: nuclear@2: glFrontFace(GL_CCW); nuclear@0: } nuclear@0: nuclear@0: void update_rtarg(int width, int height) nuclear@0: { nuclear@0: if(!fbo) { 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@0: fb_tex_width = next_pow2(width); nuclear@0: fb_tex_height = next_pow2(height); nuclear@0: 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@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@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@0: switch(key) { nuclear@0: case 27: nuclear@0: return -1; nuclear@0: nuclear@0: default: nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: return 0; nuclear@0: } nuclear@2: nuclear@2: unsigned int next_pow2(unsigned int x) nuclear@2: { nuclear@2: x -= 1; nuclear@2: x |= x >> 1; nuclear@2: x |= x >> 2; nuclear@2: x |= x >> 4; nuclear@2: x |= x >> 8; nuclear@2: x |= x >> 16; nuclear@2: return x + 1; nuclear@2: }