};
-OpenVRCombiner::OpenVRCombiner(OpenVRDevice &d):
- device(d)
+OpenVRCombiner::OpenVRCombiner(OpenVRDevice &d, GL::View &v):
+ device(d),
+ view(v)
{
vr::IVRSystem *vr_sys = vr::VRSystem();
uint32_t w, h;
Frustum left_frustum = Private::get_projection(vr::Eye_Left);
Frustum right_frustum = Private::get_projection(vr::Eye_Right);
configure_eye_frustums(left_frustum, right_frustum);
+
+ set_mirroring(true);
}
void OpenVRCombiner::prepare() const
compositor->Submit(vr::Eye_Left, &tex);
tex.handle = reinterpret_cast<void *>(right.get_id());
compositor->Submit(vr::Eye_Right, &tex);
+
+ if(mirror)
+ {
+ mirror->shdata.uniform("scale", view.get_aspect()/render_aspect/2, 0.5f);
+ render_mirror(left);
+ view.get_context().swap_buffers();
+ }
}
#ifndef MSP_VR_OPENVRCOMBINER_H_
#define MSP_VR_OPENVRCOMBINER_H_
+#include <msp/gl/view.h>
#include <msp/vr/stereocombiner.h>
namespace Msp {
struct Private;
OpenVRDevice &device;
+ GL::View &view;
public:
- OpenVRCombiner(OpenVRDevice &);
+ OpenVRCombiner(OpenVRDevice &, GL::View &);
virtual void prepare() const;
virtual void render(const GL::Texture2D &, const GL::Texture2D &) const;
return new OpenVRCamera(*this, bc);
}
-OpenVRCombiner *OpenVRDevice::create_combiner(GL::View &)
+OpenVRCombiner *OpenVRDevice::create_combiner(GL::View &v)
{
- return new OpenVRCombiner(*this);
+ return new OpenVRCombiner(*this, v);
}
void OpenVRDevice::update_pose_matrices()
#include <algorithm>
+#include <msp/gl/meshbuilder.h>
#include "stereocombiner.h"
using namespace std;
+namespace {
+
+const char mirror_vs_source[] =
+ "uniform vec2 scale;\n"
+ "varying vec2 texcoord;\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = vec4(gl_Vertex.xy, 0.0, 1.0);\n"
+ " texcoord = gl_Vertex.xy*scale*0.5+0.5;\n"
+ "}";
+
+const char mirror_fs_source[] =
+ "uniform sampler2D texture;\n"
+ "varying vec2 texcoord;\n"
+ "void main()\n"
+ "{\n"
+ " gl_FragColor = texture2D(texture, texcoord);\n"
+ "}";
+
+}
+
+
namespace Msp {
namespace VR {
target_width(0),
target_height(0),
render_aspect(1.0f),
- frustum_skew(0.0f)
+ frustum_skew(0.0f),
+ mirror(0)
{ }
void StereoCombiner::configure_eye_frustums(const Frustum &left_frustum, const Frustum &right_frustum)
render_aspect = (inner+outer)/(vertical*2);
}
+void StereoCombiner::set_mirroring(bool m)
+{
+ if(m && !mirror)
+ mirror = new MirrorView;
+ else if(!m && mirror)
+ {
+ delete mirror;
+ mirror = 0;
+ }
+}
+
+void StereoCombiner::render_mirror(const GL::Texture2D &tex) const
+{
+ if(!mirror)
+ return;
+
+ GL::Bind bind_tex(tex);
+ GL::Bind bind_shprog(mirror->shader);
+ mirror->shdata.apply();
+ mirror->mesh.draw();
+}
+
StereoCombiner::Frustum::Frustum():
left(-1),
top(t)
{ }
+
+StereoCombiner::MirrorView::MirrorView():
+ mesh(GL::VERTEX2),
+ shader(mirror_vs_source, mirror_fs_source)
+{
+ GL::MeshBuilder bld(mesh);
+ bld.begin(GL::TRIANGLE_STRIP);
+ bld.vertex(-1, 1);
+ bld.vertex(-1, -1);
+ bld.vertex(1, 1);
+ bld.vertex(1, -1);
+ bld.end();
+
+ shdata.uniform("scale", 0.5f, 0.5f);
+}
+
} // namespace VR
} // namespace Msp
#define MSP_VR_STEREOCOMBINER_H_
#include <msp/geometry/angle.h>
+#include <msp/gl/mesh.h>
+#include <msp/gl/program.h>
+#include <msp/gl/programdata.h>
#include <msp/gl/texture2d.h>
namespace Msp {
Frustum(float, float, float, float);
};
+ struct MirrorView
+ {
+ GL::Mesh mesh;
+ GL::Program shader;
+ GL::ProgramData shdata;
+
+ MirrorView();
+ };
+
unsigned target_width;
unsigned target_height;
float render_aspect;
Geometry::Angle<float> fov;
float frustum_skew;
+ MirrorView *mirror;
StereoCombiner();
public:
const Geometry::Angle<float> &get_field_of_view() const { return fov; }
float get_frustum_skew() const { return frustum_skew; }
+ void set_mirroring(bool);
+
virtual void prepare() const { }
virtual void render(const GL::Texture2D &, const GL::Texture2D &) const = 0;
+protected:
+ void render_mirror(const GL::Texture2D &) const;
};
} // namespace VR