Make the StereoCombiner information interface more flexible
[libs/vr.git] / source / oculusriftcombiner.cpp
1 #include <cmath>
2 #include <msp/gl/meshbuilder.h>
3 #include <msp/gl/texture2d.h>
4 #include "oculusriftcombiner.h"
5 #include "oculusriftdevice.h"
6 #include "oculusriftdevice_private.h"
7
8 using namespace std;
9
10
11 namespace {
12
13 const char vs_source[] =
14         "varying vec2 texcoord_r;\n"
15         "varying vec2 texcoord_g;\n"
16         "varying vec2 texcoord_b;\n"
17         "void main()\n"
18         "{\n"
19         "       gl_Position = vec4(gl_Vertex.xy, 0.5, 1.0);\n"
20         "       texcoord_r = gl_MultiTexCoord0.xy;\n"
21         "       texcoord_g = gl_MultiTexCoord1.xy;\n"
22         "       texcoord_b = gl_MultiTexCoord2.xy;\n"
23         "}\n";
24
25 const char fs_source[] =
26         "uniform sampler2D texture;\n"
27         "varying vec2 texcoord_r;\n"
28         "varying vec2 texcoord_g;\n"
29         "varying vec2 texcoord_b;\n"
30         "void main()\n"
31         "{\n"
32         "       float r = texture2D(texture, texcoord_r).r;\n"
33         "       float g = texture2D(texture, texcoord_g).g;\n"
34         "       float b = texture2D(texture, texcoord_b).b;\n"
35         "       gl_FragColor = vec4(r, g, b, 1.0);\n"
36         "}\n";
37
38 void create_distortion_mesh(Msp::GL::Mesh &mesh, ovrHmd hmd, ovrEyeType eye, const ovrFovPort &fov)
39 {
40         ovrDistortionMesh ovr_mesh;
41         ovrHmd_CreateDistortionMesh(hmd, eye, fov, ovrDistortionCap_Chromatic, &ovr_mesh);
42
43         ovrSizei tex_size = ovrHmd_GetFovTextureSize(hmd, eye, fov, 1.0);
44         ovrRecti view_rect;
45         view_rect.Pos.x = 0;
46         view_rect.Pos.y = 0;
47         view_rect.Size = tex_size;
48         ovrVector2f uv_scale_offset[2];
49         ovrHmd_GetRenderScaleAndOffset(fov, tex_size, view_rect, uv_scale_offset);
50         ovrVector2f &scale = uv_scale_offset[0];
51         ovrVector2f &offset = uv_scale_offset[1];
52
53         Msp::GL::MeshBuilder bld(mesh);
54         for(unsigned i=0; i<ovr_mesh.VertexCount; ++i)
55         {
56                 ovrDistortionVertex &v = ovr_mesh.pVertexData[i];
57                 bld.multitexcoord(0, v.TanEyeAnglesR.x*scale.x+offset.x, 1.0f-(v.TanEyeAnglesR.y*scale.y+offset.y));
58                 bld.multitexcoord(1, v.TanEyeAnglesG.x*scale.x+offset.x, 1.0f-(v.TanEyeAnglesG.y*scale.y+offset.y));
59                 bld.multitexcoord(2, v.TanEyeAnglesB.x*scale.x+offset.x, 1.0f-(v.TanEyeAnglesB.y*scale.y+offset.y));
60                 bld.vertex(v.ScreenPosNDC.x, v.ScreenPosNDC.y);
61         }
62
63         Msp::GL::Batch batch(Msp::GL::TRIANGLES);
64         batch.append(vector<unsigned>(ovr_mesh.pIndexData, ovr_mesh.pIndexData+ovr_mesh.IndexCount));
65         mesh.add_batch(batch);
66
67         ovrHmd_DestroyDistortionMesh(&ovr_mesh);
68 }
69
70 }
71
72 namespace Msp {
73 namespace VR {
74
75 OculusRiftCombiner::OculusRiftCombiner(const OculusRiftDevice &d):
76         device(d),
77         left_mesh((GL::VERTEX2, GL::TEXCOORD2,0, GL::TEXCOORD2,1, GL::TEXCOORD2,2)),
78         right_mesh((GL::VERTEX2, GL::TEXCOORD2,0, GL::TEXCOORD2,1, GL::TEXCOORD2,2)),
79         shprog(vs_source, fs_source)
80 {
81         const OculusRiftDevice::Private &dev_priv = device.get_private();
82         ovrHmd hmd = dev_priv.ovr_hmd;
83
84         ovrFovPort left_fov = hmd->DefaultEyeFov[ovrEye_Left];
85         ovrFovPort right_fov = hmd->DefaultEyeFov[ovrEye_Right];
86         float vertical = max(max(left_fov.UpTan, left_fov.DownTan), max(right_fov.UpTan, right_fov.DownTan));
87         fov = Geometry::atan<float>(vertical)*2.0f;
88
89         float inner = max(left_fov.RightTan, right_fov.LeftTan);
90         float outer = max(left_fov.LeftTan, right_fov.RightTan);
91         frustum_skew = (inner-outer)*2/(inner+outer);
92
93         left_fov.UpTan = right_fov.UpTan = vertical;
94         left_fov.DownTan = right_fov.DownTan = vertical;
95         left_fov.RightTan = right_fov.LeftTan = inner;
96         left_fov.LeftTan = right_fov.RightTan = outer;
97
98         create_distortion_mesh(left_mesh, hmd, ovrEye_Left, left_fov);
99         create_distortion_mesh(right_mesh, hmd, ovrEye_Right, right_fov);
100
101         ovrSizei tex_size = ovrHmd_GetFovTextureSize(hmd, ovrEye_Left, left_fov, 1.0);
102         width_factor = tex_size.w*1.0f/hmd->Resolution.w;
103         height_factor = tex_size.h*1.0f/hmd->Resolution.h;
104         float aspect = (inner+outer)/(vertical*2);
105         aspect_factor = aspect*hmd->Resolution.h/hmd->Resolution.w;
106
107         shdata.uniform("texture", 0);
108
109 }
110
111 void OculusRiftCombiner::render(const GL::Texture2D &left, const GL::Texture2D &right) const
112 {
113         GL::Bind bind_shprog(shprog);
114         shdata.apply();
115
116         GL::Bind bind_tex(left);
117         left_mesh.draw();
118
119         right.bind();
120         right_mesh.draw();
121 }
122
123 } // namespace VR
124 } // namespace Msp