Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
1041 lines (940 sloc) 31.1 KB
/*
* This file is part of bino, a 3D video player.
*
* 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"
#include "s11n.h"
#include "video_output_opengl.h"
#include "player_equalizer.h"
/*
* Every eq::Node has a special player: player_eq_node.
* These node players do not control the video playing themselves. Instead,
* they are told what to do via the frame data.
*
* eq::Config has the master player object. This master also plays the sound,
* to be able to synchronize the video to it.
*
* The application node reuses the player of eq::Config, so that it does not
* need to run two players.
*
* Each eq::Window has a special video_output_opengl: video_output_opengl_eq_window.
* It manages the video textures.
*
* Each eq::Channel than calls the window's display function to render its subset of
* the video.
*/
/*
* player_eq_node
*
* Implementation of player for eq_node.
* The player_eq_node instance of the application node lives in eq_config instead of eq_node.
*/
class player_eq_node : public player
{
private:
bool _is_master;
public:
player_eq_node() : player(player::slave), _is_master(false)
{
}
void eq_make_master()
{
make_master();
_is_master = true;
}
bool eq_init(const player_init_data &init_data,
int *src_width, int *src_height, float *src_aspect_ratio,
enum decoder::video_frame_format *src_frame_format, bool *src_is_mono)
{
try
{
set_benchmark(init_data.benchmark);
reset_playstate();
create_decoders(init_data.filenames);
create_input(init_data.input_mode);
*src_width = get_input()->video_width();
*src_height = get_input()->video_height();
*src_aspect_ratio = get_input()->video_aspect_ratio();
*src_frame_format = get_input()->video_frame_format();
*src_is_mono = get_input()->video_is_mono();
if (_is_master)
{
create_audio_output();
}
}
catch (std::exception &e)
{
msg::err("%s", e.what());
return false;
}
return true;
}
video_output_state &eq_video_state()
{
return video_state();
}
void eq_seek_to(int64_t seek_to)
{
get_input()->seek(seek_to);
}
void eq_read_frame() // Only called on slave nodes to force reading the next frame
{
if (get_input()->read_video_frame() < 0)
{
msg::err("reading input frame failed (EOF?)");
abort();
}
}
void eq_prep_frame(video_output *vo)
{
prepare_video_frame(vo);
}
void eq_run_step(bool *more_steps, int64_t *seek_to, bool *prep_frame, bool *drop_frame, bool *display_frame)
{
run_step(more_steps, seek_to, prep_frame, drop_frame, display_frame);
}
void eq_get_frame()
{
get_video_frame();
}
void eq_release_frame()
{
release_video_frame();
}
};
/*
* video_output_opengl_eq_window
*
* Implementation of video_output_opengl for eq_window
*/
class video_output_opengl_eq_window : public video_output_opengl
{
public:
video_output_opengl_eq_window() : video_output_opengl(false)
{
}
void eq_display(bool toggle_swap_eyes, float x, float y, float w, float h, const int viewport[4])
{
video_output_opengl::display(toggle_swap_eyes, x, y, w, h, viewport);
}
void eq_initialize(int src_width, int src_height, float src_aspect_ratio,
enum decoder::video_frame_format src_frame_format, bool src_is_mono)
{
set_mode(mono_left); // to display the right view, we can toggle the swap_eyes flag
set_source_info(src_width, src_height, src_aspect_ratio, src_frame_format, src_is_mono);
initialize();
}
void eq_deinitialize()
{
deinitialize();
}
void eq_swap_tex_set()
{
swap_tex_set();
}
void eq_set_state(const video_output_state &video_state)
{
set_state(video_state);
}
// The rest of the video_output_opengl interface is irrelevant for Equalizer
virtual int screen_pos_x() { return 0; }
virtual int screen_pos_y() { return 0; }
virtual void receive_notification(const notification &) {}
virtual bool supports_stereo() { return false; }
virtual void open(enum decoder::video_frame_format, bool, int, int, float, int,
const video_output_state&, unsigned int, int, int) {}
virtual void activate() {}
virtual void process_events() {}
virtual void close() {}
};
/*
* eq_init_data
*/
class eq_init_data : public eq::net::Object
{
public:
uint32_t frame_data_id;
player_init_data init_data;
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;
}
virtual ~eq_init_data()
{
frame_data_id = EQ_ID_INVALID;
}
protected:
virtual ChangeType getChangeType() const
{
return eq::net::Object::STATIC;
}
virtual void getInstanceData(eq::net::DataOStream &os)
{
std::ostringstream oss;
s11n::save(oss, frame_data_id);
s11n::save(oss, static_cast<int>(init_data.log_level));
s11n::save(oss, init_data.filenames);
s11n::save(oss, static_cast<int>(init_data.input_mode));
s11n::save(oss, static_cast<int>(init_data.video_mode));
s11n::save(oss, init_data.video_state.contrast);
s11n::save(oss, init_data.video_state.brightness);
s11n::save(oss, init_data.video_state.hue);
s11n::save(oss, init_data.video_state.saturation);
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();
}
virtual void applyInstanceData(eq::net::DataIStream &is)
{
int x;
std::string s;
is >> s;
std::istringstream iss(s);
s11n::load(iss, frame_data_id);
s11n::load(iss, x);
init_data.log_level = static_cast<msg::level_t>(x);
s11n::load(iss, init_data.filenames);
s11n::load(iss, x);
init_data.input_mode = static_cast<enum input::mode>(x);
s11n::load(iss, x);
init_data.video_mode = static_cast<enum video_output::mode>(x);
s11n::load(iss, init_data.video_state.contrast);
s11n::load(iss, init_data.video_state.brightness);
s11n::load(iss, init_data.video_state.hue);
s11n::load(iss, init_data.video_state.saturation);
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);
}
};
/*
* eq_frame_data
*/
class eq_frame_data : public eq::net::Object
{
public:
video_output_state video_state;
int64_t seek_to;
bool prep_frame;
bool drop_frame;
bool display_frame;
public:
eq_frame_data()
: video_state(), seek_to(-1),
prep_frame(false), drop_frame(false), display_frame(false)
{
}
protected:
virtual ChangeType getChangeType() const
{
return eq::net::Object::INSTANCE;
}
virtual void getInstanceData(eq::net::DataOStream &os)
{
std::ostringstream oss;
s11n::save(oss, video_state.contrast);
s11n::save(oss, video_state.brightness);
s11n::save(oss, video_state.hue);
s11n::save(oss, video_state.saturation);
s11n::save(oss, video_state.fullscreen);
s11n::save(oss, video_state.swap_eyes);
s11n::save(oss, seek_to);
s11n::save(oss, prep_frame);
s11n::save(oss, drop_frame);
s11n::save(oss, display_frame);
os << oss.str();
}
virtual void applyInstanceData(eq::net::DataIStream &is)
{
std::string s;
is >> s;
std::istringstream iss(s);
s11n::load(iss, video_state.contrast);
s11n::load(iss, video_state.brightness);
s11n::load(iss, video_state.hue);
s11n::load(iss, video_state.saturation);
s11n::load(iss, video_state.fullscreen);
s11n::load(iss, video_state.swap_eyes);
s11n::load(iss, seek_to);
s11n::load(iss, prep_frame);
s11n::load(iss, drop_frame);
s11n::load(iss, display_frame);
}
};
/*
* eq_config
*/
class eq_config : public eq::Config
{
private:
bool _is_master_config;
eq_init_data _eq_init_data; // Master eq_init_data instance
eq_frame_data _eq_frame_data; // Master eq_frame_data instance
player_eq_node _player; // Master player
controller _controller; // Sends commands to the player
public:
// Source video properties:
int src_width, src_height;
float src_aspect_ratio;
enum decoder::video_frame_format src_frame_format;
bool src_is_mono;
public:
eq_config(eq::ServerPtr parent)
: eq::Config(parent), _is_master_config(false), _eq_init_data(), _eq_frame_data(),
_player(), _controller(false),
src_width(-1), src_height(-1), src_aspect_ratio(0.0f),
src_frame_format(decoder::frame_format_yuv420p), src_is_mono(true)
{
}
bool is_master_config()
{
return _is_master_config;
}
bool init(const player_init_data &init_data, bool flat_screen)
{
msg::set_level(init_data.log_level);
msg::dbg(HERE);
// If this function is called, then this is the master config
_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();
if (!_player.eq_init(init_data, &src_width, &src_height, &src_aspect_ratio,
&src_frame_format, &src_is_mono))
{
return false;
}
// Find region of canvas to use, depending on the video aspect ratio
if (getCanvases().size() < 1)
{
msg::err("no canvas in Equalizer configuration");
return false;
}
float canvas_w = getCanvases()[0]->getWall().getWidth();
float canvas_h = getCanvases()[0]->getWall().getHeight();
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 (flat_screen)
{
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
{
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;
}
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 @ %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.d);
// Register master instances
registerObject(&_eq_frame_data);
_eq_init_data.frame_data_id = _eq_frame_data.getID();
registerObject(&_eq_init_data);
msg::dbg(HERE);
return eq::Config::init(_eq_init_data.getID());
}
virtual bool exit()
{
msg::dbg(HERE);
bool ret = eq::Config::exit();
// Deregister master instances
deregisterObject(&_eq_init_data);
deregisterObject(&_eq_frame_data);
_eq_init_data.frame_data_id = EQ_ID_INVALID;
// Cleanup
_player.close();
msg::dbg(HERE);
return ret;
}
virtual uint32_t startFrame()
{
// Run one player step to find out what to do
bool more_steps;
_player.eq_run_step(&more_steps, &_eq_frame_data.seek_to,
&_eq_frame_data.prep_frame, &_eq_frame_data.drop_frame, &_eq_frame_data.display_frame);
if (!more_steps)
{
this->exit();
}
// Update the video state for all (it might have changed via handleEvent())
_eq_frame_data.video_state = _player.eq_video_state();
// Commit the updated frame data
const uint32_t version = _eq_frame_data.commit();
// Start this frame with the committed frame data
return eq::Config::startFrame(version);
}
virtual bool handleEvent(const eq::ConfigEvent *event)
{
if (eq::Config::handleEvent(event))
{
return true;
}
if (event->data.type == eq::Event::KEY_PRESS)
{
switch (event->data.keyPress.key)
{
case 'q':
_controller.send_cmd(command::toggle_play);
break;
case 's':
_controller.send_cmd(command::toggle_swap_eyes);
break;
case 'f':
/* fullscreen toggling not supported with Equalizer */
break;
case 'c':
/* window centering not supported with Equalizer */
break;
case ' ':
case 'p':
_controller.send_cmd(command::toggle_pause);
break;
case '1':
_controller.send_cmd(command::adjust_contrast, -0.05f);
break;
case '2':
_controller.send_cmd(command::adjust_contrast, +0.05f);
break;
case '3':
_controller.send_cmd(command::adjust_brightness, -0.05f);
break;
case '4':
_controller.send_cmd(command::adjust_brightness, +0.05f);
break;
case '5':
_controller.send_cmd(command::adjust_hue, -0.05f);
break;
case '6':
_controller.send_cmd(command::adjust_hue, +0.05f);
break;
case '7':
_controller.send_cmd(command::adjust_saturation, -0.05f);
break;
case '8':
_controller.send_cmd(command::adjust_saturation, +0.05f);
break;
case eq::KC_LEFT:
_controller.send_cmd(command::seek, -10.0f);
break;
case eq::KC_RIGHT:
_controller.send_cmd(command::seek, +10.0f);
break;
case eq::KC_UP:
_controller.send_cmd(command::seek, -60.0f);
break;
case eq::KC_DOWN:
_controller.send_cmd(command::seek, +60.0f);
break;
case eq::KC_PAGE_UP:
_controller.send_cmd(command::seek, -600.0f);
break;
case eq::KC_PAGE_DOWN:
_controller.send_cmd(command::seek, +600.0f);
break;
}
}
return true;
}
player_eq_node *player()
{
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();
#if 0 // Hack to compute rotated walls for Equalizer configuration. See doc/multi-display.txt.
eq::Matrix4f matrix(eq::Matrix4f::IDENTITY);
matrix.rotate(1.3f, eq::Vector3f::FORWARD);
wall.bottomLeft = matrix * wall.bottomLeft;
wall.bottomRight = matrix * wall.bottomRight;
wall.topLeft = matrix * wall.topLeft;
std::cout << wall << std::endl;
#endif
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);
const eq::Vector3f topRight = wall.topLeft + wall.bottomRight - wall.bottomLeft;
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());
yMin = EQ_MIN(yMin, topRight.y());
yMax = EQ_MAX(yMax, topRight.y());
const float h = yMax - yMin;
const eq::Vector3f center = (wall.bottomRight + wall.topLeft) * 0.5f;
const float d = -center.z();
// '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;
}
}
}
}
};
/*
* eq_node
*/
class eq_node : public eq::Node
{
private:
bool _is_app_node;
player_eq_node _player;
public:
eq_init_data init_data;
eq_frame_data frame_data;
int src_width, src_height;
float src_aspect_ratio;
enum decoder::video_frame_format src_frame_format;
bool src_is_mono;
eq_node(eq::Config *parent)
: eq::Node(parent), _is_app_node(false),
_player(), init_data(), frame_data(),
src_width(-1), src_height(-1), src_aspect_ratio(-1.0f),
src_frame_format(decoder::frame_format_yuv420p), src_is_mono(true)
{
}
protected:
virtual bool configInit(const uint32_t initID)
{
if (!eq::Node::configInit(initID))
{
return false;
}
// Map our InitData instance to the master instance
eq_config *config = static_cast<eq_config *>(getConfig());
if (!config->mapObject(&init_data, initID))
{
return false;
}
// Is this the application node?
if (config->is_master_config())
{
_is_app_node = true;
}
// Map our FrameData instance to the master instance
if (!config->mapObject(&frame_data, init_data.frame_data_id))
{
return false;
}
msg::set_level(init_data.init_data.log_level);
msg::dbg(HERE);
// Create decoders and input
if (!_is_app_node)
{
if (!_player.eq_init(init_data.init_data, &src_width, &src_height, &src_aspect_ratio,
&src_frame_format, &src_is_mono))
{
return false;
}
}
else
{
src_width = config->src_width;
src_height = config->src_height;
src_aspect_ratio = config->src_aspect_ratio;
src_frame_format = config->src_frame_format;
src_is_mono = config->src_is_mono;
}
msg::dbg(HERE);
return true;
}
virtual bool configExit()
{
msg::dbg(HERE);
eq::Config *config = getConfig();
// Unmap our FrameData instance
config->unmapObject(&frame_data);
// Unmap our InitData instance
config->unmapObject(&init_data);
// Cleanup
_player.close();
msg::dbg(HERE);
return eq::Node::configExit();
}
virtual void frameStart(const uint32_t frameID, const uint32_t frameNumber)
{
// Update our frame data
frame_data.sync(frameID);
// Do as we're told
if (_is_app_node)
{
eq_config *config = static_cast<eq_config *>(getConfig());
if (frame_data.prep_frame)
{
config->player()->eq_get_frame();
}
if (frame_data.drop_frame)
{
config->player()->eq_release_frame();
}
}
else
{
if (frame_data.seek_to >= 0)
{
_player.eq_seek_to(frame_data.seek_to);
}
if (frame_data.prep_frame)
{
_player.eq_read_frame();
_player.eq_get_frame();
}
if (frame_data.drop_frame)
{
_player.eq_read_frame();
_player.eq_release_frame();
}
}
startFrame(frameNumber);
}
virtual void frameFinish(const uint32_t, const uint32_t frameNumber)
{
// Do as we're told
if (_is_app_node)
{
eq_config *config = static_cast<eq_config *>(getConfig());
if (frame_data.prep_frame)
{
config->player()->eq_release_frame();
}
}
else
{
if (frame_data.prep_frame)
{
_player.eq_release_frame();
}
}
releaseFrame(frameNumber);
}
public:
void prep_frame(video_output *vo)
{
if (_is_app_node)
{
eq_config *config = static_cast<eq_config *>(getConfig());
config->player()->eq_prep_frame(vo);
}
else
{
_player.eq_prep_frame(vo);
}
}
};
/*
* eq_pipe
*/
class eq_pipe : public eq::Pipe
{
public:
eq_pipe(eq::Node *parent) : eq::Pipe(parent)
{
}
};
/*
* eq_window
*/
class eq_window : public eq::Window
{
private:
video_output_opengl_eq_window _video_output;
public:
eq_window(eq::Pipe *parent) : eq::Window(parent), _video_output()
{
}
void display(bool toggle_swap_eyes, float x, float y, float w, float h, const int viewport[4])
{
_video_output.eq_display(toggle_swap_eyes, x, y, w, h, viewport);
}
protected:
virtual bool configInitGL(const uint32_t initID)
{
msg::dbg(HERE);
if (!eq::Window::configInitGL(initID))
{
return false;
}
if (!glewContextIsSupported(const_cast<GLEWContext *>(glewGetContext()),
"GL_VERSION_2_1"))
{
msg::err("This OpenGL implementation does not support OpenGL 2.1");
return false;
}
if (!glewContextIsSupported(const_cast<GLEWContext *>(glewGetContext()),
"GL_EXT_framebuffer_object"))
{
msg::err("This OpenGL implementation does not support framebuffer objects");
return false;
}
// Disable some things that Equalizer seems to enable for some reason.
glDisable(GL_LIGHTING);
eq_node *node = static_cast<eq_node *>(getNode());
_video_output.eq_initialize(node->src_width, node->src_height,
node->src_aspect_ratio, node->src_frame_format, node->src_is_mono);
msg::dbg(HERE);
return true;
}
virtual bool configExitGL()
{
msg::dbg(HERE);
_video_output.eq_deinitialize();
msg::dbg(HERE);
return eq::Window::configExitGL();
}
virtual void frameStart(const uint32_t, const uint32_t frameNumber)
{
// Get frame data via from the node
eq_node *node = static_cast<eq_node *>(getNode());
_video_output.eq_set_state(node->frame_data.video_state);
// Do as we're told
if (node->frame_data.prep_frame)
{
makeCurrent(); // XXX Is this necessary?
node->prep_frame(&_video_output);
}
if (node->frame_data.display_frame)
{
makeCurrent(); // XXX Is this necessary?
_video_output.eq_swap_tex_set();
}
startFrame(frameNumber);
}
virtual void frameFinish(const uint32_t, const uint32_t frameNumber)
{
releaseFrame(frameNumber);
}
};
/*
* eq_channel
*/
class eq_channel : public eq::Channel
{
private:
public:
eq_channel(eq::Window *parent) : eq::Channel(parent)
{
}
protected:
virtual void frameDraw(const uint32_t frameID)
{
// Let Equalizer initialize some stuff
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, 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.d
};
const eq::Viewport &canvas_channel_area = getViewport();
// Determine the video quad to render
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
eq_window *window = static_cast<eq_window *>(getWindow());
bool toggle_swap_eyes = (getEye() == eq::EYE_RIGHT);
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
window->display(toggle_swap_eyes, quad_x, quad_y, quad_w, quad_h, viewport);
}
};
/*
* eq_node_factory
*/
class eq_node_factory : public eq::NodeFactory
{
public:
virtual eq::Config *createConfig(eq::ServerPtr parent)
{
return new eq_config(parent);
}
virtual eq::Node *createNode(eq::Config *parent)
{
return new eq_node(parent);
}
virtual eq::Pipe *createPipe(eq::Node *parent)
{
return new eq_pipe(parent);
}
virtual eq::Window *createWindow(eq::Pipe *parent)
{
return new eq_window(parent);
}
virtual eq::Channel *createChannel(eq::Window *parent)
{
return new eq_channel(parent);
}
};
/*
* player_equalizer
*/
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);
if (!eq::init(*argc, argv, static_cast<eq::NodeFactory *>(_node_factory)))
{
throw exc("equalizer initialization failed");
}
/* Get a configuration */
_config = static_cast<void *>(eq::getConfig(*argc, argv));
// The following code is only executed on the application node because
// eq::getConfig() does not return on other nodes.
if (!_config)
{
throw exc("cannot get equalizer configuration");
}
}
player_equalizer::~player_equalizer()
{
delete static_cast<eq_node_factory *>(_node_factory);
}
void player_equalizer::open(const player_init_data &init_data)
{
eq_config *config = static_cast<eq_config *>(_config);
if (!config->init(init_data, _flat_screen))
{
throw exc("equalizer configuration initialization failed");
}
}
void player_equalizer::run()
{
eq_config *config = static_cast<eq_config *>(_config);
while (config->isRunning())
{
config->startFrame();
config->finishFrame();
}
config->exit();
eq::releaseConfig(config);
eq::exit();
}
void player_equalizer::close()
{
}
std::vector<std::string> equalizer_versions()
{
std::vector<std::string> v;
v.push_back(str::asprintf("Equalizer %d.%d.%d / %d.%d.%d",
EQ_VERSION_MAJOR, EQ_VERSION_MINOR, EQ_VERSION_PATCH,
static_cast<int>(eq::Version::getMajor()),
static_cast<int>(eq::Version::getMinor()),
static_cast<int>(eq::Version::getPatch())));
return v;
}