Implement display mirroring in StereoCombiner
authorMikko Rasa <tdb@tdb.fi>
Mon, 26 Sep 2016 11:41:26 +0000 (14:41 +0300)
committerMikko Rasa <tdb@tdb.fi>
Mon, 26 Sep 2016 11:41:26 +0000 (14:41 +0300)
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
source/openvr/openvrcombiner.h
source/openvr/openvrdevice.cpp
source/stereocombiner.cpp
source/stereocombiner.h

index 2272a1a3509dad7b4667b49fb4a6c348d2026078..9bdf4b01a8151755a7f1ca3fa715c6dd96de9045 100644 (file)
@@ -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<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();
+       }
 }
 
 
index ad4a37d8a99758ee8f65e4e120bf282ff613ce75..58a24c9c9f2708eebac8c2f048e7e762ec4dada7 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef MSP_VR_OPENVRCOMBINER_H_
 #define MSP_VR_OPENVRCOMBINER_H_
 
+#include <msp/gl/view.h>
 #include <msp/vr/stereocombiner.h>
 
 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;
index f6f0bf1cf796cd18c1781e26100c9d68bfe601ba..b4ff20b83fb0944b35ed8b5c769d989fb0ee9368 100644 (file)
@@ -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()
index 75c788997e770fa0f1a7340d03b578e969062d51..ebb888ee6fe59ec6bd39446ebff00008b21380e4 100644 (file)
@@ -1,8 +1,31 @@
 #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 {
 
@@ -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
index bef0849b39ee4a460d8c8c838957286f70dc4fa9..2cfe3eb1f5255f30d6104aacd6c1d734700488da 100644 (file)
@@ -2,6 +2,9 @@
 #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 {
@@ -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<float> fov;
        float frustum_skew;
+       MirrorView *mirror;
 
        StereoCombiner();
 public:
@@ -40,8 +53,12 @@ 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