From c07c707c480f4e989caee17541187f08f136d216 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Mon, 26 Sep 2016 14:41:26 +0300 Subject: [PATCH] Implement display mirroring in StereoCombiner It's up to individual combiners to use it. Currently OpenVRCombiner is the only one to support it, since the others render directly to the application window. --- source/openvr/openvrcombiner.cpp | 14 ++++++- source/openvr/openvrcombiner.h | 4 +- source/openvr/openvrdevice.cpp | 4 +- source/stereocombiner.cpp | 64 +++++++++++++++++++++++++++++++- source/stereocombiner.h | 17 +++++++++ 5 files changed, 97 insertions(+), 6 deletions(-) diff --git a/source/openvr/openvrcombiner.cpp b/source/openvr/openvrcombiner.cpp index 2272a1a..9bdf4b0 100644 --- a/source/openvr/openvrcombiner.cpp +++ b/source/openvr/openvrcombiner.cpp @@ -11,8 +11,9 @@ struct OpenVRCombiner::Private }; -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; @@ -23,6 +24,8 @@ OpenVRCombiner::OpenVRCombiner(OpenVRDevice &d): 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 @@ -41,6 +44,13 @@ void OpenVRCombiner::render(const GL::Texture2D &left, const GL::Texture2D &righ compositor->Submit(vr::Eye_Left, &tex); tex.handle = reinterpret_cast(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(); + } } diff --git a/source/openvr/openvrcombiner.h b/source/openvr/openvrcombiner.h index ad4a37d..58a24c9 100644 --- a/source/openvr/openvrcombiner.h +++ b/source/openvr/openvrcombiner.h @@ -1,6 +1,7 @@ #ifndef MSP_VR_OPENVRCOMBINER_H_ #define MSP_VR_OPENVRCOMBINER_H_ +#include #include namespace Msp { @@ -14,9 +15,10 @@ private: 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; diff --git a/source/openvr/openvrdevice.cpp b/source/openvr/openvrdevice.cpp index f6f0bf1..b4ff20b 100644 --- a/source/openvr/openvrdevice.cpp +++ b/source/openvr/openvrdevice.cpp @@ -74,9 +74,9 @@ OpenVRCamera *OpenVRDevice::create_camera(const GL::Camera &bc) 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() diff --git a/source/stereocombiner.cpp b/source/stereocombiner.cpp index 75c7889..ebb888e 100644 --- a/source/stereocombiner.cpp +++ b/source/stereocombiner.cpp @@ -1,8 +1,31 @@ #include +#include #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 { @@ -10,7 +33,8 @@ StereoCombiner::StereoCombiner(): 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) @@ -25,6 +49,28 @@ void StereoCombiner::configure_eye_frustums(const Frustum &left_frustum, const F 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), @@ -40,5 +86,21 @@ StereoCombiner::Frustum::Frustum(float l, float r, float b, float t): 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 diff --git a/source/stereocombiner.h b/source/stereocombiner.h index bef0849..2cfe3eb 100644 --- a/source/stereocombiner.h +++ b/source/stereocombiner.h @@ -2,6 +2,9 @@ #define MSP_VR_STEREOCOMBINER_H_ #include +#include +#include +#include #include namespace Msp { @@ -21,11 +24,21 @@ protected: 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 fov; float frustum_skew; + MirrorView *mirror; StereoCombiner(); public: @@ -40,8 +53,12 @@ public: const Geometry::Angle &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 -- 2.45.2