goat3dgfx

annotate src/vr/vr.cc @ 25:6236080aaea4

LIBOVR conditional compilation fix
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 27 Feb 2014 01:40:12 +0200
parents 7d6b667821cf
children
rev   line source
nuclear@25 1 #include "config.h"
nuclear@25 2
nuclear@11 3 #include <stdio.h>
nuclear@25 4 #include <string.h>
nuclear@25 5 #define _USE_MATH_DEFINES
nuclear@25 6 #include <math.h>
nuclear@11 7 #include <GL/glew.h>
nuclear@25 8 #include "vmath/vmath.h"
nuclear@11 9 #include "vr.h"
nuclear@11 10 #include "vr_impl.h"
nuclear@11 11 #include "vr_sdr.h"
nuclear@11 12
nuclear@11 13 #ifndef WIN32
nuclear@11 14 #include <alloca.h>
nuclear@11 15 #else
nuclear@11 16 #include <malloc.h>
nuclear@11 17 #endif
nuclear@11 18
nuclear@11 19 static void init_ctx();
nuclear@11 20 static bool init_ovr();
nuclear@11 21 static bool init_sdr();
nuclear@11 22
nuclear@11 23 VRContext vr_ctx;
nuclear@11 24 static unsigned int sdrprog;
nuclear@11 25
nuclear@11 26 extern "C" int vr_init(enum vr_init_mode mode)
nuclear@11 27 {
nuclear@11 28 init_ctx();
nuclear@11 29
nuclear@11 30 if(!init_ovr()) {
nuclear@11 31 return -1;
nuclear@11 32 }
nuclear@11 33
nuclear@11 34 if(!init_sdr()) {
nuclear@11 35 return -1;
nuclear@11 36 }
nuclear@11 37
nuclear@11 38 return 0;
nuclear@11 39 }
nuclear@11 40
nuclear@11 41 extern "C" void vr_shutdown(void)
nuclear@11 42 {
nuclear@11 43 delete [] vr_ctx.info.display;
nuclear@25 44 #ifdef USE_LIBOVR
nuclear@15 45 delete vr_ctx.ovr_sfusion;
nuclear@11 46 //System::Destroy();
nuclear@25 47 #endif
nuclear@15 48
nuclear@15 49 memset(&vr_ctx, 0, sizeof vr_ctx);
nuclear@11 50 }
nuclear@11 51
nuclear@11 52 static void init_ctx()
nuclear@11 53 {
nuclear@11 54 vr_ctx.info.width = 1280;
nuclear@11 55 vr_ctx.info.height = 800;
nuclear@11 56 vr_ctx.info.fov = M_PI / 2.0;
nuclear@11 57 vr_ctx.info.aspect = (float)vr_ctx.info.width / (float)vr_ctx.info.height;
nuclear@11 58 vr_ctx.info.ipd = 0.035;
nuclear@11 59 vr_ctx.info.scale = 1.0;
nuclear@11 60 }
nuclear@11 61
nuclear@11 62 static bool init_ovr()
nuclear@11 63 {
nuclear@25 64 #ifdef USE_LIBOVR
nuclear@11 65 LogMaskConstants log_level = LogMask_All;
nuclear@11 66 // initialize Oculus SDK
nuclear@11 67 const char *logenv = getenv("VR_LOGLEVEL");
nuclear@11 68 if(logenv) {
nuclear@11 69 switch(atoi(logenv)) {
nuclear@11 70 case 0:
nuclear@11 71 log_level = LogMask_None;
nuclear@11 72 break;
nuclear@11 73 case 1:
nuclear@11 74 log_level = LogMask_Regular;
nuclear@11 75 break;
nuclear@11 76 case 2:
nuclear@11 77 default:
nuclear@11 78 log_level = LogMask_All;
nuclear@11 79 break;
nuclear@11 80 }
nuclear@11 81 }
nuclear@11 82
nuclear@11 83 System::Init(Log::ConfigureDefaultLog(log_level));
nuclear@11 84 if(!(vr_ctx.ovr_devman = DeviceManager::Create())) {
nuclear@11 85 fprintf(stderr, "failed to create OVR device manager\n");
nuclear@11 86 return false;
nuclear@11 87 }
nuclear@11 88
nuclear@11 89 // create the display device
nuclear@11 90 HMDInfo info;
nuclear@11 91 if(!(vr_ctx.ovr_hmd_dev = vr_ctx.ovr_devman->EnumerateDevices<HMDDevice>().CreateDevice())) {
nuclear@11 92 fprintf(stderr, "no oculus rift devices found\n");
nuclear@11 93 } else {
nuclear@11 94 if(vr_ctx.ovr_hmd_dev->GetDeviceInfo(&info)) {
nuclear@11 95 printf("oculus device info:\n");
nuclear@11 96 printf(" name: %s\n", info.DisplayDeviceName);
nuclear@11 97 printf(" ipd: %f\n", info.InterpupillaryDistance);
nuclear@11 98 printf(" distortion: %f %f %f %f\n", info.DistortionK[0],
nuclear@11 99 info.DistortionK[1], info.DistortionK[2], info.DistortionK[3]);
nuclear@11 100 }
nuclear@11 101
nuclear@11 102 // calculate and store viewing parameters
nuclear@11 103 vr_ctx.info.width = info.HResolution;
nuclear@11 104 vr_ctx.info.height = info.VResolution;
nuclear@11 105 vr_ctx.info.aspect = (float)vr_ctx.info.width / (float)vr_ctx.info.height;
nuclear@11 106
nuclear@11 107 vr_ctx.info.ipd = info.InterpupillaryDistance;
nuclear@11 108 for(int i=0; i<4; i++) {
nuclear@11 109 vr_ctx.info.distort[i] = info.DistortionK[i];
nuclear@11 110 }
nuclear@11 111
nuclear@11 112 Util::Render::StereoConfig stereohelp;
nuclear@11 113 stereohelp.SetFullViewport(Util::Render::Viewport(0, 0, vr_ctx.info.width, vr_ctx.info.height));
nuclear@11 114 stereohelp.SetStereoMode(Util::Render::Stereo_LeftRight_Multipass);
nuclear@11 115 stereohelp.SetHMDInfo(info);
nuclear@11 116 stereohelp.SetDistortionFitPointVP(-1.0, 0.0);
nuclear@11 117
nuclear@11 118 vr_ctx.info.scale = stereohelp.GetDistortionScale();
nuclear@11 119
nuclear@11 120 float vhalfsz = vr_ctx.info.scale * info.VScreenSize * 0.5;
nuclear@11 121 vr_ctx.info.fov = 2.0 * atan(vhalfsz / info.EyeToScreenDistance);
nuclear@11 122
nuclear@11 123 vr_ctx.info.lens_center_offset = 0.5 - info.LensSeparationDistance / info.HScreenSize;
nuclear@11 124
nuclear@11 125 // calculate center of projection shift to match the lens positions
nuclear@11 126 float center_dist_meters = info.HScreenSize * 0.25;
nuclear@11 127 float proj_shift = center_dist_meters - info.LensSeparationDistance * 0.5;
nuclear@11 128 vr_ctx.info.proj_center_offset = 4.0 * proj_shift / info.HScreenSize;
nuclear@11 129
nuclear@11 130 // grab the display info
nuclear@11 131 vr_ctx.info.display = new char[strlen(info.DisplayDeviceName) + 1];
nuclear@11 132 strcpy(vr_ctx.info.display, info.DisplayDeviceName);
nuclear@11 133
nuclear@11 134 vr_ctx.info.display_xoffs = info.DesktopX;
nuclear@11 135 vr_ctx.info.display_yoffs = info.DesktopY;
nuclear@11 136
nuclear@11 137 printf("display: \"%s\" offset: %+d %+d\n", vr_ctx.info.display,
nuclear@11 138 vr_ctx.info.display_xoffs, vr_ctx.info.display_yoffs);
nuclear@11 139 }
nuclear@11 140
nuclear@11 141 // get the sensor device
nuclear@11 142 if(vr_ctx.ovr_hmd_dev) {
nuclear@11 143 if(!(vr_ctx.ovr_sensor_dev = vr_ctx.ovr_hmd_dev->GetSensor())) {
nuclear@11 144 fprintf(stderr, "failed to get oculus sensor device\n");
nuclear@11 145 }
nuclear@11 146 } else {
nuclear@11 147 if(!(vr_ctx.ovr_sensor_dev = vr_ctx.ovr_devman->EnumerateDevices<SensorDevice>().CreateDevice())) {
nuclear@11 148 fprintf(stderr, "failed to get oculus sensor device\n");
nuclear@11 149 }
nuclear@11 150 }
nuclear@11 151
nuclear@11 152 if(vr_ctx.ovr_sensor_dev) {
nuclear@11 153 SensorInfo sinfo;
nuclear@11 154 if(vr_ctx.ovr_sensor_dev->GetDeviceInfo(&sinfo)) {
nuclear@11 155 printf("oculus sensor device info:\n");
nuclear@11 156 printf(" name: %s\n", sinfo.ProductName);
nuclear@11 157 }
nuclear@11 158
nuclear@15 159 vr_ctx.ovr_sfusion = new SensorFusion;
nuclear@15 160 vr_ctx.ovr_sfusion->AttachToSensor(vr_ctx.ovr_sensor_dev);
nuclear@11 161 }
nuclear@25 162 #endif // USE_LIBOVR
nuclear@11 163 return true;
nuclear@11 164 }
nuclear@11 165
nuclear@11 166 #undef EXTERNAL_SHADER
nuclear@11 167
nuclear@11 168 static bool init_sdr()
nuclear@11 169 {
nuclear@11 170 int status;
nuclear@11 171
nuclear@11 172 #ifdef EXTERNAL_SHADER
nuclear@11 173 FILE *fp = fopen("sdr/sdr.glsl", "rb");
nuclear@11 174 if(!fp) {
nuclear@11 175 perror("failed to load sdr.glsl");
nuclear@11 176 return false;
nuclear@11 177 }
nuclear@11 178 fseek(fp, 0, SEEK_END);
nuclear@11 179 long sz = ftell(fp);
nuclear@11 180 rewind(fp);
nuclear@11 181
nuclear@11 182 char *buf = (char*)alloca(sz + 1);
nuclear@11 183 fread(buf, 1, sz, fp);
nuclear@11 184 buf[sz] = 0;
nuclear@11 185 sdr_src = buf;
nuclear@11 186
nuclear@11 187 fclose(fp);
nuclear@11 188 #endif
nuclear@11 189
nuclear@11 190 unsigned int sdr = glCreateShader(GL_FRAGMENT_SHADER);
nuclear@11 191 glShaderSource(sdr, 1, &sdr_src, 0);
nuclear@11 192 glCompileShader(sdr);
nuclear@11 193 glGetShaderiv(sdr, GL_COMPILE_STATUS, &status);
nuclear@11 194 if(!status) {
nuclear@11 195 fprintf(stderr, "failed to compile distortion shader\n");
nuclear@11 196
nuclear@11 197 int loglen;
nuclear@11 198 glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &loglen);
nuclear@11 199
nuclear@11 200 if(loglen > 0) {
nuclear@11 201 char *log = (char*)alloca(loglen);
nuclear@11 202 glGetShaderInfoLog(sdr, loglen, &loglen, log);
nuclear@11 203 fprintf(stderr, "%s\n", log);
nuclear@11 204 }
nuclear@11 205
nuclear@11 206 return false;
nuclear@11 207 }
nuclear@11 208
nuclear@11 209 sdrprog = glCreateProgram();
nuclear@11 210 glAttachShader(sdrprog, sdr);
nuclear@11 211 glLinkProgram(sdrprog);
nuclear@11 212 if(!status) {
nuclear@11 213 fprintf(stderr, "failed to link distortion shader program\n");
nuclear@11 214 glDeleteShader(sdr);
nuclear@11 215 return false;
nuclear@11 216 }
nuclear@11 217
nuclear@11 218 int loc;
nuclear@11 219
nuclear@11 220 glUseProgram(sdrprog);
nuclear@11 221
nuclear@11 222 if((loc = glGetUniformLocation(sdrprog, "tex")) != -1) {
nuclear@11 223 glUniform1i(loc, 0);
nuclear@11 224 }
nuclear@11 225 if((loc = glGetUniformLocation(sdrprog, "lens_center_offset")) != -1) {
nuclear@11 226 glUniform1f(loc, 0);
nuclear@11 227 }
nuclear@11 228 if((loc = glGetUniformLocation(sdrprog, "scr_center")) != -1) {
nuclear@11 229 glUniform2f(loc, 0, 0);
nuclear@11 230 }
nuclear@11 231 if((loc = glGetUniformLocation(sdrprog, "scale")) != -1) {
nuclear@11 232 glUniform1f(loc, vr_ctx.info.scale);
nuclear@11 233 }
nuclear@11 234 if((loc = glGetUniformLocation(sdrprog, "aspect")) != -1) {
nuclear@11 235 printf("setting aspect: %f\n", vr_ctx.info.aspect / 2.0);
nuclear@11 236 glUniform1f(loc, vr_ctx.info.aspect / 2.0);
nuclear@11 237 }
nuclear@11 238 if((loc = glGetUniformLocation(sdrprog, "scale_in")) != -1) {
nuclear@11 239 glUniform2f(loc, 1, 1);
nuclear@11 240 }
nuclear@11 241 if((loc = glGetUniformLocation(sdrprog, "dist_factors")) != -1) {
nuclear@11 242 glUniform4f(loc, vr_ctx.info.distort[0], vr_ctx.info.distort[1],
nuclear@11 243 vr_ctx.info.distort[2], vr_ctx.info.distort[3]);
nuclear@11 244 }
nuclear@11 245
nuclear@11 246 return true;
nuclear@11 247 }
nuclear@11 248
nuclear@11 249 extern "C" const char *vr_get_display_name(void)
nuclear@11 250 {
nuclear@11 251 return vr_ctx.info.display;
nuclear@11 252 }
nuclear@11 253
nuclear@11 254 extern "C" void vr_get_display_pos(int *xptr, int *yptr)
nuclear@11 255 {
nuclear@11 256 *xptr = vr_ctx.info.display_xoffs;
nuclear@11 257 *yptr = vr_ctx.info.display_yoffs;
nuclear@11 258 }
nuclear@11 259
nuclear@11 260 extern "C" int vr_get_width(void)
nuclear@11 261 {
nuclear@11 262 return vr_ctx.info.width;
nuclear@11 263 }
nuclear@11 264
nuclear@11 265 extern "C" int vr_get_height(void)
nuclear@11 266 {
nuclear@11 267 return vr_ctx.info.height;
nuclear@11 268 }
nuclear@11 269
nuclear@11 270 extern "C" float vr_get_fov(void)
nuclear@11 271 {
nuclear@11 272 return vr_ctx.info.fov;
nuclear@11 273 }
nuclear@11 274
nuclear@11 275 extern "C" float vr_get_aspect(void)
nuclear@11 276 {
nuclear@11 277 return vr_ctx.info.aspect;
nuclear@11 278 }
nuclear@11 279
nuclear@11 280 extern "C" void vr_set_eyedist(float ipd)
nuclear@11 281 {
nuclear@11 282 vr_ctx.info.ipd = ipd;
nuclear@11 283 }
nuclear@11 284
nuclear@11 285 extern "C" float vr_get_eyedist(void)
nuclear@11 286 {
nuclear@11 287 return vr_ctx.info.ipd;
nuclear@11 288 }
nuclear@11 289
nuclear@11 290 extern "C" void vr_set_distort(const float *coef)
nuclear@11 291 {
nuclear@11 292 memcpy(vr_ctx.info.distort, coef, sizeof vr_ctx.info.distort);
nuclear@11 293 }
nuclear@11 294
nuclear@11 295 extern "C" void vr_get_distort(float *coef)
nuclear@11 296 {
nuclear@11 297 memcpy(coef, vr_ctx.info.distort, sizeof vr_ctx.info.distort);
nuclear@11 298 }
nuclear@11 299
nuclear@11 300 extern "C" void vr_set_prediction_sec(float dt)
nuclear@11 301 {
nuclear@25 302 #ifdef USE_LIBOVR
nuclear@15 303 vr_ctx.ovr_sfusion->SetPrediction(dt);
nuclear@25 304 #endif
nuclear@11 305 }
nuclear@11 306
nuclear@11 307 extern "C" float vr_get_prediction_sec(void)
nuclear@11 308 {
nuclear@25 309 #ifdef USE_LIBOVR
nuclear@15 310 return vr_ctx.ovr_sfusion->GetPredictionDelta();
nuclear@25 311 #endif
nuclear@11 312 }
nuclear@11 313
nuclear@11 314 extern "C" void vr_get_view_matrix(float *res, int eye)
nuclear@11 315 {
nuclear@11 316 // TODO
nuclear@11 317 }
nuclear@11 318
nuclear@11 319 extern "C" void vr_get_proj_matrix(float *res, int eye)
nuclear@11 320 {
nuclear@25 321 #ifdef USE_LIBOVR
nuclear@11 322 static float eye_scale[] = {0.0, 1.0, -1.0};
nuclear@11 323
nuclear@11 324 Matrix4f proj = Matrix4f::PerspectiveRH(vr_ctx.info.fov, vr_ctx.info.aspect / 2.0, 0.3, 1000.0);
nuclear@11 325 proj = Matrix4f::Translation(vr_ctx.info.proj_center_offset * eye_scale[eye], 0, 0) * proj;
nuclear@11 326
nuclear@11 327 memcpy(res, proj.M[0], 16 * sizeof(float));
nuclear@25 328 #else
nuclear@25 329 Matrix4x4 proj;
nuclear@25 330 proj.set_perspective(vr_ctx.info.fov, vr_ctx.info.aspect, 0.3, 1000.0);
nuclear@25 331 proj.transpose();
nuclear@25 332 memcpy(res, proj[0], 16 * sizeof(float));
nuclear@25 333 #endif
nuclear@11 334 }
nuclear@11 335
nuclear@11 336 extern "C" void vr_get_translation(float *offs)
nuclear@11 337 {
nuclear@11 338 // current oculus devkit doesn't do translation
nuclear@11 339 offs[0] = offs[1] = offs[2] = 0.0f;
nuclear@11 340 }
nuclear@11 341
nuclear@11 342 extern "C" void vr_get_rotation(float *quat)
nuclear@11 343 {
nuclear@25 344 #ifdef USE_LIBOVR
nuclear@15 345 Quatf oq = vr_ctx.ovr_sfusion->GetPredictedOrientation();
nuclear@11 346 quat[0] = oq.x;
nuclear@11 347 quat[1] = oq.y;
nuclear@11 348 quat[2] = oq.z;
nuclear@11 349 quat[3] = oq.w;
nuclear@25 350 #else
nuclear@25 351 quat[0] = quat[1] = quat[2] = 0.0;
nuclear@25 352 quat[3] = 1.0;
nuclear@25 353 #endif
nuclear@11 354 }
nuclear@11 355
nuclear@11 356 extern "C" void vr_get_rotation_euler(float *euler)
nuclear@11 357 {
nuclear@25 358 #ifdef USE_LIBOVR
nuclear@15 359 Quatf oq = vr_ctx.ovr_sfusion->GetPredictedOrientation();
nuclear@11 360 oq.GetEulerAngles<Axis_Y, Axis_X, Axis_Z>(euler + 1, euler, euler + 2);
nuclear@25 361 #else
nuclear@25 362 euler[0] = euler[1] = euler[2] = 0.0;
nuclear@25 363 #endif
nuclear@11 364 }
nuclear@11 365
nuclear@11 366 extern "C" void vr_draw_eye(int eye, unsigned int tex, float tex_scale_x, float tex_scale_y)
nuclear@11 367 {
nuclear@11 368 static const float rects[3][4] = {
nuclear@11 369 {-1, -1, 1, 1},
nuclear@11 370 {-1, -1, 0, 1},
nuclear@11 371 {0, -1, 1, 1}
nuclear@11 372 };
nuclear@11 373 static const float offs_scale[3] = {0.0, -1.0, 1.0};
nuclear@11 374
nuclear@11 375 glPushAttrib(GL_ENABLE_BIT);
nuclear@11 376 glDisable(GL_DEPTH_TEST);
nuclear@11 377 glDisable(GL_LIGHTING);
nuclear@11 378 glEnable(GL_TEXTURE_2D);
nuclear@11 379
nuclear@11 380 glMatrixMode(GL_MODELVIEW);
nuclear@11 381 glPushMatrix();
nuclear@11 382 glLoadIdentity();
nuclear@11 383
nuclear@11 384 glMatrixMode(GL_PROJECTION);
nuclear@11 385 glPushMatrix();
nuclear@11 386 glLoadIdentity();
nuclear@11 387
nuclear@11 388 glUseProgram(sdrprog);
nuclear@11 389
nuclear@11 390 if(sdrprog) {
nuclear@11 391 int loc;
nuclear@11 392 if((loc = glGetUniformLocation(sdrprog, "lens_center_offset")) != -1) {
nuclear@11 393 float offset = vr_ctx.info.lens_center_offset * offs_scale[eye];
nuclear@11 394 glUniform1f(loc, offset);
nuclear@11 395 }
nuclear@11 396
nuclear@11 397 if((loc = glGetUniformLocation(sdrprog, "tex_scale")) != -1) {
nuclear@11 398 glUniform2f(loc, tex_scale_x, tex_scale_y);
nuclear@11 399 }
nuclear@11 400 }
nuclear@11 401
nuclear@11 402 glBindTexture(GL_TEXTURE_2D, tex);
nuclear@11 403 glBegin(GL_QUADS);
nuclear@11 404 glColor4f(1, 1, 1, 1);
nuclear@11 405 glTexCoord2f(0, 0); glVertex2f(rects[eye][0], rects[eye][1]);
nuclear@11 406 glTexCoord2f(1, 0); glVertex2f(rects[eye][2], rects[eye][1]);
nuclear@11 407 glTexCoord2f(1, 1); glVertex2f(rects[eye][2], rects[eye][3]);
nuclear@11 408 glTexCoord2f(0, 1); glVertex2f(rects[eye][0], rects[eye][3]);
nuclear@11 409 glEnd();
nuclear@11 410
nuclear@11 411 glUseProgram(0);
nuclear@11 412
nuclear@11 413 glPopMatrix();
nuclear@11 414 glMatrixMode(GL_MODELVIEW);
nuclear@11 415 glPopMatrix();
nuclear@11 416
nuclear@11 417 glPopAttrib();
nuclear@11 418 }