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