diff options
| author | Stefan Eilemann <eilemann@gmail.com> | 2010-12-01 21:32:22 +0100 |
|---|---|---|
| committer | Martin Lambers <marlam@marlam.de> | 2010-12-01 21:32:22 +0100 |
| commit | 8832aa87a0fb8b2e0428fade3e116ee42f90d985 (patch) | |
| tree | 6d12540749b05406643b969a131d7383d2b61b21 | |
| parent | 4e87aef9d7840d2b387e7efd932908a33057bd84 (diff) | |
| download | bino-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.1 | 4 | ||||
| -rw-r--r-- | doc/multi-display.txt | 8 | ||||
| -rw-r--r-- | src/main.cpp | 19 | ||||
| -rw-r--r-- | src/player_equalizer.cpp | 174 | ||||
| -rw-r--r-- | src/player_equalizer.h | 24 |
5 files changed, 190 insertions, 39 deletions
@@ -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); |
