-#include <cmath>
-#include <msp/gl/meshbuilder.h>
-#include <msp/gl/texture2d.h>
-#include "oculusriftcombiner.h"
-#include "oculusriftdevice.h"
-#include "oculusriftdevice_private.h"
-
-using namespace std;
-
-
-namespace {
-
-const char vs_source[] =
- "uniform mat4 timewarp[2];\n"
- "uniform vec2 uv_scale;\n"
- "uniform vec2 uv_offset;\n"
- "varying vec2 texcoord_r;\n"
- "varying vec2 texcoord_g;\n"
- "varying vec2 texcoord_b;\n"
- "varying float vignette;\n"
- "vec2 apply_timewarp(vec2 coords, float factor)\n"
- "{\n"
- " vec4 coords4 = vec4(coords, 1.0, 1.0);\n"
- " vec4 warped = mix(timewarp[0]*coords4, timewarp[1]*coords4, factor);\n"
- " return (warped.xy/warped.z)*uv_scale+uv_offset;\n"
- "}\n"
- "void main()\n"
- "{\n"
- " gl_Position = vec4(gl_Vertex.xy, 0.5, 1.0);\n"
- " float tw_factor = gl_MultiTexCoord3.y;\n"
- " texcoord_r = apply_timewarp(gl_MultiTexCoord0.xy, tw_factor);\n"
- " texcoord_g = apply_timewarp(gl_MultiTexCoord1.xy, tw_factor);\n"
- " texcoord_b = apply_timewarp(gl_MultiTexCoord2.xy, tw_factor);\n"
- " vignette = gl_MultiTexCoord3.x;\n"
- "}\n";
-
-const char fs_source[] =
- "uniform sampler2D texture;\n"
- "varying vec2 texcoord_r;\n"
- "varying vec2 texcoord_g;\n"
- "varying vec2 texcoord_b;\n"
- "varying float vignette;\n"
- "void main()\n"
- "{\n"
- " float r = texture2D(texture, texcoord_r).r;\n"
- " float g = texture2D(texture, texcoord_g).g;\n"
- " float b = texture2D(texture, texcoord_b).b;\n"
- " gl_FragColor = vec4(vec3(r, g, b)*vignette, 1.0);\n"
- "}\n";
-
-void create_distortion_mesh(Msp::GL::Mesh &mesh, ovrHmd hmd, ovrEyeType eye, const ovrFovPort &fov)
-{
- ovrDistortionMesh ovr_mesh;
- ovrHmd_CreateDistortionMesh(hmd, eye, fov, ovrDistortionCap_Vignette|ovrDistortionCap_TimeWarp, &ovr_mesh);
-
- Msp::GL::MeshBuilder bld(mesh);
- for(unsigned i=0; i<ovr_mesh.VertexCount; ++i)
- {
- ovrDistortionVertex &v = ovr_mesh.pVertexData[i];
- bld.multitexcoord(0, v.TanEyeAnglesR.x, v.TanEyeAnglesR.y);
- bld.multitexcoord(1, v.TanEyeAnglesG.x, v.TanEyeAnglesG.y);
- bld.multitexcoord(2, v.TanEyeAnglesB.x, v.TanEyeAnglesB.y);
- bld.multitexcoord(3, v.VignetteFactor, v.TimeWarpFactor);
- bld.vertex(v.ScreenPosNDC.x, v.ScreenPosNDC.y);
- }
-
- Msp::GL::Batch batch(Msp::GL::TRIANGLES);
- batch.append(vector<unsigned>(ovr_mesh.pIndexData, ovr_mesh.pIndexData+ovr_mesh.IndexCount));
- mesh.add_batch(batch);
-
- ovrHmd_DestroyDistortionMesh(&ovr_mesh);
-}
-
-}
-
-namespace Msp {
-namespace VR {
-
-OculusRiftCombiner::OculusRiftCombiner(const OculusRiftDevice &d):
- device(d),
- left_mesh((GL::VERTEX2, GL::TEXCOORD2,0, GL::TEXCOORD2,1, GL::TEXCOORD2,2, GL::TEXCOORD2,3)),
- right_mesh((GL::VERTEX2, GL::TEXCOORD2,0, GL::TEXCOORD2,1, GL::TEXCOORD2,2, GL::TEXCOORD2,3)),
- shprog(vs_source, fs_source)
-{
- ovrHmd hmd = device.get_private().ovr_hmd;
-
- ovrFovPort left_fov = hmd->DefaultEyeFov[ovrEye_Left];
- ovrFovPort right_fov = hmd->DefaultEyeFov[ovrEye_Right];
- float vertical = max(max(left_fov.UpTan, left_fov.DownTan), max(right_fov.UpTan, right_fov.DownTan));
- fov = Geometry::atan<float>(vertical)*2.0f;
-
- float inner = max(left_fov.RightTan, right_fov.LeftTan);
- float outer = max(left_fov.LeftTan, right_fov.RightTan);
- frustum_skew = (inner-outer)/(inner+outer);
-
- left_fov.UpTan = right_fov.UpTan = vertical;
- left_fov.DownTan = right_fov.DownTan = vertical;
- left_fov.RightTan = right_fov.LeftTan = inner;
- left_fov.LeftTan = right_fov.RightTan = outer;
-
- create_distortion_mesh(left_mesh, hmd, ovrEye_Left, left_fov);
- create_distortion_mesh(right_mesh, hmd, ovrEye_Right, right_fov);
-
- ovrSizei tex_size = ovrHmd_GetFovTextureSize(hmd, ovrEye_Left, left_fov, 1.0);
- width_factor = tex_size.w*1.0f/hmd->Resolution.w;
- height_factor = tex_size.h*1.0f/hmd->Resolution.h;
- float aspect = (inner+outer)/(vertical*2);
- aspect_factor = aspect*hmd->Resolution.h/hmd->Resolution.w;
-
- left_shdata.uniform("texture", 0);
- right_shdata.uniform("texture", 0);
-
- ovrRecti view_rect;
- view_rect.Pos.x = 0;
- view_rect.Pos.y = 0;
- view_rect.Size = tex_size;
- ovrVector2f uv_scale_offset[2];
- ovrHmd_GetRenderScaleAndOffset(left_fov, tex_size, view_rect, uv_scale_offset);
- left_shdata.uniform("uv_scale", uv_scale_offset[0].x, -uv_scale_offset[0].y);
- left_shdata.uniform("uv_offset", uv_scale_offset[1].x, 1-uv_scale_offset[1].y);
- ovrHmd_GetRenderScaleAndOffset(right_fov, tex_size, view_rect, uv_scale_offset);
- right_shdata.uniform("uv_scale", uv_scale_offset[0].x, -uv_scale_offset[0].y);
- right_shdata.uniform("uv_offset", uv_scale_offset[1].x, 1-uv_scale_offset[1].y);
-}
-
-void OculusRiftCombiner::render(const GL::Texture2D &left, const GL::Texture2D &right) const
-{
- GL::Bind bind_shprog(shprog);
-
- ovrHmd hmd = device.get_private().ovr_hmd;
-
- if(device.is_timing_active())
- {
- ovr_WaitTillTime(device.get_timewarp_time());
- ovrTrackingState state = ovrHmd_GetTrackingState(hmd, device.get_tracking_time());
-
- ovrMatrix4f matrices[2];
- ovrHmd_GetEyeTimewarpMatrices(hmd, ovrEye_Left, state.HeadPose.ThePose, matrices);
- left_shdata.uniform_matrix4_array("timewarp", 2, &matrices[0].M[0][0]);
-
- ovrHmd_GetEyeTimewarpMatrices(hmd, ovrEye_Right, state.HeadPose.ThePose, matrices);
- right_shdata.uniform_matrix4_array("timewarp", 2, &matrices[0].M[0][0]);
- }
- else
- {
- GL::Matrix matrices[2];
- left_shdata.uniform_matrix4_array("timewarp", 2, matrices[0].data());
- right_shdata.uniform_matrix4_array("timewarp", 2, matrices[0].data());
- }
-
- GL::Bind bind_tex(left);
- left_shdata.apply();
- left_mesh.draw();
-
- right.bind();
- right_shdata.apply();
- right_mesh.draw();
-}
-
-} // namespace VR
-} // namespace Msp