# HG changeset patch # User John Tsiombikas # Date 1393350814 -7200 # Node ID a90a71a74f0b2b348330c7c7f416840857e76d2d initial commit diff -r 000000000000 -r a90a71a74f0b .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Tue Feb 25 19:53:34 2014 +0200 @@ -0,0 +1,10 @@ +\.o$ +\.d$ +\.swp$ +\.suo$ +\.obj$ +\.exe$ +Debug/ +Release/ +\.user$ +symmetry$ diff -r 000000000000 -r a90a71a74f0b Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Tue Feb 25 19:53:34 2014 +0200 @@ -0,0 +1,31 @@ +src = $(wildcard src/*.cc) $(wildcard src/vr/*.cc) +csrc = $(wildcard src/*.c) $(wildcard src/vr/*.c) +obj = $(src:.cc=.o) $(csrc:.c=.o) +dep = $(obj:.o=.d) +bin = symmetry + +CFLAGS = -pedantic -Wall -g -Isrc +CXXFLAGS = $(CFLAGS) +LDFLAGS = $(libgl) $(libovr) -lvmath -limago -lm + +ifeq ($(shell uname -s), Darwin) + libgl = -framework OpenGL -framework GLUT -lGLEW +else + libgl = -lX11 -lGL -lGLU -lglut -lGLEW + libovr = -lXinerama -lovr -lpthread -ludev +endif + +$(bin): $(obj) + $(CXX) -o $@ $(obj) $(LDFLAGS) + +-include $(dep) + +%.d: %.c + @$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@ + +%.d: %.cc + @$(CPP) $(CXXFLAGS) $< -MM -MT $(@:.d=.o) >$@ + +.PHONY: clean +clean: + rm -f $(obj) $(bin) $(dep) diff -r 000000000000 -r a90a71a74f0b src/camera.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/camera.cc Tue Feb 25 19:53:34 2014 +0200 @@ -0,0 +1,240 @@ +#include "opengl.h" +#include "camera.h" +//#include "unistate.h" +#include "vr.h" + +using namespace goatgfx; + +Camera::Camera() +{ + roll = 0.0; + inval_cache(); +} + +Camera::~Camera() +{ +} + +void Camera::calc_inv_matrix(Matrix4x4 *mat) const +{ + *mat = matrix().inverse(); +} + +const Matrix4x4 &Camera::matrix() const +{ + if(!mcache.valid) { + calc_matrix(&mcache.mat); + mcache.valid = true; + } + return mcache.mat; +} + +const Matrix4x4 &Camera::inv_matrix() const +{ + if(!mcache_inv.valid) { + calc_inv_matrix(&mcache_inv.mat); + mcache_inv.valid = true; + } + return mcache_inv.mat; +} + +void Camera::use() const +{ + //set_view_matrix(matrix()); + mult_matrix(matrix()); +} + +void Camera::use_inverse() const +{ + //set_view_matrix(inv_matrix()); + mult_matrix(inv_matrix()); +} + +void Camera::input_move(float x, float y, float z) +{ +} + +void Camera::input_rotate(float x, float y, float z) +{ +} + +void Camera::input_zoom(float factor) +{ +} + + +// ---- orbit camera ---- + +OrbitCamera::OrbitCamera() +{ + theta = 0.0; + phi = 0.0; + rad = 10.0; +} + +OrbitCamera::~OrbitCamera() +{ +} + +void OrbitCamera::calc_matrix(Matrix4x4 *mat) const +{ + mat->reset_identity(); + mat->translate(Vector3(0, 0, -rad)); + mat->rotate(Vector3(phi, 0, 0)); + mat->rotate(Vector3(0, theta, 0)); + mat->rotate(Vector3(0, 0, roll)); +} + +void OrbitCamera::calc_inv_matrix(Matrix4x4 *mat) const +{ + mat->reset_identity(); + mat->rotate(Vector3(0, 0, roll)); + mat->rotate(Vector3(0, theta, 0)); + mat->rotate(Vector3(phi, 0, 0)); + mat->translate(Vector3(0, 0, -rad)); +} + +void OrbitCamera::input_rotate(float x, float y, float z) +{ + theta += y; + phi += x; + roll += z; + + if(phi < -M_PI / 2) + phi = -M_PI / 2; + if(phi > M_PI) + phi = M_PI; + + inval_cache(); +} + +void OrbitCamera::input_zoom(float factor) +{ + rad += factor; + if(rad < 0.0) + rad = 0.0; + + inval_cache(); +} + +void FpsCamera::calc_matrix(Matrix4x4 *mat) const +{ + mat->reset_identity(); + mat->translate(Vector3(pos.x, pos.y, pos.z)); + mat->rotate(Vector3(0, theta, 0)); + mat->rotate(Vector3(phi, 0, 0)); + mat->rotate(Vector3(0, 0, roll)); +} + +void FpsCamera::calc_inv_matrix(Matrix4x4 *mat) const +{ + mat->reset_identity(); + mat->rotate(Vector3(0, 0, roll)); + mat->rotate(Vector3(phi, 0, 0)); + mat->rotate(Vector3(0, theta, 0)); + mat->translate(Vector3(-pos.x, -pos.y, -pos.z)); +} + +void FpsCamera::input_move(float x, float y, float z) +{ + pos.x += x * cos(theta) - z * sin(theta); + pos.z += x * sin(theta) + z * cos(theta); + pos.y += y; + inval_cache(); +} + +const Vector3 &FpsCamera::get_position() const +{ + return pos; +} + + +FlyCamera::FlyCamera() +{ + pos.z = 10.0f; +} + +void FlyCamera::calc_matrix(Matrix4x4 *mat) const +{ + Matrix3x3 rmat = rot.get_rotation_matrix().transposed(); + Matrix4x4 tmat; + tmat.set_translation(pos); + *mat = tmat * Matrix4x4(rmat); +} + +/*void FlyCamera::calc_inv_matrix(Matrix4x4 *mat) const +{ +}*/ + +const Vector3 &FlyCamera::get_position() const +{ + return pos; +} + +const Quaternion &FlyCamera::get_rotation() const +{ + return rot; +} + +void FlyCamera::input_move(float x, float y, float z) +{ + static const Vector3 vfwd(0, 0, 1), vright(1, 0, 0); + + Vector3 k = vfwd.transformed(rot); + Vector3 i = vright.transformed(rot); + Vector3 j = cross_product(k, i); + + pos += i * x + j * y + k * z; + inval_cache(); +} + +void FlyCamera::input_rotate(float x, float y, float z) +{ + Vector3 axis(x, y, z); + float axis_len = axis.length(); + rot.rotate(axis / axis_len, axis_len); + rot.normalize(); + + inval_cache(); +} + + +// --- VR additions --- +VRFpsCamera::VRFpsCamera() +{ + neck_eye_dist = 0.14; // default neck->eye distance 14cm +} + +void VRFpsCamera::calc_matrix(Matrix4x4 *mat) const +{ + mat->reset_identity(); + mat->translate(Vector3(pos.x, pos.y, pos.z)); + mat->rotate(Vector3(0, theta, 0)); + mat->rotate(Vector3(phi, 0, 0)); + mat->rotate(Vector3(0, 0, roll)); + mat->translate(Vector3(0, neck_eye_dist, 0)); +} + +void VRFpsCamera::calc_inv_matrix(Matrix4x4 *mat) const +{ + mat->reset_identity(); + mat->translate(Vector3(0, -neck_eye_dist, 0)); + mat->rotate(Vector3(0, 0, roll)); + mat->rotate(Vector3(phi, 0, 0)); + mat->rotate(Vector3(0, theta, 0)); + mat->translate(Vector3(-pos.x, -pos.y, -pos.z)); +} + +void VRFpsCamera::track_vr() +{ + float euler[3]; + vr_get_rotation_euler(euler); + + // input_rotate invalidates cache + input_rotate(prev_angles[0] - euler[0], prev_angles[1] - euler[1], prev_angles[2] - euler[2]); + + prev_angles[0] = euler[0]; + prev_angles[1] = euler[1]; + prev_angles[2] = euler[2]; +} + diff -r 000000000000 -r a90a71a74f0b src/camera.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/camera.h Tue Feb 25 19:53:34 2014 +0200 @@ -0,0 +1,102 @@ +#ifndef CAMERA_H_ +#define CAMERA_H_ + +#include + +namespace goatgfx { + +class Camera { +protected: + float roll; + + mutable struct { + bool valid; + Matrix4x4 mat; + } mcache, mcache_inv; + + virtual void calc_matrix(Matrix4x4 *mat) const = 0; + virtual void calc_inv_matrix(Matrix4x4 *mat) const; + + void inval_cache() { mcache.valid = mcache_inv.valid = false; } + void set_glmat(const Matrix4x4 &m) const; + +public: + Camera(); + virtual ~Camera(); + + const Matrix4x4 &matrix() const; + const Matrix4x4 &inv_matrix() const; + + void use() const; + void use_inverse() const; + + // these do nothing, override to provide input handling + virtual void input_move(float x, float y, float z); + virtual void input_rotate(float x, float y, float z); + virtual void input_zoom(float factor); +}; + +class OrbitCamera : public Camera { +protected: + float theta, phi, rad; + + void calc_matrix(Matrix4x4 *mat) const; + void calc_inv_matrix(Matrix4x4 *mat) const; + +public: + OrbitCamera(); + virtual ~OrbitCamera(); + + void input_rotate(float x, float y, float z); + void input_zoom(float factor); +}; + +class FpsCamera : public OrbitCamera { +protected: + Vector3 pos; + + void calc_matrix(Matrix4x4 *mat) const; + void calc_inv_matrix(Matrix4x4 *mat) const; + +public: + void input_move(float x, float y, float z); + + const Vector3 &get_position() const; +}; + +class FlyCamera : public Camera { +private: + Vector3 pos; + Quaternion rot; + + void calc_matrix(Matrix4x4 *mat) const; + //void calc_inv_matrix(Matrix4x4 *mat) const; + +public: + FlyCamera(); + + const Vector3 &get_position() const; + const Quaternion &get_rotation() const; + + void input_move(float x, float y, float z); + void input_rotate(float x, float y, float z); +}; + + +class VRFpsCamera : public FpsCamera { +private: + float neck_eye_dist; + float prev_angles[3]; + + void calc_matrix(Matrix4x4 *mat) const; + void calc_inv_matrix(Matrix4x4 *mat) const; + +public: + VRFpsCamera(); + + void track_vr(); +}; + +} // namespace goatgfx + +#endif // CAMERA_H_ diff -r 000000000000 -r a90a71a74f0b src/main.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main.cc Tue Feb 25 19:53:34 2014 +0200 @@ -0,0 +1,174 @@ +#include +#include +#include +#include +#include "opengl.h" +#include "camera.h" + +static bool init(); +static void cleanup(); +static void handle_input(float dt); +static void disp(); +static void idle(); +static void reshape(int x, int y); +static void keypress(unsigned char key, int x, int y); +static void keyrelease(unsigned char key, int x, int y); +static void mouse(int bn, int st, int x, int y); +static void motion(int x, int y); + +static goatgfx::VRFpsCamera cam; +static std::vector keystate(256); + +int main(int argc, char **argv) +{ + glutInitWindowSize(800, 600); + glutInit(&argc, argv); + glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); + glutCreateWindow("symmetry"); + + glutDisplayFunc(disp); + glutIdleFunc(idle); + glutReshapeFunc(reshape); + glutKeyboardFunc(keypress); + glutKeyboardUpFunc(keyrelease); + glutMouseFunc(mouse); + glutMotionFunc(motion); + + if(!init()) { + return 1; + } + atexit(cleanup); + + glutMainLoop(); + return 0; +} + + +static bool init() +{ + glewInit(); + + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + + cam.input_move(0, 1.65, 0); + + return true; +} + +static void cleanup() +{ +} + +static void disp() +{ + unsigned int msec = glutGet(GLUT_ELAPSED_TIME); + static unsigned int prev_msec; + float dt = (float)(msec - prev_msec) / 1000.0f; + + handle_input(dt); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + cam.use_inverse(); + + glBegin(GL_QUADS); + glNormal3f(0, 1, 0); + glVertex3f(-5, 0, 5); + glVertex3f(5, 0, 5); + glVertex3f(5, 0, -5); + glVertex3f(-5, 0, -5); + glEnd(); + + glFrontFace(GL_CW); + glutSolidTeapot(1.0); + glFrontFace(GL_CCW); + + glutSwapBuffers(); + assert(glGetError() == GL_NO_ERROR); +} + + +static void handle_input(float dt) +{ + Vector3 inpv; + float offs = dt * 2.0; + + if(keystate['w'] || keystate['W']) { + inpv.z -= offs; + } + if(keystate['s'] || keystate['S']) { + inpv.z += offs; + } + if(keystate['d'] || keystate['D']) { + inpv.x += offs; + } + if(keystate['a'] || keystate['A']) { + inpv.x -= offs; + } + + cam.input_move(inpv.x, inpv.y, inpv.z); +} + +static void idle() +{ + glutPostRedisplay(); +} + +static void reshape(int x, int y) +{ + glViewport(0, 0, x, y); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(45.0, (float)x / (float)y, 0.5, 500.0); +} + +static void keypress(unsigned char key, int x, int y) +{ + keystate[key] = true; + + switch(key) { + case 27: + exit(0); + } +} + +static void keyrelease(unsigned char key, int x, int y) +{ + keystate[key] = false; +} + +static int prev_x, prev_y; +static bool bnstate[32]; + +static void mouse(int bn, int st, int x, int y) +{ + prev_x = x; + prev_y = y; + bnstate[bn - GLUT_LEFT_BUTTON] = st == GLUT_DOWN; +} + +static void motion(int x, int y) +{ + int dx = x - prev_x; + int dy = y - prev_y; + prev_x = x; + prev_y = y; + + if(!dx && !dy) { + return; + } + + if(bnstate[0]) { + float dtheta_deg = dy * 0.5; + float dphi_deg = dx * 0.5; + + cam.input_rotate(DEG_TO_RAD(dtheta_deg), DEG_TO_RAD(dphi_deg), 0); + } +} diff -r 000000000000 -r a90a71a74f0b src/opengl.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/opengl.cc Tue Feb 25 19:53:34 2014 +0200 @@ -0,0 +1,61 @@ +#include "opengl.h" +#include + +void load_matrix(const Matrix4x4 &m) +{ +#ifdef SINGLE_PRECISION_MATH + if(glLoadTransposeMatrixfARB) { + glLoadTransposeMatrixfARB((float*)&m); + } else { + Matrix4x4 tmat = m.transposed(); + glLoadMatrixf((float*)&tmat); + } +#else + if(glLoadTransposeMatrixdARB) { + glLoadTransposeMatrixdARB((double*)&m); + } else { + Matrix4x4 tmat = m.transposed(); + glLoadMatrixd((double*)&tmat); + } +#endif +} + +void mult_matrix(const Matrix4x4 &m) +{ +#ifdef SINGLE_PRECISION_MATH + if(glMultTransposeMatrixfARB) { + glMultTransposeMatrixfARB((float*)&m); + } else { + Matrix4x4 tmat = m.transposed(); + glMultMatrixf((float*)&tmat); + } +#else + if(glMultTransposeMatrixdARB) { + glMultTransposeMatrixdARB((double*)&m); + } else { + Matrix4x4 tmat = m.transposed(); + glMultMatrixd((double*)&tmat); + } +#endif +} + +const char *strglerr(int err) +{ + static const char *errnames[] = { + "GL_INVALID_ENUM", + "GL_INVALID_VALUE", + "GL_INVALID_OPERATION", + "GL_STACK_OVERFLOW", + "GL_STACK_UNDERFLOW", + "GL_OUT_OF_MEMORY", + "GL_INVALID_FRAMEBUFFER_OPERATION" + }; + + if(!err) { + return "GL_NO_ERROR"; + } + if(err < GL_INVALID_ENUM || err > GL_OUT_OF_MEMORY) { + return ""; + } + return errnames[err - GL_INVALID_ENUM]; +} diff -r 000000000000 -r a90a71a74f0b src/opengl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/opengl.h Tue Feb 25 19:53:34 2014 +0200 @@ -0,0 +1,29 @@ +#ifndef OPENGL_H_ +#define OPENGL_H_ + +#include + +#ifndef __APPLE__ +#include +#else +#include +#endif + +#define CHECKGLERR \ + do { \ + int err = glGetError(); \ + if(err) { \ + fprintf(stderr, "%s:%d: OpenGL error 0x%x: %s\n", __FILE__, __LINE__, err, strglerr(err)); \ + abort(); \ + } \ + } while(0) + + +class Matrix4x4; + +void load_matrix(const Matrix4x4 &m); +void mult_matrix(const Matrix4x4 &m); + +const char *strglerr(int err); + +#endif /* OPENGL_H_ */ diff -r 000000000000 -r a90a71a74f0b src/vr.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vr.h Tue Feb 25 19:53:34 2014 +0200 @@ -0,0 +1,63 @@ +#ifndef GOAT3DGFX_VR_H_ +#define GOAT3DGFX_VR_H_ + +/* VR mode init options */ +enum vr_init_mode { + VR_INIT_NONE, + VR_INIT_OCULUS, + VR_INIT_STEREO +}; + +/* possible eye values */ +enum { + VR_EYE_CENTER, + VR_EYE_LEFT, + VR_EYE_RIGHT +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int vr_init(enum vr_init_mode mode); +void vr_shutdown(void); + +const char *vr_get_display_name(void); +void vr_get_display_pos(int *xptr, int *yptr); + +int vr_get_width(void); +int vr_get_height(void); + +float vr_get_fov(void); +float vr_get_aspect(void); + +void vr_set_eyedist(float ipd); +float vr_get_eyedist(void); + +/* expects an array of 4 barrel distortion coefficients: + * polar scale: k_0 + k_1 r^2 + k_2 r^4 + k_3 r^6 + */ +void vr_set_distort(const float *coef); +void vr_get_distort(float *coef); + +void vr_set_prediction_sec(float dt); +float vr_get_prediction_sec(void); + +void vr_get_view_matrix(float *res, int eye); +void vr_get_proj_matrix(float *res, int eye); + +/* expects an array of at least 3 floats (x, y, z, offset). */ +void vr_get_translation(float *offs); +/* expects an array of at least 4 floats (x, y, z, w, quaternion). */ +void vr_get_rotation(float *quat); +/* expects an array of at least 3 floats (pitch, yaw, roll, angles). */ +void vr_get_rotation_euler(float *euler); + +/* OpenGL stuff */ +void vr_draw_eye(int eye, unsigned int tex, float tex_scale_x, float tex_scale_y); + +#ifdef __cplusplus +} +#endif + +#endif /* GOAT3DGFX_VR_H_ */ diff -r 000000000000 -r a90a71a74f0b src/vr/vr.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vr/vr.cc Tue Feb 25 19:53:34 2014 +0200 @@ -0,0 +1,388 @@ +#include +#include +#include "vr.h" +#include "vr_impl.h" +#include "vr_sdr.h" + +#ifndef WIN32 +#include +#else +#include +#endif + +static void init_ctx(); +static bool init_ovr(); +static bool init_sdr(); + +VRContext vr_ctx; +static unsigned int sdrprog; + +extern "C" int vr_init(enum vr_init_mode mode) +{ + init_ctx(); + + if(!init_ovr()) { + return -1; + } + + if(!init_sdr()) { + return -1; + } + + return 0; +} + +extern "C" void vr_shutdown(void) +{ + delete [] vr_ctx.info.display; + delete vr_ctx.ovr_sfusion; + //System::Destroy(); + + memset(&vr_ctx, 0, sizeof vr_ctx); +} + +static void init_ctx() +{ + vr_ctx.info.width = 1280; + vr_ctx.info.height = 800; + vr_ctx.info.fov = M_PI / 2.0; + vr_ctx.info.aspect = (float)vr_ctx.info.width / (float)vr_ctx.info.height; + vr_ctx.info.ipd = 0.035; + vr_ctx.info.scale = 1.0; +} + +static bool init_ovr() +{ + LogMaskConstants log_level = LogMask_All; + // initialize Oculus SDK + const char *logenv = getenv("VR_LOGLEVEL"); + if(logenv) { + switch(atoi(logenv)) { + case 0: + log_level = LogMask_None; + break; + case 1: + log_level = LogMask_Regular; + break; + case 2: + default: + log_level = LogMask_All; + break; + } + } + + System::Init(Log::ConfigureDefaultLog(log_level)); + if(!(vr_ctx.ovr_devman = DeviceManager::Create())) { + fprintf(stderr, "failed to create OVR device manager\n"); + return false; + } + + // create the display device + HMDInfo info; + if(!(vr_ctx.ovr_hmd_dev = vr_ctx.ovr_devman->EnumerateDevices().CreateDevice())) { + fprintf(stderr, "no oculus rift devices found\n"); + } else { + if(vr_ctx.ovr_hmd_dev->GetDeviceInfo(&info)) { + printf("oculus device info:\n"); + printf(" name: %s\n", info.DisplayDeviceName); + printf(" ipd: %f\n", info.InterpupillaryDistance); + printf(" distortion: %f %f %f %f\n", info.DistortionK[0], + info.DistortionK[1], info.DistortionK[2], info.DistortionK[3]); + } + + // calculate and store viewing parameters + vr_ctx.info.width = info.HResolution; + vr_ctx.info.height = info.VResolution; + vr_ctx.info.aspect = (float)vr_ctx.info.width / (float)vr_ctx.info.height; + + vr_ctx.info.ipd = info.InterpupillaryDistance; + for(int i=0; i<4; i++) { + vr_ctx.info.distort[i] = info.DistortionK[i]; + } + + Util::Render::StereoConfig stereohelp; + stereohelp.SetFullViewport(Util::Render::Viewport(0, 0, vr_ctx.info.width, vr_ctx.info.height)); + stereohelp.SetStereoMode(Util::Render::Stereo_LeftRight_Multipass); + stereohelp.SetHMDInfo(info); + stereohelp.SetDistortionFitPointVP(-1.0, 0.0); + + vr_ctx.info.scale = stereohelp.GetDistortionScale(); + + float vhalfsz = vr_ctx.info.scale * info.VScreenSize * 0.5; + vr_ctx.info.fov = 2.0 * atan(vhalfsz / info.EyeToScreenDistance); + + vr_ctx.info.lens_center_offset = 0.5 - info.LensSeparationDistance / info.HScreenSize; + + // calculate center of projection shift to match the lens positions + float center_dist_meters = info.HScreenSize * 0.25; + float proj_shift = center_dist_meters - info.LensSeparationDistance * 0.5; + vr_ctx.info.proj_center_offset = 4.0 * proj_shift / info.HScreenSize; + + // grab the display info + vr_ctx.info.display = new char[strlen(info.DisplayDeviceName) + 1]; + strcpy(vr_ctx.info.display, info.DisplayDeviceName); + + vr_ctx.info.display_xoffs = info.DesktopX; + vr_ctx.info.display_yoffs = info.DesktopY; + + printf("display: \"%s\" offset: %+d %+d\n", vr_ctx.info.display, + vr_ctx.info.display_xoffs, vr_ctx.info.display_yoffs); + } + + // get the sensor device + if(vr_ctx.ovr_hmd_dev) { + if(!(vr_ctx.ovr_sensor_dev = vr_ctx.ovr_hmd_dev->GetSensor())) { + fprintf(stderr, "failed to get oculus sensor device\n"); + } + } else { + if(!(vr_ctx.ovr_sensor_dev = vr_ctx.ovr_devman->EnumerateDevices().CreateDevice())) { + fprintf(stderr, "failed to get oculus sensor device\n"); + } + } + + if(vr_ctx.ovr_sensor_dev) { + SensorInfo sinfo; + if(vr_ctx.ovr_sensor_dev->GetDeviceInfo(&sinfo)) { + printf("oculus sensor device info:\n"); + printf(" name: %s\n", sinfo.ProductName); + } + + vr_ctx.ovr_sfusion = new SensorFusion; + vr_ctx.ovr_sfusion->AttachToSensor(vr_ctx.ovr_sensor_dev); + } + return true; +} + +#undef EXTERNAL_SHADER + +static bool init_sdr() +{ + int status; + +#ifdef EXTERNAL_SHADER + FILE *fp = fopen("sdr/sdr.glsl", "rb"); + if(!fp) { + perror("failed to load sdr.glsl"); + return false; + } + fseek(fp, 0, SEEK_END); + long sz = ftell(fp); + rewind(fp); + + char *buf = (char*)alloca(sz + 1); + fread(buf, 1, sz, fp); + buf[sz] = 0; + sdr_src = buf; + + fclose(fp); +#endif + + unsigned int sdr = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(sdr, 1, &sdr_src, 0); + glCompileShader(sdr); + glGetShaderiv(sdr, GL_COMPILE_STATUS, &status); + if(!status) { + fprintf(stderr, "failed to compile distortion shader\n"); + + int loglen; + glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &loglen); + + if(loglen > 0) { + char *log = (char*)alloca(loglen); + glGetShaderInfoLog(sdr, loglen, &loglen, log); + fprintf(stderr, "%s\n", log); + } + + return false; + } + + sdrprog = glCreateProgram(); + glAttachShader(sdrprog, sdr); + glLinkProgram(sdrprog); + if(!status) { + fprintf(stderr, "failed to link distortion shader program\n"); + glDeleteShader(sdr); + return false; + } + + int loc; + + glUseProgram(sdrprog); + + if((loc = glGetUniformLocation(sdrprog, "tex")) != -1) { + glUniform1i(loc, 0); + } + if((loc = glGetUniformLocation(sdrprog, "lens_center_offset")) != -1) { + glUniform1f(loc, 0); + } + if((loc = glGetUniformLocation(sdrprog, "scr_center")) != -1) { + glUniform2f(loc, 0, 0); + } + if((loc = glGetUniformLocation(sdrprog, "scale")) != -1) { + glUniform1f(loc, vr_ctx.info.scale); + } + if((loc = glGetUniformLocation(sdrprog, "aspect")) != -1) { + printf("setting aspect: %f\n", vr_ctx.info.aspect / 2.0); + glUniform1f(loc, vr_ctx.info.aspect / 2.0); + } + if((loc = glGetUniformLocation(sdrprog, "scale_in")) != -1) { + glUniform2f(loc, 1, 1); + } + if((loc = glGetUniformLocation(sdrprog, "dist_factors")) != -1) { + glUniform4f(loc, vr_ctx.info.distort[0], vr_ctx.info.distort[1], + vr_ctx.info.distort[2], vr_ctx.info.distort[3]); + } + + return true; +} + +extern "C" const char *vr_get_display_name(void) +{ + return vr_ctx.info.display; +} + +extern "C" void vr_get_display_pos(int *xptr, int *yptr) +{ + *xptr = vr_ctx.info.display_xoffs; + *yptr = vr_ctx.info.display_yoffs; +} + +extern "C" int vr_get_width(void) +{ + return vr_ctx.info.width; +} + +extern "C" int vr_get_height(void) +{ + return vr_ctx.info.height; +} + +extern "C" float vr_get_fov(void) +{ + return vr_ctx.info.fov; +} + +extern "C" float vr_get_aspect(void) +{ + return vr_ctx.info.aspect; +} + +extern "C" void vr_set_eyedist(float ipd) +{ + vr_ctx.info.ipd = ipd; +} + +extern "C" float vr_get_eyedist(void) +{ + return vr_ctx.info.ipd; +} + +extern "C" void vr_set_distort(const float *coef) +{ + memcpy(vr_ctx.info.distort, coef, sizeof vr_ctx.info.distort); +} + +extern "C" void vr_get_distort(float *coef) +{ + memcpy(coef, vr_ctx.info.distort, sizeof vr_ctx.info.distort); +} + +extern "C" void vr_set_prediction_sec(float dt) +{ + vr_ctx.ovr_sfusion->SetPrediction(dt); +} + +extern "C" float vr_get_prediction_sec(void) +{ + return vr_ctx.ovr_sfusion->GetPredictionDelta(); +} + +extern "C" void vr_get_view_matrix(float *res, int eye) +{ + // TODO +} + +extern "C" void vr_get_proj_matrix(float *res, int eye) +{ + static float eye_scale[] = {0.0, 1.0, -1.0}; + + Matrix4f proj = Matrix4f::PerspectiveRH(vr_ctx.info.fov, vr_ctx.info.aspect / 2.0, 0.3, 1000.0); + proj = Matrix4f::Translation(vr_ctx.info.proj_center_offset * eye_scale[eye], 0, 0) * proj; + + memcpy(res, proj.M[0], 16 * sizeof(float)); +} + +extern "C" void vr_get_translation(float *offs) +{ + // current oculus devkit doesn't do translation + offs[0] = offs[1] = offs[2] = 0.0f; +} + +extern "C" void vr_get_rotation(float *quat) +{ + Quatf oq = vr_ctx.ovr_sfusion->GetPredictedOrientation(); + quat[0] = oq.x; + quat[1] = oq.y; + quat[2] = oq.z; + quat[3] = oq.w; +} + +extern "C" void vr_get_rotation_euler(float *euler) +{ + Quatf oq = vr_ctx.ovr_sfusion->GetPredictedOrientation(); + oq.GetEulerAngles(euler + 1, euler, euler + 2); +} + +extern "C" void vr_draw_eye(int eye, unsigned int tex, float tex_scale_x, float tex_scale_y) +{ + static const float rects[3][4] = { + {-1, -1, 1, 1}, + {-1, -1, 0, 1}, + {0, -1, 1, 1} + }; + static const float offs_scale[3] = {0.0, -1.0, 1.0}; + + glPushAttrib(GL_ENABLE_BIT); + glDisable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glEnable(GL_TEXTURE_2D); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + glUseProgram(sdrprog); + + if(sdrprog) { + int loc; + if((loc = glGetUniformLocation(sdrprog, "lens_center_offset")) != -1) { + float offset = vr_ctx.info.lens_center_offset * offs_scale[eye]; + glUniform1f(loc, offset); + } + + if((loc = glGetUniformLocation(sdrprog, "tex_scale")) != -1) { + glUniform2f(loc, tex_scale_x, tex_scale_y); + } + } + + glBindTexture(GL_TEXTURE_2D, tex); + glBegin(GL_QUADS); + glColor4f(1, 1, 1, 1); + glTexCoord2f(0, 0); glVertex2f(rects[eye][0], rects[eye][1]); + glTexCoord2f(1, 0); glVertex2f(rects[eye][2], rects[eye][1]); + glTexCoord2f(1, 1); glVertex2f(rects[eye][2], rects[eye][3]); + glTexCoord2f(0, 1); glVertex2f(rects[eye][0], rects[eye][3]); + glEnd(); + + glUseProgram(0); + + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + glPopAttrib(); +} diff -r 000000000000 -r a90a71a74f0b src/vr/vr_impl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vr/vr_impl.h Tue Feb 25 19:53:34 2014 +0200 @@ -0,0 +1,36 @@ +#ifndef VR_IMPL_H_ +#define VR_IMPL_H_ + +#include + +using namespace OVR; + +struct VRContext { + DeviceManager *ovr_devman; + HMDDevice *ovr_hmd_dev; + SensorDevice *ovr_sensor_dev; + SensorFusion *ovr_sfusion; + + struct { + char *display; + int display_xoffs, display_yoffs; + + // the full width and height of the display (both eyes) + int width, height; + float fov; + // the full aspect ratio of the display (both eyes) + float aspect; + float ipd; + float distort[4]; + // the right lens center offset (negate for left) + float lens_center_offset; + float proj_center_offset; + float scale; // scaling to be applied to the two views to fill the screen + } info; +}; + +extern VRContext vr_ctx; + +bool vr_gl_init(); + +#endif // VR_IMPL_H_ diff -r 000000000000 -r a90a71a74f0b src/vr/vr_sdr.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vr/vr_sdr.h Tue Feb 25 19:53:34 2014 +0200 @@ -0,0 +1,45 @@ +static const char *sdr_src = + "uniform sampler2D tex;\n" + "uniform float aspect, scale;\n" + "uniform float lens_center_offset;\n" + "uniform vec4 dist_factors;\n" + "\n" + "vec2 distort_texcoords(in vec2 tc);\n" + "float barrel_scale(float x, in vec4 k);\n" + "\n" + "void main()\n" + "{\n" + " vec2 tc = distort_texcoords(gl_TexCoord[0].xy);\n" + "\n" + " float vis = any(greaterThan(tc, vec2(1.0)) || lessThan(tc, vec2(0.0))) ? 0.0 : 1.0;\n" + "\n" + " gl_FragColor.rgb = texture2D(tex, tc).rgb * vis;\n" + " gl_FragColor.a = 1.0;\n" + "}\n" + "\n" + "vec2 distort_texcoords(in vec2 tc)\n" + "{\n" + " // map tc [0, 1] -> [-1, 1]\n" + " vec2 pt = tc * 2.0 - 1.0;\n" + "\n" + " pt.x += lens_center_offset * 2.0;\n" + " pt.y /= aspect; // correct for aspect ratio\n" + "\n" + " float rad = barrel_scale(dot(pt, pt), dist_factors);\n" + " pt *= rad; // scale the point by the computer distortion radius\n" + "\n" + " pt /= scale;\n" + " pt.y *= aspect;\n" + " pt.x -= lens_center_offset * 2.0;\n" + "\n" + " // map back to range [0, 1]\n" + " return pt * 0.5 + 0.5;\n" + "}\n" + "\n" + "float barrel_scale(float rad, in vec4 k)\n" + "{\n" + " float radsq = rad * rad;\n" + " float radquad = radsq * radsq;\n" + " return k.x + k.y * radsq + k.z * radquad + k.w * radquad * radsq;\n" + "}\n"; +