+++ /dev/null
-#include <cmath>
-#include "meshbuilder.h"
-#include "oculusriftcombiner.h"
-#include "texture2d.h"
-
-using namespace std;
-
-namespace {
-
-const char vs_source[] =
- "uniform float offset;\n"
- "uniform vec2 lens_center;\n"
- "uniform vec3 scale;\n"
- "varying vec2 texcoord;\n"
- "void main()\n"
- "{\n"
- " gl_Position = vec4(gl_Vertex.x*0.5+offset, gl_Vertex.yzw);\n"
- " texcoord = (gl_Vertex.xy*0.5+0.5-lens_center)*scale.xy;\n"
- "}\n";
-
-const char fs_source[] =
- "uniform sampler2D texture;\n"
- "uniform vec4 distortion;\n"
- "uniform vec2 eye_center;\n"
- "uniform vec3 scale;\n"
- "varying vec2 texcoord;\n"
- "vec2 distort(vec2 coord)\n"
- "{\n"
- " float r_sq = dot(coord, coord);\n"
- " return coord*dot(distortion, vec4(1.0, r_sq, r_sq*r_sq, r_sq*r_sq*r_sq));\n"
- "}\n"
- "void main()\n"
- "{\n"
- " vec2 dtc = (distort(texcoord)-eye_center)/(scale.xy*scale.z)+0.5;\n"
- " if(dtc.x<0.0 || dtc.y<0.0 || dtc.x>1.0 || dtc.y>1.0)\n"
- " gl_FragColor = vec4(0.0);\n"
- " else\n"
- " gl_FragColor = texture2D(texture, dtc);\n"
- "}\n";
-
-}
-
-namespace Msp {
-namespace GL {
-
-OculusRiftCombiner::OculusRiftCombiner():
- mesh(VERTEX2),
- shprog(vs_source, fs_source),
- // Default values copied from the SDK
- view_distance(0.438f),
- lens_separation(0.424f),
- eye_separation(0.42735f),
- fill_factor(0.95f)
-{
- width_div = 2;
-
- left_shdata.uniform("texture", 0);
- left_shdata.uniform("offset", -0.5f);
- right_shdata.uniform("texture", 0);
- right_shdata.uniform("offset", 0.5f);
-
- // This will also call update_parameters
- set_distortion(1.0f, 0.22f, 0.24f);
-
- MeshBuilder bld(mesh);
- bld.begin(TRIANGLE_STRIP);
- bld.vertex(-1, 1);
- bld.vertex(-1, -1);
- bld.vertex(1, 1);
- bld.vertex(1, -1);
- bld.end();
-}
-
-void OculusRiftCombiner::set_view_distance(float d)
-{
- view_distance = d;
- update_parameters();
-}
-
-void OculusRiftCombiner::set_lens_separation(float s)
-{
- lens_separation = s;
- update_parameters();
-}
-
-void OculusRiftCombiner::set_eye_separation(float s)
-{
- eye_separation = s;
- update_parameters();
-}
-
-void OculusRiftCombiner::set_distortion(float d0, float d1, float d2, float d3)
-{
- distortion[0] = d0;
- distortion[1] = d1;
- distortion[2] = d2;
- distortion[3] = d3;
-
- update_parameters();
-}
-
-void OculusRiftCombiner::set_fill_factor(float f)
-{
- fill_factor = f;
- update_parameters();
-}
-
-void OculusRiftCombiner::update_parameters()
-{
- left_shdata.uniform4("distortion", distortion);
- right_shdata.uniform4("distortion", distortion);
-
- // Set lens center positions, in output texture coordinates
- left_shdata.uniform("lens_center", 1.0f-lens_separation, 0.5);
- right_shdata.uniform("lens_center", lens_separation, 0.5);
-
- /* Compute distance between eye and lens centers, in sampling texture
- coordinates. */
- float eye_offset = distort((eye_separation-lens_separation)*2);
- left_shdata.uniform("eye_center", -eye_offset, 0.0f);
- right_shdata.uniform("eye_center", eye_offset, 0.0f);
-
- /* Determine the necessary scaling factor to avoid quality degradation in
- the center of the screen. */
- float horiz_oversize = distort((fill_factor-lens_separation)*2)-eye_offset;
- float vert_oversize = distort(1.25f*fill_factor)/(1.25f*fill_factor);
- oversize = min(horiz_oversize, vert_oversize);
-
- left_shdata.uniform("scale", 2.0f, 2.5f, oversize);
- right_shdata.uniform("scale", 2.0f, 2.5f, oversize);
-
- fov = Geometry::atan(oversize*0.625f/view_distance)*2.0f;
-}
-
-float OculusRiftCombiner::distort(float r) const
-{
- float r_sq = r*r;
- return r*(distortion[0]+(distortion[1]+(distortion[2]+distortion[3]*r_sq)*r_sq)*r_sq);
-}
-
-float OculusRiftCombiner::undistort(float r) const
-{
- float x = r;
- while(1)
- {
- float y = distort(x);
- if(abs(r-y)<1e-5)
- return x;
-
- float x_sq = x*x;
- float d = distortion[0]+(3*distortion[1]+(5*distortion[2]+7*distortion[3]*x_sq)*x_sq)*x_sq;
- x -= (y-r)/d;
- }
-}
-
-void OculusRiftCombiner::render(const Texture2D &left, const Texture2D &right) const
-{
- Bind bind_shprog(shprog);
-
- Bind bind_tex(left);
- left_shdata.apply();
- mesh.draw();
-
- right.bind();
- right_shdata.apply();
- mesh.draw();
-}
-
-} // namespace GL
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_GL_OCULUSRIFTCOMBINER_H_
-#define MSP_GL_OCULUSRIFTCOMBINER_H_
-
-#include "mesh.h"
-#include "program.h"
-#include "programdata.h"
-#include "stereocombiner.h"
-
-namespace Msp {
-namespace GL {
-
-/**
-Presents a stereo view in a way suitable for an Oculus Rift HMD. All distances
-are specified in multiples of the screen width.
-*/
-class OculusRiftCombiner: public StereoCombiner
-{
-private:
- Mesh mesh;
- Program shprog;
- ProgramData left_shdata;
- ProgramData right_shdata;
- float view_distance;
- float lens_separation;
- float eye_separation;
- float distortion[4];
- float fill_factor;
-
-public:
- OculusRiftCombiner();
-
- void set_view_distance(float);
- void set_lens_separation(float);
- void set_eye_separation(float);
- void set_distortion(float = 1.0f, float = 0.0f, float = 0.0f, float = 0.0f);
- void set_fill_factor(float);
-private:
- void update_parameters();
-
- float distort(float) const;
- float undistort(float) const;
-
-public:
- virtual void render(const Texture2D &, const Texture2D &) const;
-};
-
-} // namespace GL
-} // namespace Msp
-
-#endif
+++ /dev/null
-#include "meshbuilder.h"
-#include "sidebysidecombiner.h"
-#include "texture2d.h"
-
-namespace {
-
-const char vs_source[] =
- "uniform float offset;\n"
- "varying vec2 texcoord;\n"
- "void main()\n"
- "{\n"
- " gl_Position = vec4(gl_Vertex.x*0.5+offset, gl_Vertex.yzw);\n"
- " texcoord = gl_Vertex.xy*0.5+0.5;\n"
- "}\n";
-
-const char fs_source[] =
- "uniform sampler2D texture;\n"
- "varying vec2 texcoord;\n"
- "void main()\n"
- "{\n"
- " gl_FragColor = texture2D(texture, texcoord);\n"
- "}\n";
-
-}
-
-namespace Msp {
-namespace GL {
-
-SideBySideCombiner::SideBySideCombiner(bool c):
- mesh(VERTEX2),
- shprog(vs_source, fs_source)
-{
- width_div = 2;
-
- left_shdata.uniform("texture", 0);
- right_shdata.uniform("texture", 0);
-
- set_cross_eyed(c);
-
- MeshBuilder bld(mesh);
- bld.begin(TRIANGLE_STRIP);
- bld.vertex(-1, 1);
- bld.vertex(-1, -1);
- bld.vertex(1, 1);
- bld.vertex(1, -1);
- bld.end();
-}
-
-void SideBySideCombiner::set_cross_eyed(bool c)
-{
- cross_eyed = c;
- float m = (cross_eyed ? -0.5f : 0.5f);
- left_shdata.uniform("offset", -m);
- right_shdata.uniform("offset", m);
-}
-
-void SideBySideCombiner::render(const Texture2D &left, const Texture2D &right) const
-{
- Bind bind_shprog(shprog);
-
- Bind bind_tex(left);
- left_shdata.apply();
- mesh.draw();
-
- right.bind();
- right_shdata.apply();
- mesh.draw();
-}
-
-} // namespace GL
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_GL_SIDEBYSIDECOMBINER_H_
-#define MSP_GL_SIDEBYSIDECOMBINER_H_
-
-#include "mesh.h"
-#include "program.h"
-#include "programdata.h"
-#include "stereocombiner.h"
-
-namespace Msp {
-namespace GL {
-
-class SideBySideCombiner: public StereoCombiner
-{
-private:
- Mesh mesh;
- Program shprog;
- ProgramData left_shdata;
- ProgramData right_shdata;
- bool cross_eyed;
-
-public:
- SideBySideCombiner(bool = false);
-
- void set_cross_eyed(bool);
-
- virtual void render(const Texture2D &, const Texture2D &) const;
-};
-
-} // namespace GL
-} // namespace Msp
-
-#endif
+++ /dev/null
-#include "stereocombiner.h"
-
-namespace Msp {
-namespace GL {
-
-StereoCombiner::StereoCombiner():
- width_div(1),
- height_div(1),
- keep_aspect(false),
- oversize(1.0f)
-{ }
-
-} // namespace GL
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_GL_STEREOCOMBINER_H_
-#define MSP_GL_STEREOCOMBINER_H_
-
-#include <msp/geometry/angle.h>
-
-namespace Msp {
-namespace GL {
-
-class Texture2D;
-
-class StereoCombiner
-{
-protected:
- unsigned width_div;
- unsigned height_div;
- bool keep_aspect;
- Geometry::Angle<float> fov;
- float oversize;
-
- StereoCombiner();
-public:
- virtual ~StereoCombiner() { }
-
- unsigned get_width_divisor() const { return width_div; }
- unsigned get_height_divisor() const { return height_div; }
- bool is_aspect_kept() const { return keep_aspect; }
- const Geometry::Angle<float> &get_field_of_view() const { return fov; }
- float get_oversize() const { return oversize; }
-
- virtual void render(const Texture2D &, const Texture2D &) const = 0;
-};
-
-} // namespace GL
-} // namespace Msp
-
-#endif
+++ /dev/null
-#include "renderer.h"
-#include "stereocombiner.h"
-#include "stereoview.h"
-
-using namespace std;
-
-namespace Msp {
-namespace GL {
-
-StereoView::StereoView(unsigned w, unsigned h, const Camera &c, const Renderable &r, const StereoCombiner &m):
- width(w),
- height(h),
- base_camera(c),
- renderable(r),
- combiner(0)
-{
- set_combiner(m);
- set_eye_spacing(0.07);
-}
-
-void StereoView::set_combiner(const StereoCombiner &c)
-{
- combiner = &c;
-
- unsigned w = width/combiner->get_width_divisor()*combiner->get_oversize();
- unsigned h = height/combiner->get_height_divisor()*combiner->get_oversize();
- left.create_target(w, h);
- right.create_target(w, h);
-}
-
-void StereoView::set_eye_spacing(float s)
-{
- eye_spacing = s;
-}
-
-void StereoView::setup_frame() const
-{
- offset_axis = normalize(cross(base_camera.get_look_direction(), base_camera.get_up_direction()))*0.5f;
-
- EyeParams params;
- params.fov = combiner->get_field_of_view();
- if(params.fov==Geometry::Angle<float>::zero())
- params.fov = base_camera.get_field_of_view();
-
- params.aspect = base_camera.get_aspect();
- if(!combiner->is_aspect_kept())
- params.aspect = params.aspect*combiner->get_height_divisor()/combiner->get_width_divisor();
-
- params.near_clip = base_camera.get_near_clip();
- params.far_clip = base_camera.get_far_clip();
-
- left.setup_frame(base_camera, offset_axis*-eye_spacing, params);
- right.setup_frame(base_camera, offset_axis*eye_spacing, params);
-
- renderable.setup_frame();
-}
-
-void StereoView::finish_frame() const
-{
- renderable.finish_frame();
-}
-
-void StereoView::render(const Tag &tag) const
-{
- setup_frame();
- left.render(renderable, tag);
- right.render(renderable, tag);
- combiner->render(left.target->color, right.target->color);
- finish_frame();
-}
-
-void StereoView::render(Renderer &renderer, const Tag &tag) const
-{
- renderer.escape();
- return render(tag);
-}
-
-
-StereoView::RenderTarget::RenderTarget(unsigned width, unsigned height)
-{
- color.set_min_filter(LINEAR);
- color.set_wrap(CLAMP_TO_EDGE);
- color.storage(RGB, width, height);
- fbo.attach(COLOR_ATTACHMENT0, color);
-
- depth.storage(DEPTH_COMPONENT, width, height);
- fbo.attach(DEPTH_ATTACHMENT, depth);
-}
-
-
-StereoView::Eye::Eye():
- target(0)
-{ }
-
-void StereoView::Eye::create_target(unsigned w, unsigned h)
-{
- delete target;
- target = new RenderTarget(w, h);
-}
-
-void StereoView::Eye::setup_frame(const Camera &base_camera, const Vector3 &offset, const EyeParams ¶ms) const
-{
- camera.set_position(base_camera.get_position()+offset);
- camera.set_up_direction(base_camera.get_up_direction());
- camera.set_look_direction(base_camera.get_look_direction());
-
- camera.set_field_of_view(params.fov);
- camera.set_aspect(params.aspect);
- camera.set_depth_clip(params.near_clip, params.far_clip);
-}
-
-void StereoView::Eye::render(const Renderable &renderable, const Tag &tag) const
-{
- Bind bind_fbo(target->fbo);
- Renderer renderer(&camera);
- renderable.render(renderer, tag);
-}
-
-} // namespace GL
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_GL_STEREOVIEW_H_
-#define MSP_GL_STEREOVIEW_H_
-
-#include <msp/geometry/angle.h>
-#include "camera.h"
-#include "framebuffer.h"
-#include "renderable.h"
-#include "renderbuffer.h"
-#include "texture2d.h"
-
-namespace Msp {
-namespace GL {
-
-class StereoCombiner;
-
-class StereoView: public Renderable
-{
-private:
- struct RenderTarget
- {
- Framebuffer fbo;
- Texture2D color;
- Renderbuffer depth;
-
- RenderTarget(unsigned, unsigned);
- };
-
- struct EyeParams
- {
- Geometry::Angle<float> fov;
- float aspect;
- float near_clip;
- float far_clip;
- };
-
- struct Eye
- {
- mutable Camera camera;
- RenderTarget *target;
-
- Eye();
-
- void create_target(unsigned, unsigned);
- void setup_frame(const Camera &, const Vector3 &, const EyeParams &) const;
- void render(const Renderable &, const Tag &) const;
- };
-
- unsigned width;
- unsigned height;
- const Camera &base_camera;
- const Renderable &renderable;
- const StereoCombiner *combiner;
- Eye left;
- Eye right;
- float eye_spacing;
- mutable Vector3 offset_axis;
-
-public:
- StereoView(unsigned, unsigned, const Camera &, const Renderable &, const StereoCombiner &);
-
- void set_combiner(const StereoCombiner &);
- void set_eye_spacing(float);
-
- virtual void setup_frame() const;
- virtual void finish_frame() const;
-
- virtual void render(const Tag & = Tag()) const;
- virtual void render(Renderer &, const Tag & = Tag()) const;
-};
-
-} // namespace GL
-} // namespace Msp
-
-#endif