X-Git-Url: http://git.tdb.fi/?p=libs%2Fvr.git;a=blobdiff_plain;f=source%2Flibovr%2Flibovrcombiner.cpp;fp=source%2Flibovr%2Flibovrcombiner.cpp;h=5eddb4a2f91e959065119b180a70f664515edca6;hp=0000000000000000000000000000000000000000;hb=31c28161d36749d040cbab0099b352f53cad232d;hpb=b6de7d24475dec8f5d6b8148a69cf8b561bc0761 diff --git a/source/libovr/libovrcombiner.cpp b/source/libovr/libovrcombiner.cpp new file mode 100644 index 0000000..5eddb4a --- /dev/null +++ b/source/libovr/libovrcombiner.cpp @@ -0,0 +1,176 @@ +#include +#include +#include "libovrcombiner.h" +#include "libovrsystem.h" +#include "libovrsystem_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.pIndexData, ovr_mesh.pIndexData+ovr_mesh.IndexCount)); + mesh.add_batch(batch); + + ovrHmd_DestroyDistortionMesh(&ovr_mesh); +} + +} + +namespace Msp { +namespace VR { + +struct LibOVRCombiner::Frustum: StereoCombiner::Frustum +{ + Frustum(const ovrFovPort &); +}; + + +LibOVRCombiner::LibOVRCombiner(LibOVRSystem &d, GL::View &v): + device(d), + view(v), + 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]; + configure_eye_frustums(Frustum(left_fov), Frustum(right_fov)); + + left_fov.UpTan = left_fov.DownTan = tan(fov/2.0f); + left_fov.LeftTan = left_fov.UpTan*render_aspect*(1-frustum_skew); + left_fov.RightTan = left_fov.UpTan*render_aspect*(1+frustum_skew); + right_fov = left_fov; + swap(right_fov.LeftTan, right_fov.RightTan); + + 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); + target_width = tex_size.w; + target_height = tex_size.h; + + 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); + + device.configure_window(view.get_window()); +} + +void LibOVRCombiner::prepare() const +{ + device.begin_frame(); +} + +void LibOVRCombiner::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(); + + view.get_context().swap_buffers(); + device.end_frame(); +} + + +LibOVRCombiner::Frustum::Frustum(const ovrFovPort &fov): + StereoCombiner::Frustum(-fov.LeftTan, fov.RightTan, -fov.DownTan, fov.UpTan) +{ } + +} // namespace VR +} // namespace Msp