# HG changeset patch # User John Tsiombikas # Date 1393364840 -7200 # Node ID 46fe847bba082c52de1f5e404bdc25ffd0d6f642 # Parent a90a71a74f0b2b348330c7c7f416840857e76d2d using goat3dgfx diff -r a90a71a74f0b -r 46fe847bba08 Makefile --- a/Makefile Tue Feb 25 19:53:34 2014 +0200 +++ b/Makefile Tue Feb 25 23:47:20 2014 +0200 @@ -4,9 +4,9 @@ dep = $(obj:.o=.d) bin = symmetry -CFLAGS = -pedantic -Wall -g -Isrc +CFLAGS = -pedantic -Wall -g -Isrc `pkg-config --cflags goat3dgfx` CXXFLAGS = $(CFLAGS) -LDFLAGS = $(libgl) $(libovr) -lvmath -limago -lm +LDFLAGS = `pkg-config --libs goat3dgfx` ifeq ($(shell uname -s), Darwin) libgl = -framework OpenGL -framework GLUT -lGLEW diff -r a90a71a74f0b -r 46fe847bba08 src/camera.cc --- a/src/camera.cc Tue Feb 25 19:53:34 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,240 +0,0 @@ -#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 a90a71a74f0b -r 46fe847bba08 src/camera.h --- a/src/camera.h Tue Feb 25 19:53:34 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +0,0 @@ -#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 a90a71a74f0b -r 46fe847bba08 src/main.cc --- a/src/main.cc Tue Feb 25 19:53:34 2014 +0200 +++ b/src/main.cc Tue Feb 25 23:47:20 2014 +0200 @@ -2,13 +2,15 @@ #include #include #include -#include "opengl.h" -#include "camera.h" +#include + +using namespace goatgfx; static bool init(); static void cleanup(); +static void disp(); +static void draw_scene(int which); 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); @@ -16,12 +18,14 @@ static void mouse(int bn, int st, int x, int y); static void motion(int x, int y); -static goatgfx::VRFpsCamera cam; +static int win_width, win_height; +static float split_pos = 0.5; +static VRFpsCamera cam; static std::vector keystate(256); int main(int argc, char **argv) { - glutInitWindowSize(800, 600); + glutInitWindowSize(1024, 768); glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); glutCreateWindow("symmetry"); @@ -68,31 +72,73 @@ unsigned int msec = glutGet(GLUT_ELAPSED_TIME); static unsigned int prev_msec; float dt = (float)(msec - prev_msec) / 1000.0f; + prev_msec = msec; handle_input(dt); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); cam.use_inverse(); + setup_gl_matrices(); - glBegin(GL_QUADS); - glNormal3f(0, 1, 0); - glVertex3f(-5, 0, 5); - glVertex3f(5, 0, 5); - glVertex3f(5, 0, -5); - glVertex3f(-5, 0, -5); - glEnd(); + float left_pixels = split_pos * win_width; - glFrontFace(GL_CW); - glutSolidTeapot(1.0); - glFrontFace(GL_CCW); + glEnable(GL_SCISSOR_TEST); + + // draw left viewport + if(left_pixels > 0) { + glScissor(0, 0, left_pixels, win_height); + draw_scene(0); + } + + // draw right viewport + if(left_pixels < win_width) { + glScissor(left_pixels, 0, win_width - left_pixels, win_height); + draw_scene(1); + } + + glDisable(GL_SCISSOR_TEST); glutSwapBuffers(); assert(glGetError() == GL_NO_ERROR); } +static void draw_scene(int which) +{ + glMatrixMode(GL_MODELVIEW); + + float lpos[] = {-5, 20, 5, 1}; + glLightfv(GL_LIGHT0, GL_POSITION, lpos); + + float color[][4] = { + {1.0, 0.3, 0.2, 1.0}, + {0.2, 0.3, 1.0, 1.0} + }; + + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color[which]); + + glBegin(GL_QUADS); + glNormal3f(0, 1, 0); + glVertex3f(-20, 0, 20); + glVertex3f(20, 0, 20); + glVertex3f(20, 0, -20); + glVertex3f(-20, 0, -20); + glEnd(); + + for(int i=0; i<8; i++) { + float theta = 360.0 * (float)i / 8.0; + glPushMatrix(); + glRotatef(theta, 0, 1, 0); + glTranslatef(0, 0, 10); + + glTranslatef(0, 1, 0); + + glFrontFace(GL_CW); + glutSolidTeapot(1.0); + glFrontFace(GL_CCW); + glPopMatrix(); + } +} static void handle_input(float dt) { @@ -124,9 +170,12 @@ { glViewport(0, 0, x, y); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluPerspective(45.0, (float)x / (float)y, 0.5, 500.0); + Matrix4x4 proj; + proj.set_perspective(DEG_TO_RAD(50), (float)x / (float)y, 0.5, 500.0); + set_projection_matrix(proj); + + win_width = x; + win_height = y; } static void keypress(unsigned char key, int x, int y) @@ -136,6 +185,10 @@ switch(key) { case 27: exit(0); + + case ' ': + split_pos = 0.5; + break; } } @@ -165,6 +218,11 @@ return; } + if(keystate[(int)'\b']) { + split_pos = (float)x / win_width; + return; + } + if(bnstate[0]) { float dtheta_deg = dy * 0.5; float dphi_deg = dx * 0.5; diff -r a90a71a74f0b -r 46fe847bba08 src/terrain.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/terrain.cc Tue Feb 25 23:47:20 2014 +0200 @@ -0,0 +1,349 @@ +#include +#include "terrain.h" +#include "imago2.h" + +using namespace goatgfx; + +Terrain::Terrain() +{ + xsz = ysz = 0; + dx = dy = 0; + hmap = 0; + scale = height_scale = 1; + + dlist = dlist_norm = 0; + + dlist_sub[0] = dlist_sub[1] = dlist_norm_sub[0] = dlist_norm_sub[1] = -1; + dlist_norm_sz = -1.0; +} + +Terrain::~Terrain() +{ + if(hmap) { + img_free_pixels(hmap); + } + + glDeleteLists(dlist, 2); +} + +void Terrain::set_scale(float s) +{ + if(s != scale) { + scale = s; + invalidate_mesh(); + } +} + +float Terrain::get_scale() const +{ + return scale; +} + +void Terrain::set_height_scale(float s) +{ + if(s != height_scale) { + height_scale = s; + invalidate_mesh(); + } +} + +float Terrain::get_height_scale() const +{ + return height_scale; +} + +bool Terrain::load(const char *fname) +{ + if(!(hmap = (float*)img_load_pixels(fname, &xsz, &ysz, IMG_FMT_GREYF))) { + fprintf(stderr, "failed to load image: %s\n", fname); + return false; + } + + dx = 1.0 / (float)(xsz - 1); + dy = 1.0 / (float)(ysz - 1); + return true; +} + +Vector2 Terrain::world_to_uv(const Vector2 &pt) const +{ + return pt / scale + 0.5; +} + +Vector2 Terrain::uv_to_world(const Vector2 &pt) const +{ + return (pt - 0.5) * scale; +} + +float Terrain::lookup(int x, int y) const +{ + int px = x < 0 ? 0 : (x >= xsz ? x = xsz - 1 : x); + int py = y < 0 ? 0 : (y >= ysz ? y = ysz - 1 : y); + return hmap[py * xsz + px]; +} + +float Terrain::get_height(const Vector2 &pt) const +{ + float fxsz = (float)xsz; + float fysz = (float)ysz; + + // the floor of x * xsz is the pixel x coordinate (e.g. [0.0, 1.0, 2.0, ... 127.0] for 128x128) + float floorx = floor(pt.x * fxsz); + float floory = floor(pt.y * fysz); + + // (x0, y0) is the lower left pixel in normalized coords of the four pixels surrounding pt + float x0 = floorx / fxsz; + float y0 = floory / fysz; + + // (u, v) is the relative position of pt within the 4pix square + // so if it's exactly at the lower-right it'll be (0, 0), in the middle it'll be (0.5, 0.5) etc. + float u = (pt.x - x0) * fxsz; + float v = (pt.y - y0) * fysz; + + // we need integer pixel coordinates to use lookup() + int px = (int)floorx; + int py = (int)floory; + + // the heights at the 4 corners + float h00 = lookup(px, py); + float h10 = lookup(px + 1, py); + float h01 = lookup(px, py + 1); + float h11 = lookup(px + 1, py + 1); + + // first interpolate along the top and bottom edges + float top = lerp(h01, h11, u); + float bot = lerp(h00, h10, u); + // then vertically between the top/bot values + return lerp(bot, top, v); +} + +Vector3 Terrain::get_normal(const Vector2 &pt) const +{ + // compute partial derivatives (slopes) in respect to X and Y using central differences + float dfdx = get_height(Vector2(pt.x + dx, pt.y)) - get_height(Vector2(pt.x - dx, pt.y)); + float dfdy = get_height(Vector2(pt.x, pt.y + dy)) - get_height(Vector2(pt.x, pt.y - dy)); + + /* we need to multiply with the final scale factors while constructing the tangent and + * bitangent vectors, otherwise the "aspect" of the normals will be wrong while changing + * the two scale factors independently. + */ + Vector3 tang = Vector3(2.0 * dx * scale, dfdx * height_scale, 0); + Vector3 bitan = Vector3(0, dfdy * height_scale, 2.0 * dy * scale); + return cross_product(bitan, tang).normalized(); +} + +float Terrain::get_world_height(const Vector2 &pt) const +{ + return get_height(world_to_uv(pt)) * height_scale; +} + +/* step over pixel distances until we cross the terrain, then determine the + * point of intersection + */ +bool Terrain::intersect(const Ray &ray, float *dist) const +{ + // axis-aligned bounding box of the terrain + AABox aabb; + aabb.min = Vector3(-0.5 * scale, 0, -0.5 * scale); + aabb.max = Vector3(0.5 * scale, height_scale, 0.5 * scale); + + Ray mray; + mray.origin = ray.origin; + // find a reasonable step size + float pixsz = dx > dy ? dx : dy; + float raysz = ray.dir.length(); + mray.dir = ray.dir / raysz * pixsz; + + float aabb_dist = 0.0; + + if(!aabb.contains(mray.origin)) { + /* if we're not in the aabb, calculate the intersection point of the ray + * with the aabb, to start ray-marching from that point. + */ + HitPoint hit; + if(!aabb.intersect(ray, &hit)) { + return false; // the ray misses the terrain completely + } + aabb_dist = hit.dist; + mray.origin += ray.dir * aabb_dist; + } + + + // ray-march over the terrain until we find an intersection or leave the box + int num_steps = 0; + do { + float mdist; + if(intersect_micro(mray, &mdist, 0.01)) { + /* to calculate the distance travelled along the original ray we need to + * first add the distance to the aabb where we started ray marching. Then + * add the fraction of the last step to the number of micro-steps up to + * this point, which have to be converted to the original ray scale by + * multiplying by the magnitude of the micro-ray direction, over the + * magnitude of the original ray direction. + */ + *dist = aabb_dist + (mdist + (float)num_steps) * pixsz / raysz; + return true; + } + + mray.origin += mray.dir; + num_steps++; + } while(aabb.contains(mray.origin)); + + return false; +} + +bool Terrain::intersect_micro(const Ray &ray, float *dist, float thres) const +{ + Vector3 start = ray.origin; + Vector3 end = ray.origin + ray.dir; + + float hstart = get_world_height(Vector2(start.x, start.z)); + float hend = get_world_height(Vector2(end.x, end.z)); + + /* if both the start and the end of the ray are above or below the heightfield + * then there's no possible intersection in micro-scales. + */ + if(start.y > hstart && end.y > hend) { + return false; // all above + } + if(start.y < hstart && end.y < hend) { + return false; // all below + } + + /* otherwise (one on one side and the other on the other side), we're straddling + * the heightfield. So, find the mid-point and binary-search until we find an + * estimated intersection point within the limits defined by "thres". + */ + Vector3 mid = lerp(start, end, 0.5); + float hmid = get_world_height(Vector2(mid.x, mid.z)); + float dh = mid.y - hmid; + + int iter = 0; // iter is there to avoid infinite loops in marginal cases + while(fabs(dh) > thres && iter < 100) { + if(dh > 0) { // mid is above the surface + start = mid; + } else { // mid is below the surface + end = mid; + } + mid = lerp(start, end, 0.5); + hmid = get_world_height(Vector2(mid.x, mid.z)); + dh = mid.y - hmid; + + iter++; + } + + // found the intersection point, calculate the parametric distance and return true + *dist = (mid - ray.origin).length() / ray.dir.length(); + return true; +} + +void Terrain::draw(int usub, int vsub) const +{ + if(usub < 1) usub = xsz - 1; + if(vsub < 1) vsub = ysz - 1; + + if(dlist && dlist_sub[0] == usub && dlist_sub[1] == vsub) { + glCallList(dlist); + return; + } + + if(!dlist) { + dlist = glGenLists(2); + dlist_norm = dlist + 1; + } + glNewList(dlist, GL_COMPILE_AND_EXECUTE); + dlist_sub[0] = usub; + dlist_sub[1] = vsub; + + float du = 1.0 / (float)usub; + float dv = 1.0 / (float)vsub; + + glBegin(GL_QUADS); + + float v = 0.0; + for(int i=0; i -#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 a90a71a74f0b -r 46fe847bba08 src/vr/vr_impl.h --- a/src/vr/vr_impl.h Tue Feb 25 19:53:34 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -#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 a90a71a74f0b -r 46fe847bba08 src/vr/vr_sdr.h --- a/src/vr/vr_sdr.h Tue Feb 25 19:53:34 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -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"; -