summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Lambers <marlam@marlam.de>2011-03-21 21:00:37 +0100
committerMartin Lambers <marlam@marlam.de>2011-03-21 21:00:37 +0100
commit6b893a1e78592e502ccaff0cbf4c6bb4d4c3d32f (patch)
tree63907e2ea4437eeaa3c8604c960b333890f1bfbb
parent6958295b09f35c6d2151984ed19c17e75cb21cb4 (diff)
downloadbino-6b893a1e78592e502ccaff0cbf4c6bb4d4c3d32f.tar.gz
Fix viewports for separate-view output modes.
The output modes left_right, left_right_half, top_bottom, top_bottom_half, and hdmi_frame_pack now use viewports that split aspect ratio borders equally between the two views.
-rw-r--r--src/player_equalizer.cpp6
-rw-r--r--src/video_output.cpp164
-rw-r--r--src/video_output.h6
3 files changed, 106 insertions, 70 deletions
diff --git a/src/player_equalizer.cpp b/src/player_equalizer.cpp
index 4972ddb..f209b2b 100644
--- a/src/player_equalizer.cpp
+++ b/src/player_equalizer.cpp
@@ -23,6 +23,7 @@
#include <sstream>
#include <cmath>
+#include <cstdlib>
#include <eq/eq.h>
@@ -189,7 +190,10 @@ public:
void display_current_frame(bool mono_right_instead_of_left,
float x, float y, float w, float h, const GLint viewport[4])
{
- video_output::display_current_frame(mono_right_instead_of_left, x, y, w, h, viewport);
+ GLint vp[2][4];
+ std::memcpy(vp[0], viewport, 4 * sizeof(int));
+ std::memcpy(vp[1], viewport, 4 * sizeof(int));
+ video_output::display_current_frame(mono_right_instead_of_left, x, y, w, h, vp);
}
};
diff --git a/src/video_output.cpp b/src/video_output.cpp
index 66b7f48..a5ba05e 100644
--- a/src/video_output.cpp
+++ b/src/video_output.cpp
@@ -599,7 +599,7 @@ static void draw_quad(float x, float y, float w, float h)
}
void video_output::display_current_frame(bool mono_right_instead_of_left,
- float x, float y, float w, float h, const GLint viewport[4])
+ float x, float y, float w, float h, const GLint viewport[2][4])
{
make_context_current();
assert(xgl::CheckError(HERE));
@@ -641,13 +641,13 @@ void video_output::display_current_frame(bool mono_right_instead_of_left,
}
if ((_params.stereo_mode == parameters::even_odd_rows
|| _params.stereo_mode == parameters::checkerboard)
- && (pos_y() + viewport[1]) % 2 == 0)
+ && (pos_y() + viewport[0][1]) % 2 == 0)
{
std::swap(left, right);
}
if ((_params.stereo_mode == parameters::even_odd_columns
|| _params.stereo_mode == parameters::checkerboard)
- && (pos_x() + viewport[0]) % 2 == 1)
+ && (pos_x() + viewport[0][0]) % 2 == 1)
{
std::swap(left, right);
}
@@ -725,7 +725,7 @@ void video_output::display_current_frame(bool mono_right_instead_of_left,
draw_quad(-1.0f, +1.0f, +2.0f, -2.0f);
}
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
- glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
+ glViewport(viewport[0][0], viewport[0][1], viewport[0][2], viewport[0][3]);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
@@ -777,8 +777,8 @@ void video_output::display_current_frame(bool mono_right_instead_of_left,
|| _params.stereo_mode == parameters::checkerboard)
{
glUniform1i(glGetUniformLocation(_render_prg, "mask_tex"), 2);
- glUniform1f(glGetUniformLocation(_render_prg, "step_x"), 1.0f / static_cast<float>(viewport[2]));
- glUniform1f(glGetUniformLocation(_render_prg, "step_y"), 1.0f / static_cast<float>(viewport[3]));
+ glUniform1f(glGetUniformLocation(_render_prg, "step_x"), 1.0f / static_cast<float>(viewport[0][2]));
+ glUniform1f(glGetUniformLocation(_render_prg, "step_y"), 1.0f / static_cast<float>(viewport[0][3]));
}
if (_params.stereo_mode == parameters::stereo)
@@ -794,8 +794,8 @@ void video_output::display_current_frame(bool mono_right_instead_of_left,
|| _params.stereo_mode == parameters::even_odd_columns
|| _params.stereo_mode == parameters::checkerboard)
{
- float vpw = static_cast<float>(viewport[2]);
- float vph = static_cast<float>(viewport[3]);
+ float vpw = static_cast<float>(viewport[0][2]);
+ float vph = static_cast<float>(viewport[0][3]);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, _render_mask_tex);
glBegin(GL_QUADS);
@@ -843,34 +843,16 @@ void video_output::display_current_frame(bool mono_right_instead_of_left,
draw_quad(x, y, w, h);
}
else if (_params.stereo_mode == parameters::left_right
- || _params.stereo_mode == parameters::left_right_half)
- {
- glUniform1f(glGetUniformLocation(_render_prg, "channel"), 0.0f);
- draw_quad(-1.0f, -1.0f, 1.0f, 2.0f);
- glUniform1f(glGetUniformLocation(_render_prg, "channel"), 1.0f);
- draw_quad(0.0f, -1.0f, 1.0f, 2.0f);
- }
- else if (_params.stereo_mode == parameters::top_bottom
- || _params.stereo_mode == parameters::top_bottom_half)
- {
- glUniform1f(glGetUniformLocation(_render_prg, "channel"), 0.0f);
- draw_quad(-1.0f, 0.0f, 2.0f, 1.0f);
- glUniform1f(glGetUniformLocation(_render_prg, "channel"), 1.0f);
- draw_quad(-1.0f, -1.0f, 2.0f, 1.0f);
- }
- else if (_params.stereo_mode == parameters::hdmi_frame_pack)
+ || _params.stereo_mode == parameters::left_right_half
+ || _params.stereo_mode == parameters::top_bottom
+ || _params.stereo_mode == parameters::top_bottom_half
+ || _params.stereo_mode == parameters::hdmi_frame_pack)
{
- // HDMI frame packing mode has left view top, right view bottom, plus a
- // blank area separating the two. 720p uses 30 blank lines (total: 720
- // + 30 + 720 = 1470), 1080p uses 45 (total: 10280 + 45 + 1080 = 2205).
- // In both cases, the blank area is 30/1470 = 45/2205 = 1/49 of the
- // total height. See the document "High-Definition Multimedia Interface
- // Specification Version 1.4a Extraction of 3D Signaling Portion" from
- // hdmi.org.
glUniform1f(glGetUniformLocation(_render_prg, "channel"), 0.0f);
- draw_quad(-1.0f, 0.0f + 1.0f / 49.0f, 2.0f, 1.0f - 1.0f / 49.0f);
+ draw_quad(x, y, w, h);
+ glViewport(viewport[1][0], viewport[1][1], viewport[1][2], viewport[1][3]);
glUniform1f(glGetUniformLocation(_render_prg, "channel"), 1.0f);
- draw_quad(-1.0f, -1.0f, 2.0f, 1.0f - 1.0f / 49.0f);
+ draw_quad(x, y, w, h);
}
assert(xgl::CheckError(HERE));
}
@@ -893,14 +875,36 @@ void video_output::clear()
assert(xgl::CheckError(HERE));
}
+static void compute_viewport(int vp[4], int w, int h, float dst_w, float dst_h, float dst_ar, float src_ar)
+{
+ vp[2] = dst_w;
+ vp[3] = dst_h;
+ if (src_ar >= dst_ar)
+ {
+ // need black borders top and bottom
+ vp[3] = dst_ar / src_ar * dst_h;
+ }
+ else
+ {
+ // need black borders left and right
+ vp[2] = src_ar / dst_ar * dst_w;
+ }
+ vp[0] = (w - vp[2]) / 2;
+ vp[1] = (h - vp[3]) / 2;
+}
+
void video_output::reshape(int w, int h)
{
make_context_current();
// Clear
- _viewport[0] = 0;
- _viewport[1] = 0;
- _viewport[2] = w;
- _viewport[3] = h;
+ _viewport[0][0] = 0;
+ _viewport[0][1] = 0;
+ _viewport[0][2] = w;
+ _viewport[0][3] = h;
+ _viewport[1][0] = 0;
+ _viewport[1][1] = 0;
+ _viewport[1][2] = w;
+ _viewport[1][3] = h;
glViewport(0, 0, w, h);
clear();
if (!_frame[_active_index].is_valid())
@@ -909,45 +913,73 @@ void video_output::reshape(int w, int h)
}
// Compute viewport with the right aspect ratio
- float dst_w = w;
- float dst_h = h;
- if (_params.stereo_mode == parameters::hdmi_frame_pack)
- {
- // Account for the blank space between left and right view. See
- // comments for this mode in the display_current_frame() function.
- dst_h -= dst_h / 49.0f;
- }
- float dst_ar = dst_w * screen_pixel_aspect_ratio() / dst_h;
- float src_ar = _frame[_active_index].aspect_ratio;
- if (_params.stereo_mode == parameters::left_right)
+ if (_params.stereo_mode == parameters::left_right
+ || _params.stereo_mode == parameters::left_right_half)
{
- src_ar *= 2.0f;
+ float dst_w = w / 2;
+ float dst_h = h;
+ float dst_ar = dst_w * screen_pixel_aspect_ratio() / dst_h;
+ float src_ar = _frame[_active_index].aspect_ratio;
+ if (_params.stereo_mode == parameters::left_right_half)
+ {
+ src_ar /= 2.0f;
+ }
+ compute_viewport(_viewport[0], w / 2, h, dst_w, dst_h, dst_ar, src_ar);
+ _viewport[1][0] = _viewport[0][0] + w / 2;
+ _viewport[1][1] = _viewport[0][1];
+ _viewport[1][2] = _viewport[0][2];
+ _viewport[1][3] = _viewport[0][3];
}
else if (_params.stereo_mode == parameters::top_bottom
- || _params.stereo_mode == parameters::hdmi_frame_pack)
+ || _params.stereo_mode == parameters::top_bottom_half)
{
- src_ar /= 2.0f;
+ float dst_w = w;
+ float dst_h = h / 2;
+ float dst_ar = dst_w * screen_pixel_aspect_ratio() / dst_h;
+ float src_ar = _frame[_active_index].aspect_ratio;
+ if (_params.stereo_mode == parameters::top_bottom_half)
+ {
+ src_ar *= 2.0f;
+ }
+ compute_viewport(_viewport[0], w, h / 2, dst_w, dst_h, dst_ar, src_ar);
+ _viewport[1][0] = _viewport[0][0];
+ _viewport[1][1] = _viewport[0][1] + h / 2;
+ _viewport[1][2] = _viewport[0][2];
+ _viewport[1][3] = _viewport[0][3];
}
- int vp_w = w;
- int vp_h = h;
- if (src_ar >= dst_ar)
+ else if (_params.stereo_mode == parameters::hdmi_frame_pack)
{
- // need black borders top and bottom
- vp_h = dst_ar / src_ar * dst_h;
+ // HDMI frame packing mode has left view top, right view bottom, plus a
+ // blank area separating the two. 720p uses 30 blank lines (total: 720
+ // + 30 + 720 = 1470), 1080p uses 45 (total: 10280 + 45 + 1080 = 2205).
+ // In both cases, the blank area is 30/1470 = 45/2205 = 1/49 of the
+ // total height. See the document "High-Definition Multimedia Interface
+ // Specification Version 1.4a Extraction of 3D Signaling Portion" from
+ // hdmi.org.
+ int blank_lines = h / 49;
+ float dst_w = w;
+ float dst_h = (h - blank_lines) / 2;
+ float dst_ar = dst_w * screen_pixel_aspect_ratio() / dst_h;
+ float src_ar = _frame[_active_index].aspect_ratio;
+ src_ar *= 2.0f;
+ compute_viewport(_viewport[0], w, (h - blank_lines) / 2, dst_w, dst_h, dst_ar, src_ar);
+ _viewport[1][0] = _viewport[0][0];
+ _viewport[1][1] = _viewport[0][1] + (h - blank_lines) / 2 + blank_lines;
+ _viewport[1][2] = _viewport[0][2];
+ _viewport[1][3] = _viewport[0][3];
}
else
{
- // need black borders left and right
- vp_w = src_ar / dst_ar * dst_w;
+ float dst_w = w;
+ float dst_h = h;
+ float dst_ar = dst_w * screen_pixel_aspect_ratio() / dst_h;
+ float src_ar = _frame[_active_index].aspect_ratio;
+ compute_viewport(_viewport[0], w, h, dst_w, dst_h, dst_ar, src_ar);
+ _viewport[1][0] = _viewport[0][0];
+ _viewport[1][1] = _viewport[0][1];
+ _viewport[1][2] = _viewport[0][2];
+ _viewport[1][3] = _viewport[0][3];
}
- int vp_x = (w - vp_w) / 2;
- int vp_y = (h - vp_h) / 2;
-
- // Save new size
- _viewport[0] = vp_x;
- _viewport[1] = vp_y;
- _viewport[2] = vp_w;
- _viewport[3] = vp_h;
}
bool video_output::need_redisplay_on_move()
diff --git a/src/video_output.h b/src/video_output.h
index 6c64234..409a189 100644
--- a/src/video_output.h
+++ b/src/video_output.h
@@ -62,8 +62,8 @@ private:
parameters _render_last_params; // last params for this step; used for reinitialization check
GLuint _render_prg; // reads sRGB texture, renders according to _params[_active_index]
GLuint _render_mask_tex; // for the masking modes even-odd-{rows,columns}, checkerboard
- // OpenGL Viewport for drawing the video frame
- GLint _viewport[4];
+ // OpenGL viewports for drawing the two views of the video frame
+ GLint _viewport[2][4];
private:
// Step 1: initialize/deinitialize, and check if reinitialization is necessary
@@ -96,7 +96,7 @@ protected:
* Third version: This version is used to redisplay the current frame, e.g. for repaint events.
* TODO: This function needs to handle interlaced frames! */
void display_current_frame(bool mono_right_instead_of_left,
- float x, float y, float w, float h, const GLint viewport[4]);
+ float x, float y, float w, float h, const GLint viewport[2][4]);
void display_current_frame()
{
display_current_frame(false, -1.0f, -1.0f, 2.0f, 2.0f, _viewport);