nuclear@11: #include nuclear@11: #include nuclear@11: #include "vr.h" nuclear@11: #include "vr_impl.h" nuclear@11: #include "vr_sdr.h" nuclear@11: nuclear@11: #ifndef WIN32 nuclear@11: #include nuclear@11: #else nuclear@11: #include nuclear@11: #endif nuclear@11: nuclear@11: static void init_ctx(); nuclear@11: static bool init_ovr(); nuclear@11: static bool init_sdr(); nuclear@11: nuclear@11: VRContext vr_ctx; nuclear@11: static unsigned int sdrprog; nuclear@11: nuclear@11: extern "C" int vr_init(enum vr_init_mode mode) nuclear@11: { nuclear@11: init_ctx(); nuclear@11: nuclear@11: if(!init_ovr()) { nuclear@11: return -1; nuclear@11: } nuclear@11: nuclear@11: if(!init_sdr()) { nuclear@11: return -1; nuclear@11: } nuclear@11: nuclear@11: return 0; nuclear@11: } nuclear@11: nuclear@11: extern "C" void vr_shutdown(void) nuclear@11: { nuclear@11: delete [] vr_ctx.info.display; nuclear@15: delete vr_ctx.ovr_sfusion; nuclear@11: //System::Destroy(); nuclear@15: nuclear@15: memset(&vr_ctx, 0, sizeof vr_ctx); nuclear@11: } nuclear@11: nuclear@11: static void init_ctx() nuclear@11: { nuclear@11: vr_ctx.info.width = 1280; nuclear@11: vr_ctx.info.height = 800; nuclear@11: vr_ctx.info.fov = M_PI / 2.0; nuclear@11: vr_ctx.info.aspect = (float)vr_ctx.info.width / (float)vr_ctx.info.height; nuclear@11: vr_ctx.info.ipd = 0.035; nuclear@11: vr_ctx.info.scale = 1.0; nuclear@11: } nuclear@11: nuclear@11: static bool init_ovr() nuclear@11: { nuclear@11: LogMaskConstants log_level = LogMask_All; nuclear@11: // initialize Oculus SDK nuclear@11: const char *logenv = getenv("VR_LOGLEVEL"); nuclear@11: if(logenv) { nuclear@11: switch(atoi(logenv)) { nuclear@11: case 0: nuclear@11: log_level = LogMask_None; nuclear@11: break; nuclear@11: case 1: nuclear@11: log_level = LogMask_Regular; nuclear@11: break; nuclear@11: case 2: nuclear@11: default: nuclear@11: log_level = LogMask_All; nuclear@11: break; nuclear@11: } nuclear@11: } nuclear@11: nuclear@11: System::Init(Log::ConfigureDefaultLog(log_level)); nuclear@11: if(!(vr_ctx.ovr_devman = DeviceManager::Create())) { nuclear@11: fprintf(stderr, "failed to create OVR device manager\n"); nuclear@11: return false; nuclear@11: } nuclear@11: nuclear@11: // create the display device nuclear@11: HMDInfo info; nuclear@11: if(!(vr_ctx.ovr_hmd_dev = vr_ctx.ovr_devman->EnumerateDevices().CreateDevice())) { nuclear@11: fprintf(stderr, "no oculus rift devices found\n"); nuclear@11: } else { nuclear@11: if(vr_ctx.ovr_hmd_dev->GetDeviceInfo(&info)) { nuclear@11: printf("oculus device info:\n"); nuclear@11: printf(" name: %s\n", info.DisplayDeviceName); nuclear@11: printf(" ipd: %f\n", info.InterpupillaryDistance); nuclear@11: printf(" distortion: %f %f %f %f\n", info.DistortionK[0], nuclear@11: info.DistortionK[1], info.DistortionK[2], info.DistortionK[3]); nuclear@11: } nuclear@11: nuclear@11: // calculate and store viewing parameters nuclear@11: vr_ctx.info.width = info.HResolution; nuclear@11: vr_ctx.info.height = info.VResolution; nuclear@11: vr_ctx.info.aspect = (float)vr_ctx.info.width / (float)vr_ctx.info.height; nuclear@11: nuclear@11: vr_ctx.info.ipd = info.InterpupillaryDistance; nuclear@11: for(int i=0; i<4; i++) { nuclear@11: vr_ctx.info.distort[i] = info.DistortionK[i]; nuclear@11: } nuclear@11: nuclear@11: Util::Render::StereoConfig stereohelp; nuclear@11: stereohelp.SetFullViewport(Util::Render::Viewport(0, 0, vr_ctx.info.width, vr_ctx.info.height)); nuclear@11: stereohelp.SetStereoMode(Util::Render::Stereo_LeftRight_Multipass); nuclear@11: stereohelp.SetHMDInfo(info); nuclear@11: stereohelp.SetDistortionFitPointVP(-1.0, 0.0); nuclear@11: nuclear@11: vr_ctx.info.scale = stereohelp.GetDistortionScale(); nuclear@11: nuclear@11: float vhalfsz = vr_ctx.info.scale * info.VScreenSize * 0.5; nuclear@11: vr_ctx.info.fov = 2.0 * atan(vhalfsz / info.EyeToScreenDistance); nuclear@11: nuclear@11: vr_ctx.info.lens_center_offset = 0.5 - info.LensSeparationDistance / info.HScreenSize; nuclear@11: nuclear@11: // calculate center of projection shift to match the lens positions nuclear@11: float center_dist_meters = info.HScreenSize * 0.25; nuclear@11: float proj_shift = center_dist_meters - info.LensSeparationDistance * 0.5; nuclear@11: vr_ctx.info.proj_center_offset = 4.0 * proj_shift / info.HScreenSize; nuclear@11: nuclear@11: // grab the display info nuclear@11: vr_ctx.info.display = new char[strlen(info.DisplayDeviceName) + 1]; nuclear@11: strcpy(vr_ctx.info.display, info.DisplayDeviceName); nuclear@11: nuclear@11: vr_ctx.info.display_xoffs = info.DesktopX; nuclear@11: vr_ctx.info.display_yoffs = info.DesktopY; nuclear@11: nuclear@11: printf("display: \"%s\" offset: %+d %+d\n", vr_ctx.info.display, nuclear@11: vr_ctx.info.display_xoffs, vr_ctx.info.display_yoffs); nuclear@11: } nuclear@11: nuclear@11: // get the sensor device nuclear@11: if(vr_ctx.ovr_hmd_dev) { nuclear@11: if(!(vr_ctx.ovr_sensor_dev = vr_ctx.ovr_hmd_dev->GetSensor())) { nuclear@11: fprintf(stderr, "failed to get oculus sensor device\n"); nuclear@11: } nuclear@11: } else { nuclear@11: if(!(vr_ctx.ovr_sensor_dev = vr_ctx.ovr_devman->EnumerateDevices().CreateDevice())) { nuclear@11: fprintf(stderr, "failed to get oculus sensor device\n"); nuclear@11: } nuclear@11: } nuclear@11: nuclear@11: if(vr_ctx.ovr_sensor_dev) { nuclear@11: SensorInfo sinfo; nuclear@11: if(vr_ctx.ovr_sensor_dev->GetDeviceInfo(&sinfo)) { nuclear@11: printf("oculus sensor device info:\n"); nuclear@11: printf(" name: %s\n", sinfo.ProductName); nuclear@11: } nuclear@11: nuclear@15: vr_ctx.ovr_sfusion = new SensorFusion; nuclear@15: vr_ctx.ovr_sfusion->AttachToSensor(vr_ctx.ovr_sensor_dev); nuclear@11: } nuclear@11: return true; nuclear@11: } nuclear@11: nuclear@11: #undef EXTERNAL_SHADER nuclear@11: nuclear@11: static bool init_sdr() nuclear@11: { nuclear@11: int status; nuclear@11: nuclear@11: #ifdef EXTERNAL_SHADER nuclear@11: FILE *fp = fopen("sdr/sdr.glsl", "rb"); nuclear@11: if(!fp) { nuclear@11: perror("failed to load sdr.glsl"); nuclear@11: return false; nuclear@11: } nuclear@11: fseek(fp, 0, SEEK_END); nuclear@11: long sz = ftell(fp); nuclear@11: rewind(fp); nuclear@11: nuclear@11: char *buf = (char*)alloca(sz + 1); nuclear@11: fread(buf, 1, sz, fp); nuclear@11: buf[sz] = 0; nuclear@11: sdr_src = buf; nuclear@11: nuclear@11: fclose(fp); nuclear@11: #endif nuclear@11: nuclear@11: unsigned int sdr = glCreateShader(GL_FRAGMENT_SHADER); nuclear@11: glShaderSource(sdr, 1, &sdr_src, 0); nuclear@11: glCompileShader(sdr); nuclear@11: glGetShaderiv(sdr, GL_COMPILE_STATUS, &status); nuclear@11: if(!status) { nuclear@11: fprintf(stderr, "failed to compile distortion shader\n"); nuclear@11: nuclear@11: int loglen; nuclear@11: glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &loglen); nuclear@11: nuclear@11: if(loglen > 0) { nuclear@11: char *log = (char*)alloca(loglen); nuclear@11: glGetShaderInfoLog(sdr, loglen, &loglen, log); nuclear@11: fprintf(stderr, "%s\n", log); nuclear@11: } nuclear@11: nuclear@11: return false; nuclear@11: } nuclear@11: nuclear@11: sdrprog = glCreateProgram(); nuclear@11: glAttachShader(sdrprog, sdr); nuclear@11: glLinkProgram(sdrprog); nuclear@11: if(!status) { nuclear@11: fprintf(stderr, "failed to link distortion shader program\n"); nuclear@11: glDeleteShader(sdr); nuclear@11: return false; nuclear@11: } nuclear@11: nuclear@11: int loc; nuclear@11: nuclear@11: glUseProgram(sdrprog); nuclear@11: nuclear@11: if((loc = glGetUniformLocation(sdrprog, "tex")) != -1) { nuclear@11: glUniform1i(loc, 0); nuclear@11: } nuclear@11: if((loc = glGetUniformLocation(sdrprog, "lens_center_offset")) != -1) { nuclear@11: glUniform1f(loc, 0); nuclear@11: } nuclear@11: if((loc = glGetUniformLocation(sdrprog, "scr_center")) != -1) { nuclear@11: glUniform2f(loc, 0, 0); nuclear@11: } nuclear@11: if((loc = glGetUniformLocation(sdrprog, "scale")) != -1) { nuclear@11: glUniform1f(loc, vr_ctx.info.scale); nuclear@11: } nuclear@11: if((loc = glGetUniformLocation(sdrprog, "aspect")) != -1) { nuclear@11: printf("setting aspect: %f\n", vr_ctx.info.aspect / 2.0); nuclear@11: glUniform1f(loc, vr_ctx.info.aspect / 2.0); nuclear@11: } nuclear@11: if((loc = glGetUniformLocation(sdrprog, "scale_in")) != -1) { nuclear@11: glUniform2f(loc, 1, 1); nuclear@11: } nuclear@11: if((loc = glGetUniformLocation(sdrprog, "dist_factors")) != -1) { nuclear@11: glUniform4f(loc, vr_ctx.info.distort[0], vr_ctx.info.distort[1], nuclear@11: vr_ctx.info.distort[2], vr_ctx.info.distort[3]); nuclear@11: } nuclear@11: nuclear@11: return true; nuclear@11: } nuclear@11: nuclear@11: extern "C" const char *vr_get_display_name(void) nuclear@11: { nuclear@11: return vr_ctx.info.display; nuclear@11: } nuclear@11: nuclear@11: extern "C" void vr_get_display_pos(int *xptr, int *yptr) nuclear@11: { nuclear@11: *xptr = vr_ctx.info.display_xoffs; nuclear@11: *yptr = vr_ctx.info.display_yoffs; nuclear@11: } nuclear@11: nuclear@11: extern "C" int vr_get_width(void) nuclear@11: { nuclear@11: return vr_ctx.info.width; nuclear@11: } nuclear@11: nuclear@11: extern "C" int vr_get_height(void) nuclear@11: { nuclear@11: return vr_ctx.info.height; nuclear@11: } nuclear@11: nuclear@11: extern "C" float vr_get_fov(void) nuclear@11: { nuclear@11: return vr_ctx.info.fov; nuclear@11: } nuclear@11: nuclear@11: extern "C" float vr_get_aspect(void) nuclear@11: { nuclear@11: return vr_ctx.info.aspect; nuclear@11: } nuclear@11: nuclear@11: extern "C" void vr_set_eyedist(float ipd) nuclear@11: { nuclear@11: vr_ctx.info.ipd = ipd; nuclear@11: } nuclear@11: nuclear@11: extern "C" float vr_get_eyedist(void) nuclear@11: { nuclear@11: return vr_ctx.info.ipd; nuclear@11: } nuclear@11: nuclear@11: extern "C" void vr_set_distort(const float *coef) nuclear@11: { nuclear@11: memcpy(vr_ctx.info.distort, coef, sizeof vr_ctx.info.distort); nuclear@11: } nuclear@11: nuclear@11: extern "C" void vr_get_distort(float *coef) nuclear@11: { nuclear@11: memcpy(coef, vr_ctx.info.distort, sizeof vr_ctx.info.distort); nuclear@11: } nuclear@11: nuclear@11: extern "C" void vr_set_prediction_sec(float dt) nuclear@11: { nuclear@15: vr_ctx.ovr_sfusion->SetPrediction(dt); nuclear@11: } nuclear@11: nuclear@11: extern "C" float vr_get_prediction_sec(void) nuclear@11: { nuclear@15: return vr_ctx.ovr_sfusion->GetPredictionDelta(); nuclear@11: } nuclear@11: nuclear@11: extern "C" void vr_get_view_matrix(float *res, int eye) nuclear@11: { nuclear@11: // TODO nuclear@11: } nuclear@11: nuclear@11: extern "C" void vr_get_proj_matrix(float *res, int eye) nuclear@11: { nuclear@11: static float eye_scale[] = {0.0, 1.0, -1.0}; nuclear@11: nuclear@11: Matrix4f proj = Matrix4f::PerspectiveRH(vr_ctx.info.fov, vr_ctx.info.aspect / 2.0, 0.3, 1000.0); nuclear@11: proj = Matrix4f::Translation(vr_ctx.info.proj_center_offset * eye_scale[eye], 0, 0) * proj; nuclear@11: nuclear@11: memcpy(res, proj.M[0], 16 * sizeof(float)); nuclear@11: } nuclear@11: nuclear@11: extern "C" void vr_get_translation(float *offs) nuclear@11: { nuclear@11: // current oculus devkit doesn't do translation nuclear@11: offs[0] = offs[1] = offs[2] = 0.0f; nuclear@11: } nuclear@11: nuclear@11: extern "C" void vr_get_rotation(float *quat) nuclear@11: { nuclear@15: Quatf oq = vr_ctx.ovr_sfusion->GetPredictedOrientation(); nuclear@11: quat[0] = oq.x; nuclear@11: quat[1] = oq.y; nuclear@11: quat[2] = oq.z; nuclear@11: quat[3] = oq.w; nuclear@11: } nuclear@11: nuclear@11: extern "C" void vr_get_rotation_euler(float *euler) nuclear@11: { nuclear@15: Quatf oq = vr_ctx.ovr_sfusion->GetPredictedOrientation(); nuclear@11: oq.GetEulerAngles(euler + 1, euler, euler + 2); nuclear@11: } nuclear@11: nuclear@11: extern "C" void vr_draw_eye(int eye, unsigned int tex, float tex_scale_x, float tex_scale_y) nuclear@11: { nuclear@11: static const float rects[3][4] = { nuclear@11: {-1, -1, 1, 1}, nuclear@11: {-1, -1, 0, 1}, nuclear@11: {0, -1, 1, 1} nuclear@11: }; nuclear@11: static const float offs_scale[3] = {0.0, -1.0, 1.0}; nuclear@11: nuclear@11: glPushAttrib(GL_ENABLE_BIT); nuclear@11: glDisable(GL_DEPTH_TEST); nuclear@11: glDisable(GL_LIGHTING); nuclear@11: glEnable(GL_TEXTURE_2D); nuclear@11: nuclear@11: glMatrixMode(GL_MODELVIEW); nuclear@11: glPushMatrix(); nuclear@11: glLoadIdentity(); nuclear@11: nuclear@11: glMatrixMode(GL_PROJECTION); nuclear@11: glPushMatrix(); nuclear@11: glLoadIdentity(); nuclear@11: nuclear@11: glUseProgram(sdrprog); nuclear@11: nuclear@11: if(sdrprog) { nuclear@11: int loc; nuclear@11: if((loc = glGetUniformLocation(sdrprog, "lens_center_offset")) != -1) { nuclear@11: float offset = vr_ctx.info.lens_center_offset * offs_scale[eye]; nuclear@11: glUniform1f(loc, offset); nuclear@11: } nuclear@11: nuclear@11: if((loc = glGetUniformLocation(sdrprog, "tex_scale")) != -1) { nuclear@11: glUniform2f(loc, tex_scale_x, tex_scale_y); nuclear@11: } nuclear@11: } nuclear@11: nuclear@11: glBindTexture(GL_TEXTURE_2D, tex); nuclear@11: glBegin(GL_QUADS); nuclear@11: glColor4f(1, 1, 1, 1); nuclear@11: glTexCoord2f(0, 0); glVertex2f(rects[eye][0], rects[eye][1]); nuclear@11: glTexCoord2f(1, 0); glVertex2f(rects[eye][2], rects[eye][1]); nuclear@11: glTexCoord2f(1, 1); glVertex2f(rects[eye][2], rects[eye][3]); nuclear@11: glTexCoord2f(0, 1); glVertex2f(rects[eye][0], rects[eye][3]); nuclear@11: glEnd(); nuclear@11: nuclear@11: glUseProgram(0); nuclear@11: nuclear@11: glPopMatrix(); nuclear@11: glMatrixMode(GL_MODELVIEW); nuclear@11: glPopMatrix(); nuclear@11: nuclear@11: glPopAttrib(); nuclear@11: }