oculus2

annotate src/main.c @ 2:0984fa94b490

rendering almost works
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 26 Aug 2014 08:14:09 +0300
parents 0a4d62469381
children 096b18432ba7
rev   line source
nuclear@0 1 #include <stdio.h>
nuclear@0 2 #include <stdlib.h>
nuclear@2 3 #include <assert.h>
nuclear@0 4 #include <SDL2/SDL.h>
nuclear@0 5 #include <GL/glew.h>
nuclear@0 6
nuclear@2 7 #ifdef WIN32
nuclear@2 8 #define OVR_OS_WIN32
nuclear@2 9 #endif
nuclear@2 10 #ifdef __APPLE__
nuclear@2 11 #define OVR_OS_MAC
nuclear@2 12 #endif
nuclear@2 13
nuclear@0 14 #include <OVR_CAPI.h>
nuclear@0 15 #include <OVR_CAPI_GL.h>
nuclear@0 16
nuclear@2 17 int init(void);
nuclear@2 18 void cleanup(void);
nuclear@2 19 void display(void);
nuclear@2 20 void draw_scene(void);
nuclear@2 21 void draw_box(float xsz, float ysz, float zsz, float norm_sign);
nuclear@0 22 void update_rtarg(int width, int height);
nuclear@0 23 int handle_event(SDL_Event *ev);
nuclear@0 24 int key_event(int key, int state);
nuclear@0 25 void reshape(int x, int y);
nuclear@0 26 unsigned int next_pow2(unsigned int x);
nuclear@0 27
nuclear@0 28 OVR_EXPORT void ovrhmd_EnableHSWDisplaySDKRender(ovrHmd hmd, ovrBool enable);
nuclear@0 29
nuclear@0 30 static SDL_Window *win;
nuclear@0 31 static SDL_GLContext ctx;
nuclear@2 32 static int win_width, win_height;
nuclear@0 33
nuclear@0 34 static unsigned int fbo, fb_tex, fb_depth;
nuclear@0 35 static int fb_width, fb_height;
nuclear@0 36 static int fb_tex_width, fb_tex_height;
nuclear@0 37
nuclear@0 38 static ovrHmd hmd;
nuclear@0 39 static ovrSizei eyeres[2];
nuclear@2 40 static ovrEyeRenderDesc eye_rdesc[2];
nuclear@2 41 static ovrGLTexture fb_ovr_tex[2];
nuclear@0 42
nuclear@0 43
nuclear@0 44 int main(void)
nuclear@0 45 {
nuclear@0 46 if(init() == -1) {
nuclear@0 47 return 1;
nuclear@0 48 }
nuclear@0 49
nuclear@0 50 for(;;) {
nuclear@0 51 SDL_Event ev;
nuclear@0 52
nuclear@0 53 while(SDL_PollEvent(&ev)) {
nuclear@0 54 if(handle_event(&ev) == -1) {
nuclear@0 55 goto done;
nuclear@0 56 }
nuclear@0 57 }
nuclear@0 58
nuclear@0 59 display();
nuclear@0 60 }
nuclear@0 61
nuclear@0 62 done:
nuclear@0 63 cleanup();
nuclear@0 64 return 0;
nuclear@0 65 }
nuclear@0 66
nuclear@0 67
nuclear@2 68 int init(void)
nuclear@0 69 {
nuclear@2 70 int i, x, y;
nuclear@0 71 unsigned int flags, dcaps;
nuclear@0 72 union ovrGLConfig glcfg;
nuclear@0 73
nuclear@0 74 // this must be called before any OpenGL init according to the docs
nuclear@0 75 ovr_Initialize();
nuclear@0 76
nuclear@0 77 SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
nuclear@0 78
nuclear@0 79 x = y = SDL_WINDOWPOS_UNDEFINED;
nuclear@2 80 flags = SDL_WINDOW_OPENGL;
nuclear@0 81 if(!(win = SDL_CreateWindow("simple oculus example", x, y, 1280, 800, flags))) {
nuclear@0 82 fprintf(stderr, "failed to create window\n");
nuclear@0 83 return -1;
nuclear@0 84 }
nuclear@0 85 if(!(ctx = SDL_GL_CreateContext(win))) {
nuclear@0 86 fprintf(stderr, "failed to create OpenGL context\n");
nuclear@0 87 return -1;
nuclear@0 88 }
nuclear@0 89
nuclear@0 90 glewInit();
nuclear@0 91
nuclear@0 92 if(!(hmd = ovrHmd_Create(0))) {
nuclear@0 93 fprintf(stderr, "failed to open Oculus HMD, falling back to virtual debug HMD\n");
nuclear@2 94 if(!(hmd = ovrHmd_CreateDebug(ovrHmd_DK2))) {
nuclear@0 95 fprintf(stderr, "failed to create virtual debug HMD\n");
nuclear@0 96 return -1;
nuclear@0 97 }
nuclear@0 98 }
nuclear@0 99 printf("initialized HMD: %s - %s\n", hmd->Manufacturer, hmd->ProductName);
nuclear@0 100
nuclear@2 101 SDL_SetWindowSize(win, hmd->Resolution.w, hmd->Resolution.h);
nuclear@0 102
nuclear@0 103 ovrHmd_ConfigureTracking(hmd, 0xffffffff, 0);
nuclear@0 104 eyeres[0] = ovrHmd_GetFovTextureSize(hmd, ovrEye_Left, hmd->DefaultEyeFov[0], 1.0);
nuclear@0 105 eyeres[1] = ovrHmd_GetFovTextureSize(hmd, ovrEye_Right, hmd->DefaultEyeFov[1], 1.0);
nuclear@0 106
nuclear@2 107 SDL_GetWindowSize(win, &win_width, &win_height);
nuclear@2 108
nuclear@2 109 fb_width = eyeres[0].w + eyeres[1].w;
nuclear@0 110 fb_height = eyeres[0].h > eyeres[1].h ? eyeres[0].h : eyeres[1].h;
nuclear@0 111 update_rtarg(fb_width, fb_height);
nuclear@0 112
nuclear@2 113 for(i=0; i<2; i++) {
nuclear@2 114 fb_ovr_tex[i].OGL.Header.API = ovrRenderAPI_OpenGL;
nuclear@2 115 fb_ovr_tex[i].OGL.Header.TextureSize.w = fb_tex_width;
nuclear@2 116 fb_ovr_tex[i].OGL.Header.TextureSize.h = fb_tex_height;
nuclear@2 117 fb_ovr_tex[i].OGL.Header.RenderViewport.Pos.y = 0;
nuclear@2 118 fb_ovr_tex[i].OGL.Header.RenderViewport.Size.w = fb_width / 2.0;
nuclear@2 119 fb_ovr_tex[i].OGL.Header.RenderViewport.Size.h = fb_height;
nuclear@2 120 fb_ovr_tex[i].OGL.TexId = fb_tex;
nuclear@2 121 }
nuclear@2 122 fb_ovr_tex[0].OGL.Header.RenderViewport.Pos.x = 0;
nuclear@2 123 fb_ovr_tex[1].OGL.Header.RenderViewport.Pos.x = fb_width / 2.0;
nuclear@2 124
nuclear@0 125 memset(&glcfg, 0, sizeof glcfg);
nuclear@0 126 glcfg.OGL.Header.API = ovrRenderAPI_OpenGL;
nuclear@0 127 glcfg.OGL.Header.RTSize = hmd->Resolution;
nuclear@0 128 glcfg.OGL.Header.Multisample = 1;
nuclear@0 129
nuclear@0 130 if(hmd->HmdCaps & ovrHmdCap_ExtendDesktop) {
nuclear@0 131 printf("running in \"extended desktop\" mode\n");
nuclear@0 132 } else {
nuclear@2 133 #ifdef WIN32
nuclear@2 134 void *sys_win = GetActiveWindow();
nuclear@2 135 glcfg.OGL.Window = sys_win;
nuclear@2 136 glcfg.OGL.DC = wglGetCurrentDC();
nuclear@2 137 ovrHmd_AttachToWindow(hmd, sys_win, 0, 0);
nuclear@2 138 #endif
nuclear@0 139 printf("running in \"direct-hmd\" mode\n");
nuclear@0 140 }
nuclear@2 141 ovrHmd_SetEnabledCaps(hmd, ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction);
nuclear@0 142
nuclear@2 143 dcaps = ovrDistortionCap_Chromatic | ovrDistortionCap_Vignette | ovrDistortionCap_TimeWarp;
nuclear@0 144 if(!ovrHmd_ConfigureRendering(hmd, &glcfg.Config, dcaps, hmd->DefaultEyeFov, eye_rdesc)) {
nuclear@0 145 fprintf(stderr, "failed to configure distortion renderer\n");
nuclear@0 146 }
nuclear@0 147
nuclear@2 148 /* ovrhmd_EnableHSWDisplaySDKRender(hmd, 0); */
nuclear@0 149
nuclear@0 150
nuclear@0 151 glEnable(GL_DEPTH_TEST);
nuclear@0 152 glEnable(GL_CULL_FACE);
nuclear@0 153 glEnable(GL_LIGHTING);
nuclear@0 154 glEnable(GL_LIGHT0);
nuclear@0 155
nuclear@2 156 glClearColor(0.5, 0.05, 0.05, 1);
nuclear@0 157
nuclear@0 158 return 0;
nuclear@0 159 }
nuclear@0 160
nuclear@2 161 void cleanup(void)
nuclear@0 162 {
nuclear@0 163 if(hmd) {
nuclear@0 164 ovrHmd_Destroy(hmd);
nuclear@0 165 }
nuclear@0 166 ovr_Shutdown();
nuclear@0 167
nuclear@0 168 SDL_Quit();
nuclear@0 169 }
nuclear@0 170
nuclear@2 171 void display(void)
nuclear@0 172 {
nuclear@2 173 int i;
nuclear@2 174 ovrMatrix4f proj;
nuclear@2 175 ovrPosef pose[2];
nuclear@2 176
nuclear@2 177 ovrHmd_BeginFrame(hmd, 0);
nuclear@2 178
nuclear@2 179 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
nuclear@0 180 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
nuclear@0 181
nuclear@2 182 /* for each eye ... */
nuclear@2 183 for(i=0; i<2; i++) {
nuclear@2 184 int eye = hmd->EyeRenderOrder[i];
nuclear@2 185
nuclear@2 186 /* vport0(0, 0, width/2, height), vport1(width/2, 0, width/2, height) */
nuclear@2 187 glViewport(eye == 0 ? 0 : fb_width / 2, 0, fb_width / 2, fb_height);
nuclear@2 188
nuclear@2 189 proj = ovrMatrix4f_Projection(hmd->DefaultEyeFov[eye], 0.5, 500.0, 1);
nuclear@2 190 glMatrixMode(GL_PROJECTION);
nuclear@2 191 glLoadMatrixf(proj.M[0]);
nuclear@2 192
nuclear@2 193 pose[eye] = ovrHmd_GetEyePose(hmd, eye);
nuclear@2 194 glMatrixMode(GL_MODELVIEW);
nuclear@2 195 /* TODO: get HMD orientation data and use them */
nuclear@2 196 glTranslatef(0, -ovrHmd_GetFloat(hmd, OVR_KEY_EYE_HEIGHT, 1.65), 0);
nuclear@2 197
nuclear@2 198 draw_scene();
nuclear@2 199 }
nuclear@2 200
nuclear@2 201 glBindFramebuffer(GL_FRAMEBUFFER, 0);
nuclear@2 202 glViewport(0, 0, win_width, win_height);
nuclear@2 203
nuclear@2 204 ovrHmd_EndFrame(hmd, pose, &fb_ovr_tex[0].Texture);
nuclear@2 205
nuclear@2 206 assert(glGetError() == GL_NO_ERROR);
nuclear@2 207 }
nuclear@2 208
nuclear@2 209 void draw_scene(void)
nuclear@2 210 {
nuclear@2 211 int i;
nuclear@2 212 float lpos[] = {0, 5, 0, 1};
nuclear@2 213 glLightfv(GL_LIGHT0, GL_POSITION, lpos);
nuclear@2 214
nuclear@2 215 glTranslatef(0, 5, 0);
nuclear@2 216 draw_box(20, 10, 20, -1.0);
nuclear@2 217
nuclear@2 218 for(i=0; i<4; i++) {
nuclear@2 219 glPushMatrix();
nuclear@2 220 if(i & 1) {
nuclear@2 221 glTranslatef(0, 0, i & 2 ? 7.5 : -7.5);
nuclear@2 222 } else {
nuclear@2 223 glTranslatef(i & 2 ? 7.5 : -7.5, 0, 0);
nuclear@2 224 }
nuclear@2 225 draw_box(3, 0, 3, 1.0);
nuclear@2 226 glPopMatrix();
nuclear@2 227 }
nuclear@2 228 }
nuclear@2 229
nuclear@2 230 void draw_box(float xsz, float ysz, float zsz, float norm_sign)
nuclear@2 231 {
nuclear@2 232 glMatrixMode(GL_MODELVIEW);
nuclear@2 233 glScalef(xsz * 0.5, ysz * 0.5, zsz * 0.5);
nuclear@2 234
nuclear@2 235 if(norm_sign < 0.0) {
nuclear@2 236 glFrontFace(GL_CW);
nuclear@2 237 }
nuclear@2 238
nuclear@2 239 glBegin(GL_QUADS);
nuclear@2 240 glNormal3f(0, 0, 1 * norm_sign);
nuclear@2 241 glTexCoord2f(0, 0); glVertex3f(-1, -1, 1);
nuclear@2 242 glTexCoord2f(1, 0); glVertex3f(1, -1, 1);
nuclear@2 243 glTexCoord2f(1, 1); glVertex3f(1, 1, 1);
nuclear@2 244 glTexCoord2f(0, 1); glVertex3f(-1, 1, 1);
nuclear@2 245 glNormal3f(1 * norm_sign, 0, 0);
nuclear@2 246 glTexCoord2f(0, 0); glVertex3f(1, -1, 1);
nuclear@2 247 glTexCoord2f(1, 0); glVertex3f(1, -1, -1);
nuclear@2 248 glTexCoord2f(1, 1); glVertex3f(1, 1, -1);
nuclear@2 249 glTexCoord2f(0, 1); glVertex3f(1, 1, 1);
nuclear@2 250 glNormal3f(0, 0, -1 * norm_sign);
nuclear@2 251 glTexCoord2f(0, 0); glVertex3f(1, -1, -1);
nuclear@2 252 glTexCoord2f(1, 0); glVertex3f(-1, -1, -1);
nuclear@2 253 glTexCoord2f(1, 1); glVertex3f(-1, 1, -1);
nuclear@2 254 glTexCoord2f(0, 1); glVertex3f(1, 1, -1);
nuclear@2 255 glNormal3f(-1 * norm_sign, 0, 0);
nuclear@2 256 glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
nuclear@2 257 glTexCoord2f(1, 0); glVertex3f(-1, -1, 1);
nuclear@2 258 glTexCoord2f(1, 1); glVertex3f(-1, 1, 1);
nuclear@2 259 glTexCoord2f(0, 1); glVertex3f(-1, 1, -1);
nuclear@2 260 glNormal3f(0, 1 * norm_sign, 0);
nuclear@2 261 glTexCoord2f(0, 0); glVertex3f(-1, 1, 1);
nuclear@2 262 glTexCoord2f(1, 0); glVertex3f(1, 1, 1);
nuclear@2 263 glTexCoord2f(1, 1); glVertex3f(1, 1, -1);
nuclear@2 264 glTexCoord2f(0, 1); glVertex3f(-1, 1, -1);
nuclear@2 265 glNormal3f(0, -1 * norm_sign, 0);
nuclear@2 266 glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
nuclear@2 267 glTexCoord2f(1, 0); glVertex3f(1, -1, -1);
nuclear@2 268 glTexCoord2f(1, 1); glVertex3f(1, -1, 1);
nuclear@2 269 glTexCoord2f(0, 1); glVertex3f(-1, -1, 1);
nuclear@2 270 glEnd();
nuclear@2 271
nuclear@2 272 glFrontFace(GL_CCW);
nuclear@0 273 }
nuclear@0 274
nuclear@0 275 void update_rtarg(int width, int height)
nuclear@0 276 {
nuclear@0 277 if(!fbo) {
nuclear@0 278 glGenFramebuffers(1, &fbo);
nuclear@0 279 glGenTextures(1, &fb_tex);
nuclear@0 280 glGenRenderbuffers(1, &fb_depth);
nuclear@0 281
nuclear@0 282 glBindTexture(GL_TEXTURE_2D, fb_tex);
nuclear@0 283 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
nuclear@0 284 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
nuclear@0 285 }
nuclear@0 286
nuclear@0 287 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
nuclear@0 288
nuclear@0 289 fb_tex_width = next_pow2(width);
nuclear@0 290 fb_tex_height = next_pow2(height);
nuclear@0 291
nuclear@0 292 glBindTexture(GL_TEXTURE_2D, fb_tex);
nuclear@0 293 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, fb_tex_width, fb_tex_height, 0,
nuclear@0 294 GL_RGBA, GL_UNSIGNED_BYTE, 0);
nuclear@0 295 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb_tex, 0);
nuclear@0 296
nuclear@0 297 glBindRenderbuffer(GL_RENDERBUFFER, fb_depth);
nuclear@0 298 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, fb_tex_width, fb_tex_height);
nuclear@0 299 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fb_depth);
nuclear@0 300
nuclear@0 301 if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
nuclear@0 302 fprintf(stderr, "incomplete framebuffer!\n");
nuclear@0 303 }
nuclear@0 304
nuclear@0 305 glBindFramebuffer(GL_FRAMEBUFFER, 0);
nuclear@0 306 printf("created render target: %dx%d (texture size: %dx%d)\n", width, height, fb_tex_width, fb_tex_height);
nuclear@0 307 }
nuclear@0 308
nuclear@0 309 int handle_event(SDL_Event *ev)
nuclear@0 310 {
nuclear@0 311 switch(ev->type) {
nuclear@0 312 case SDL_KEYDOWN:
nuclear@0 313 case SDL_KEYUP:
nuclear@0 314 if(key_event(ev->key.keysym.sym, ev->key.state == SDL_PRESSED) == -1) {
nuclear@0 315 return -1;
nuclear@0 316 }
nuclear@0 317 break;
nuclear@0 318
nuclear@0 319 default:
nuclear@0 320 break;
nuclear@0 321 }
nuclear@0 322
nuclear@0 323 return 0;
nuclear@0 324 }
nuclear@0 325
nuclear@0 326 int key_event(int key, int state)
nuclear@0 327 {
nuclear@0 328 if(state) {
nuclear@0 329 switch(key) {
nuclear@0 330 case 27:
nuclear@0 331 return -1;
nuclear@0 332
nuclear@0 333 default:
nuclear@0 334 break;
nuclear@0 335 }
nuclear@0 336 }
nuclear@0 337 return 0;
nuclear@0 338 }
nuclear@2 339
nuclear@2 340 unsigned int next_pow2(unsigned int x)
nuclear@2 341 {
nuclear@2 342 x -= 1;
nuclear@2 343 x |= x >> 1;
nuclear@2 344 x |= x >> 2;
nuclear@2 345 x |= x >> 4;
nuclear@2 346 x |= x >> 8;
nuclear@2 347 x |= x >> 16;
nuclear@2 348 return x + 1;
nuclear@2 349 }