summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Eilemann <eilemann@gmail.com>2010-12-01 21:32:22 +0100
committerMartin Lambers <marlam@marlam.de>2010-12-01 21:32:22 +0100
commit8832aa87a0fb8b2e0428fade3e116ee42f90d985 (patch)
tree6d12540749b05406643b969a131d7383d2b61b21
parent4e87aef9d7840d2b387e7efd932908a33057bd84 (diff)
downloadbino-8832aa87a0fb8b2e0428fade3e116ee42f90d985.tar.gz
Equalizer: Add an additional 3D output mode.
The new ouput mode 'equalizer-3d' allows to configure non-planar projections.
-rw-r--r--doc/bino.14
-rw-r--r--doc/multi-display.txt8
-rw-r--r--src/main.cpp19
-rw-r--r--src/player_equalizer.cpp174
-rw-r--r--src/player_equalizer.h24
5 files changed, 190 insertions, 39 deletions
diff --git a/doc/bino.1 b/doc/bino.1
index e1b8712..d2131da 100644
--- a/doc/bino.1
+++ b/doc/bino.1
@@ -82,7 +82,9 @@ Select output type:
.br
\fIstereo\fP (OpenGL quad\-buffer stereo),
.br
-\fIequalizer\fP (multi-display OpenGL via Equalizer).
+\fIequalizer\fP (multi-display OpenGL via Equalizer with a 2D canvas setup),
+.br
+\fIequalizer\-3d\fP (multi-display OpenGL via Equalizer with a 3D screen setup).
.br
For stereo input, the default is \fIstereo\fP if the display supports it,
otherwise \fIanaglyph\fP. The default for mono input is \fImono\-left\fP.
diff --git a/doc/multi-display.txt b/doc/multi-display.txt
index 3d3e27b..8cb4e2f 100644
--- a/doc/multi-display.txt
+++ b/doc/multi-display.txt
@@ -59,11 +59,19 @@ using ffserver (part of ffmpeg) or vlc, and then give the appropriate URL to
Bino. You can use multicast to stream the video to multiple systems
efficiently.
+The ouput mode '-o equalizer-3d' allows to configure non-planar projections.
+Bino projects the video onto a virtual screen in 3D space. The screen is
+located in the distance of the biggest front-facing segment, and sized to fill
+the wall optimally. By configuring the output segments accordingly, various
+advanced display configurations can be used, e.g. displays rotated around the
+Z axis by an arbitrary angle or non-planar screens.
+
Example Configurations
======================
1. Simple 2D video output
+-------------------------
In this example, you have a 2m x 1m screen and two projectors: one for the
left half of the screen, and one for the right half. The two projectors are
diff --git a/src/main.cpp b/src/main.cpp
index 5142636..c271d81 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,7 +1,9 @@
/*
* This file is part of bino, a program to play stereoscopic videos.
*
- * Copyright (C) 2010 Martin Lambers <marlam@marlam.de>
+ * Copyright (C) 2010
+ * Martin Lambers <marlam@marlam.de>
+ * Stefan Eilemann <eile@eyescale.ch>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -86,6 +88,7 @@ int main(int argc, char *argv[])
video_output_modes.push_back("anaglyph-dubois");
video_output_modes.push_back("stereo");
video_output_modes.push_back("equalizer");
+ video_output_modes.push_back("equalizer-3d");
opt::val<std::string> video_output_mode("output", 'o', opt::optional, video_output_modes, "");
options.push_back(&video_output_mode);
opt::flag fullscreen("fullscreen", 'f', opt::optional);
@@ -163,7 +166,8 @@ int main(int argc, char *argv[])
" anaglyph-half-color Red/cyan anaglyph, half color method\n"
" anaglyph-dubois Red/cyan anaglyph, Dubois method\n"
" stereo OpenGL quad-buffered stereo\n"
- " equalizer Multi-display OpenGL using Equalizer\n"
+ " equalizer Multi-display OpenGL via Equalizer (2D setup)\n"
+ " equalizer-3d Multi-display OpenGL via Equalizer (3D setup)\n"
" -f|--fullscreen Fullscreen\n"
" -c|--center Center window on screen\n"
" -s|--swap-eyes Swap left/right view\n"
@@ -193,7 +197,7 @@ int main(int argc, char *argv[])
{
try
{
- player_equalizer *player = new player_equalizer(&argc, argv);
+ player_equalizer *player = new player_equalizer(&argc, argv, true);
delete player;
}
catch (std::exception &e)
@@ -206,6 +210,7 @@ int main(int argc, char *argv[])
#endif
bool equalizer = false;
+ bool equalizer_flat_screen = true;
player_init_data init_data;
init_data.log_level = msg::level();
if (log_level.value() == "debug")
@@ -248,6 +253,12 @@ int main(int argc, char *argv[])
equalizer = true;
init_data.video_mode = video_output::mono_left;
}
+ else if (video_output_mode.value() == "equalizer-3d")
+ {
+ equalizer = true;
+ equalizer_flat_screen = false;
+ init_data.video_mode = video_output::mono_left;
+ }
else if (video_output_mode.value() == "")
{
init_data.video_mode = video_output::automatic;
@@ -276,7 +287,7 @@ int main(int argc, char *argv[])
if (equalizer)
{
#if HAVE_LIBEQUALIZER
- player = new class player_equalizer(&argc, argv);
+ player = new class player_equalizer(&argc, argv, equalizer_flat_screen);
#else
throw exc("this version of Bino was compiled without support for Equalizer");
#endif
diff --git a/src/player_equalizer.cpp b/src/player_equalizer.cpp
index e1a3d7f..7ad946d 100644
--- a/src/player_equalizer.cpp
+++ b/src/player_equalizer.cpp
@@ -1,8 +1,31 @@
+/*
+ * This file is part of bino, a program to play stereoscopic videos.
+ *
+ * Copyright (C) 2010
+ * Martin Lambers <marlam@marlam.de>
+ * Stefan Eilemann <eile@eyescale.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
#include "config.h"
#include <sstream>
+#include <cmath>
#include <eq/eq.h>
+#include <eq/client/segment.h> // FIXME: Remove this when switching to a newer Equalizer version
#include "debug.h"
#include "msg.h"
@@ -180,14 +203,17 @@ class eq_init_data : public eq::net::Object
public:
uint32_t frame_data_id;
player_init_data init_data;
- struct { float x, y, w, h; } canvas_video_area;
+ bool flat_screen;
+ struct { float x, y, w, h, d; } canvas_video_area;
eq_init_data() : frame_data_id(EQ_ID_INVALID), init_data()
{
+ flat_screen = true;
canvas_video_area.x = 0.0f;
canvas_video_area.y = 0.0f;
canvas_video_area.w = 1.0f;
canvas_video_area.h = 1.0f;
+ canvas_video_area.d = 1.0f;
}
~eq_init_data()
@@ -216,10 +242,12 @@ protected:
s11n::save(oss, init_data.video_state.fullscreen);
s11n::save(oss, init_data.video_state.swap_eyes);
s11n::save(oss, init_data.video_flags);
+ s11n::save(oss, flat_screen);
s11n::save(oss, canvas_video_area.x);
s11n::save(oss, canvas_video_area.y);
s11n::save(oss, canvas_video_area.w);
s11n::save(oss, canvas_video_area.h);
+ s11n::save(oss, canvas_video_area.d);
os << oss.str();
}
@@ -244,10 +272,12 @@ protected:
s11n::load(iss, init_data.video_state.fullscreen);
s11n::load(iss, init_data.video_state.swap_eyes);
s11n::load(iss, init_data.video_flags);
+ s11n::load(iss, flat_screen);
s11n::load(iss, canvas_video_area.x);
s11n::load(iss, canvas_video_area.y);
s11n::load(iss, canvas_video_area.w);
s11n::load(iss, canvas_video_area.h);
+ s11n::load(iss, canvas_video_area.d);
}
};
@@ -344,7 +374,7 @@ public:
return _is_master_config;
}
- bool init(const player_init_data &init_data)
+ bool init(const player_init_data &init_data, bool flat_screen)
{
msg::set_level(init_data.log_level);
msg::dbg(HERE);
@@ -352,6 +382,7 @@ public:
_is_master_config = true;
// Initialize master init/frame data instances
_eq_init_data.init_data = init_data;
+ _eq_init_data.flat_screen = flat_screen;
_eq_frame_data.video_state = _eq_init_data.init_data.video_state;
// Initialize master player
_player.eq_make_master();
@@ -370,23 +401,36 @@ public:
float canvas_aspect_ratio = canvas_w / canvas_h;
_eq_init_data.canvas_video_area.w = 1.0f;
_eq_init_data.canvas_video_area.h = 1.0f;
- if (src_aspect_ratio > canvas_aspect_ratio)
+
+ if (flat_screen)
{
- // need black borders top and bottom
- _eq_init_data.canvas_video_area.h = canvas_aspect_ratio / src_aspect_ratio;
+ if (src_aspect_ratio > canvas_aspect_ratio)
+ {
+ // need black borders top and bottom
+ _eq_init_data.canvas_video_area.h = canvas_aspect_ratio / src_aspect_ratio;
+ }
+ else
+ {
+ // need black borders left and right
+ _eq_init_data.canvas_video_area.w = src_aspect_ratio / canvas_aspect_ratio;
+ }
+ _eq_init_data.canvas_video_area.x = (1.0f - _eq_init_data.canvas_video_area.w) / 2.0f;
+ _eq_init_data.canvas_video_area.y = (1.0f - _eq_init_data.canvas_video_area.h) / 2.0f;
}
else
{
- // need black borders left and right
- _eq_init_data.canvas_video_area.w = src_aspect_ratio / canvas_aspect_ratio;
+ compute_3d_canvas(&_eq_init_data.canvas_video_area.h, &_eq_init_data.canvas_video_area.d);
+ // compute width and offset for 1m high 'screen' quad in 3D space
+ _eq_init_data.canvas_video_area.w = _eq_init_data.canvas_video_area.h * src_aspect_ratio;
+ _eq_init_data.canvas_video_area.x = -0.5f * _eq_init_data.canvas_video_area.w;
+ _eq_init_data.canvas_video_area.y = -0.5f * _eq_init_data.canvas_video_area.h;
}
- _eq_init_data.canvas_video_area.x = (1.0f - _eq_init_data.canvas_video_area.w) / 2.0f;
- _eq_init_data.canvas_video_area.y = (1.0f - _eq_init_data.canvas_video_area.h) / 2.0f;
msg::inf("equalizer canvas:");
msg::inf(" %gx%g, aspect ratio %g:1", canvas_w, canvas_h, canvas_w / canvas_h);
- msg::inf(" area for %g:1 video: [ %g %g %g %g ]", src_aspect_ratio,
+ msg::inf(" area for %g:1 video: [ %g %g %g %g @ %g ]", src_aspect_ratio,
_eq_init_data.canvas_video_area.x, _eq_init_data.canvas_video_area.y,
- _eq_init_data.canvas_video_area.w, _eq_init_data.canvas_video_area.h);
+ _eq_init_data.canvas_video_area.w, _eq_init_data.canvas_video_area.h,
+ _eq_init_data.canvas_video_area.d);
// Register master instances
registerObject(&_eq_frame_data);
_eq_init_data.frame_data_id = _eq_frame_data.getID();
@@ -504,6 +548,65 @@ public:
{
return &_player;
}
+
+private:
+ void compute_3d_canvas(float *height, float *distance)
+ {
+ float angle = -1.0f;
+ *height = 0.0f;
+ *distance = 0.0f;
+
+ const eq::CanvasVector &canvases = getCanvases();
+ for (eq::CanvasVector::const_iterator i = canvases.begin(); i != canvases.end(); i++)
+ {
+ const eq::SegmentVector &segments = (*i)->getSegments();
+ for (eq::SegmentVector::const_iterator j = segments.begin(); j != segments.end(); j++)
+ {
+ const eq::Segment *segment = *j;
+ eq::Wall wall = segment->getWall();
+ const eq::Vector3f u = wall.bottomRight - wall.bottomLeft;
+ const eq::Vector3f v = wall.topLeft - wall.bottomLeft;
+ eq::Vector3f w = u.cross(v);
+ w.normalize();
+
+ const eq::Vector3f dot = w.dot(eq::Vector3f::FORWARD);
+ const float val = dot.squared_length();
+ if (val < angle) // facing more away then previous segment
+ {
+ continue;
+ }
+
+ // transform wall to full canvas
+ eq::Viewport vp = eq::Viewport::FULL;
+ vp.transform(segment->getViewport());
+ wall.apply(vp);
+
+ float yMin = EQ_MIN(wall.bottomLeft.y(), wall.bottomRight.y());
+ float yMax = EQ_MAX(wall.bottomLeft.y(), wall.bottomRight.y());
+ yMin = EQ_MIN(yMin, wall.topLeft.y());
+ yMax = EQ_MAX(yMax, wall.topLeft.y());
+
+ const float h = yMax - yMin;
+ const eq::Vector3f center = (wall.bottomRight + wall.topLeft) * 0.5f;
+ const float d = center.length();
+
+ // 'same' orientation and distance
+ if (std::fabs(angle - val) < 0.0001f && std::fabs(d - *distance) < 0.0001f)
+ {
+ if (h > *height)
+ {
+ *height = h;
+ }
+ }
+ else
+ {
+ *height = h;
+ *distance = d;
+ angle = val;
+ }
+ }
+ }
+ }
};
/*
@@ -710,18 +813,10 @@ protected:
eq_node *node = static_cast<eq_node *>(getNode());
// Disable some things that Equalizer seems to enable for some reason.
- glDisable(GL_SCISSOR_TEST);
glDisable(GL_LIGHTING);
- bool have_pixel_buffer_object = glewContextIsSupported(
- const_cast<GLEWContext *>(glewGetContext()), "GL_ARB_pixel_buffer_object");
- bool have_texture_non_power_of_two = glewContextIsSupported(
- const_cast<GLEWContext *>(glewGetContext()), "GL_ARB_texture_non_power_of_two");
- bool have_fragment_shader = glewContextIsSupported(
- const_cast<GLEWContext *>(glewGetContext()), "GL_ARB_fragment_shader");
-
_video_output.eq_initialize(node->src_width, node->src_height, node->src_aspect_ratio, node->src_preferred_frame_format,
- have_pixel_buffer_object, have_texture_non_power_of_two, have_fragment_shader);
+ GLEW_ARB_pixel_buffer_object, GLEW_ARB_texture_non_power_of_two, GLEW_ARB_fragment_shader);
msg::dbg(HERE);
return true;
@@ -780,26 +875,39 @@ protected:
eq::Channel::frameDraw(frameID);
// Get the canvas video area and the canvas channel area
eq_node *node = static_cast<eq_node *>(getNode());
- const struct { float x, y, w, h; } canvas_video_area =
+ const struct { float x, y, w, h, d; } canvas_video_area =
{
node->init_data.canvas_video_area.x,
node->init_data.canvas_video_area.y,
node->init_data.canvas_video_area.w,
- node->init_data.canvas_video_area.h
+ node->init_data.canvas_video_area.h,
+ node->init_data.canvas_video_area.d
};
const eq::Viewport &canvas_channel_area = getViewport();
// Determine the video quad to render
- float quad_x = ((canvas_video_area.x - canvas_channel_area.x) / canvas_channel_area.w - 0.5) * 2.0f;
- float quad_y = ((canvas_video_area.y - canvas_channel_area.y) / canvas_channel_area.h - 0.5) * 2.0f;
- float quad_w = 2.0f * canvas_video_area.w / canvas_channel_area.w;
- float quad_h = 2.0f * canvas_video_area.h / canvas_channel_area.h;
+ float quad_x = canvas_video_area.x;
+ float quad_y = canvas_video_area.y;
+ float quad_w = canvas_video_area.w;
+ float quad_h = canvas_video_area.h;
+ if (node->init_data.flat_screen)
+ {
+ quad_x = ((quad_x - canvas_channel_area.x) / canvas_channel_area.w - 0.5f) * 2.0f;
+ quad_y = ((quad_y - canvas_channel_area.y) / canvas_channel_area.h - 0.5f) * 2.0f;
+ quad_w = 2.0f * quad_w / canvas_channel_area.w;
+ quad_h = 2.0f * quad_h / canvas_channel_area.h;
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ }
+ else
+ {
+ glTranslatef(0.0f, 0.0f, -canvas_video_area.d);
+ }
+
// Display
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
eq_window *window = static_cast<eq_window *>(getWindow());
window->display(getEye() == eq::EYE_RIGHT ? video_output::mono_right : video_output::mono_left,
quad_x, quad_y, quad_w, quad_h);
@@ -843,8 +951,8 @@ public:
* player_equalizer
*/
-player_equalizer::player_equalizer(int *argc, char *argv[])
- : player(player::slave)
+player_equalizer::player_equalizer(int *argc, char *argv[], bool flat_screen)
+ : player(player::slave), _flat_screen(flat_screen)
{
/* Initialize Equalizer */
_node_factory = static_cast<void *>(new eq_node_factory);
@@ -870,7 +978,7 @@ player_equalizer::~player_equalizer()
void player_equalizer::open(const player_init_data &init_data)
{
eq_config *config = static_cast<eq_config *>(_config);
- if (!config->init(init_data))
+ if (!config->init(init_data, _flat_screen))
{
throw exc("equalizer configuration initialization failed");
}
diff --git a/src/player_equalizer.h b/src/player_equalizer.h
index 51b5498..3d8378a 100644
--- a/src/player_equalizer.h
+++ b/src/player_equalizer.h
@@ -1,3 +1,24 @@
+/*
+ * This file is part of bino, a program to play stereoscopic videos.
+ *
+ * Copyright (C) 2010
+ * Martin Lambers <marlam@marlam.de>
+ * Stefan Eilemann <eile@eyescale.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
#ifndef PLAYER_EQUALIZER_H
#define PLAYER_EQUALIZER_H
@@ -12,9 +33,10 @@ class player_equalizer : public player
private:
void *_node_factory;
void *_config;
+ bool _flat_screen;
public:
- player_equalizer(int *argc, char *argv[]);
+ player_equalizer(int *argc, char *argv[], bool flat_screen);
~player_equalizer();
virtual void open(const player_init_data &init_data);